diff --git a/Expert/Expert.mqh b/Expert/Expert.mqh new file mode 100644 index 0000000..4879389 Binary files /dev/null and b/Expert/Expert.mqh differ diff --git a/Expert/ExpertBase.mqh b/Expert/ExpertBase.mqh new file mode 100644 index 0000000..70260fc --- /dev/null +++ b/Expert/ExpertBase.mqh @@ -0,0 +1,715 @@ +//+------------------------------------------------------------------+ +//| ExpertBase.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/ExpertMoney.mqh b/Expert/ExpertMoney.mqh new file mode 100644 index 0000000..a552430 --- /dev/null +++ b/Expert/ExpertMoney.mqh @@ -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(lotm_account.Balance()*m_percent/100.0) + return(position.Volume()); +//--- + return(0.0); + } +//+------------------------------------------------------------------+ diff --git a/Expert/ExpertSignal.mqh b/Expert/ExpertSignal.mqh new file mode 100644 index 0000000..38f11e1 --- /dev/null +++ b/Expert/ExpertSignal.mqh @@ -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)<=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 +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| 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(pricebid+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 +// 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_lotsm_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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Money/MoneyFixedMargin.mqh b/Expert/Money/MoneyFixedMargin.mqh new file mode 100644 index 0000000..1fa3e80 --- /dev/null +++ b/Expert/Money/MoneyFixedMargin.mqh @@ -0,0 +1,76 @@ +//+------------------------------------------------------------------+ +//| MoneyFixedMargin.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Money/MoneyFixedRisk.mqh b/Expert/Money/MoneyFixedRisk.mqh new file mode 100644 index 0000000..8e99f03 --- /dev/null +++ b/Expert/Money/MoneyFixedRisk.mqh @@ -0,0 +1,109 @@ +//+------------------------------------------------------------------+ +//| MoneyFixedRisk.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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(lotmaxvol) + 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(lotmaxvol) + lot=maxvol; +//--- return trading volume + return(lot); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Money/MoneyNone.mqh b/Expert/Money/MoneyNone.mqh new file mode 100644 index 0000000..ae726cd --- /dev/null +++ b/Expert/Money/MoneyNone.mqh @@ -0,0 +1,71 @@ +//+------------------------------------------------------------------+ +//| MoneyNone.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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()); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Money/MoneySizeOptimized.mqh b/Expert/Money/MoneySizeOptimized.mqh new file mode 100644 index 0000000..e6ae11c --- /dev/null +++ b/Expert/Money/MoneySizeOptimized.mqh @@ -0,0 +1,155 @@ +//+------------------------------------------------------------------+ +//| MoneySizeOptimized.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +// 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(lotmaxvol) + lot=maxvol; +//--- + return(lot); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalAC.mqh b/Expert/Signal/SignalAC.mqh new file mode 100644 index 0000000..d2a1fad --- /dev/null +++ b/Expert/Signal/SignalAC.mqh @@ -0,0 +1,173 @@ +//+------------------------------------------------------------------+ +//| SignalAC.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalAMA.mqh b/Expert/Signal/SignalAMA.mqh new file mode 100644 index 0000000..8fd08a2 --- /dev/null +++ b/Expert/Signal/SignalAMA.mqh @@ -0,0 +1,265 @@ +//+------------------------------------------------------------------+ +//| SignalAMA.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalAO.mqh b/Expert/Signal/SignalAO.mqh new file mode 100644 index 0000000..6fc48d7 --- /dev/null +++ b/Expert/Signal/SignalAO.mqh @@ -0,0 +1,339 @@ +//+------------------------------------------------------------------+ +//| SignalAO.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalBearsPower.mqh b/Expert/Signal/SignalBearsPower.mqh new file mode 100644 index 0000000..832e897 --- /dev/null +++ b/Expert/Signal/SignalBearsPower.mqh @@ -0,0 +1,289 @@ +//+------------------------------------------------------------------+ +//| SignalBearsPower.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalBullsPower.mqh b/Expert/Signal/SignalBullsPower.mqh new file mode 100644 index 0000000..71cae79 --- /dev/null +++ b/Expert/Signal/SignalBullsPower.mqh @@ -0,0 +1,289 @@ +//+------------------------------------------------------------------+ +//| SignalBullsPower.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalCCI.mqh b/Expert/Signal/SignalCCI.mqh new file mode 100644 index 0000000..b3b77fa --- /dev/null +++ b/Expert/Signal/SignalCCI.mqh @@ -0,0 +1,382 @@ +//+------------------------------------------------------------------+ +//| SignalCCI.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalDEMA.mqh b/Expert/Signal/SignalDEMA.mqh new file mode 100644 index 0000000..57f2d8b --- /dev/null +++ b/Expert/Signal/SignalDEMA.mqh @@ -0,0 +1,257 @@ +//+------------------------------------------------------------------+ +//| SignalDEMA.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalDeMarker.mqh b/Expert/Signal/SignalDeMarker.mqh new file mode 100644 index 0000000..9f2a5b3 --- /dev/null +++ b/Expert/Signal/SignalDeMarker.mqh @@ -0,0 +1,378 @@ +//+------------------------------------------------------------------+ +//| SignalDeMarker.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalEnvelopes.mqh b/Expert/Signal/SignalEnvelopes.mqh new file mode 100644 index 0000000..1b5a249 --- /dev/null +++ b/Expert/Signal/SignalEnvelopes.mqh @@ -0,0 +1,193 @@ +//+------------------------------------------------------------------+ +//| SignalEnvelopes.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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) && closelower-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 +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalITF.mqh b/Expert/Signal/SignalITF.mqh new file mode 100644 index 0000000..a582133 --- /dev/null +++ b/Expert/Signal/SignalITF.mqh @@ -0,0 +1,91 @@ +//+------------------------------------------------------------------+ +//| SignalITF.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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< +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalMACD.mqh b/Expert/Signal/SignalMACD.mqh new file mode 100644 index 0000000..3ccc1df --- /dev/null +++ b/Expert/Signal/SignalMACD.mqh @@ -0,0 +1,408 @@ +//+------------------------------------------------------------------+ +//| SignalMACD.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalRSI.mqh b/Expert/Signal/SignalRSI.mqh new file mode 100644 index 0000000..27f4dff --- /dev/null +++ b/Expert/Signal/SignalRSI.mqh @@ -0,0 +1,400 @@ +//+------------------------------------------------------------------+ +//| SignalRSI.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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) +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalSAR.mqh b/Expert/Signal/SignalSAR.mqh new file mode 100644 index 0000000..3851b89 --- /dev/null +++ b/Expert/Signal/SignalSAR.mqh @@ -0,0 +1,168 @@ +//+------------------------------------------------------------------+ +//| SignalSAR.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalStoch.mqh b/Expert/Signal/SignalStoch.mqh new file mode 100644 index 0000000..05b7b83 --- /dev/null +++ b/Expert/Signal/SignalStoch.mqh @@ -0,0 +1,426 @@ +//+------------------------------------------------------------------+ +//| SignalStoch.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalTEMA.mqh b/Expert/Signal/SignalTEMA.mqh new file mode 100644 index 0000000..dbc50f8 --- /dev/null +++ b/Expert/Signal/SignalTEMA.mqh @@ -0,0 +1,257 @@ +//+------------------------------------------------------------------+ +//| SignalTEMA.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalTRIX.mqh b/Expert/Signal/SignalTRIX.mqh new file mode 100644 index 0000000..9e588fd --- /dev/null +++ b/Expert/Signal/SignalTRIX.mqh @@ -0,0 +1,395 @@ +//+------------------------------------------------------------------+ +//| SignalTRIX.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/SignalWPR.mqh b/Expert/Signal/SignalWPR.mqh new file mode 100644 index 0000000..987c096 --- /dev/null +++ b/Expert/Signal/SignalWPR.mqh @@ -0,0 +1,371 @@ +//+------------------------------------------------------------------+ +//| SignalWPR.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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]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>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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/mySignals/supertrendsignal.mqh b/Expert/Signal/mySignals/supertrendsignal.mqh new file mode 100644 index 0000000..df98487 --- /dev/null +++ b/Expert/Signal/mySignals/supertrendsignal.mqh @@ -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 +//--- 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Signal/signalcrossema.mqh b/Expert/Signal/signalcrossema.mqh new file mode 100644 index 0000000..7ea6d92 --- /dev/null +++ b/Expert/Signal/signalcrossema.mqh @@ -0,0 +1,246 @@ +//+------------------------------------------------------------------+ +//| SignalCrossEMA.mqh | +//| Copyright © 2010, MetaQuotes Software Corp. | +//| http://www.metaquotes.net | +//| Revision 2010.10.12 | +//+------------------------------------------------------------------+ +#include +// 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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Trailing/TrailingFixedPips.mqh b/Expert/Trailing/TrailingFixedPips.mqh new file mode 100644 index 0000000..1cdf125 --- /dev/null +++ b/Expert/Trailing/TrailingFixedPips.mqh @@ -0,0 +1,132 @@ +//+------------------------------------------------------------------+ +//| TrailingFixedPips.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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())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); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Trailing/TrailingMA.mqh b/Expert/Trailing/TrailingMA.mqh new file mode 100644 index 0000000..754ab6b --- /dev/null +++ b/Expert/Trailing/TrailingMA.mqh @@ -0,0 +1,157 @@ +//+------------------------------------------------------------------+ +//| TrailingMA.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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_sllevel) + sl=new_sl; +//--- + return(sl!=EMPTY_VALUE); + } +//+------------------------------------------------------------------+ diff --git a/Expert/Trailing/TrailingNone.mqh b/Expert/Trailing/TrailingNone.mqh new file mode 100644 index 0000000..5259f84 --- /dev/null +++ b/Expert/Trailing/TrailingNone.mqh @@ -0,0 +1,40 @@ +//+------------------------------------------------------------------+ +//| TrailingNone.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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) + { + } +//+------------------------------------------------------------------+ diff --git a/Expert/Trailing/TrailingParabolicSAR.mqh b/Expert/Trailing/TrailingParabolicSAR.mqh new file mode 100644 index 0000000..5cd07c4 --- /dev/null +++ b/Expert/Trailing/TrailingParabolicSAR.mqh @@ -0,0 +1,123 @@ +//+------------------------------------------------------------------+ +//| TrailingParabolicSAR.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +// 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_sllevel) + sl=new_sl; +//--- + return(sl!=EMPTY_VALUE); + } +//+------------------------------------------------------------------+ diff --git a/Files/File.mqh b/Files/File.mqh new file mode 100644 index 0000000..a555943 --- /dev/null +++ b/Files/File.mqh @@ -0,0 +1,292 @@ +//+------------------------------------------------------------------+ +//| File.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| 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); + } +//+------------------------------------------------------------------+ diff --git a/Files/FileBMP.mqh b/Files/FileBMP.mqh new file mode 100644 index 0000000..337c782 --- /dev/null +++ b/Files/FileBMP.mqh @@ -0,0 +1,183 @@ +//+------------------------------------------------------------------+ +//| FileBMP.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include + +//+------------------------------------------------------------------+ +//| 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) + uint WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY); + template + uint WriteStruct(T &data); + bool WriteObject(CObject *object); + template + 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 + uint ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY); + template + uint ReadStruct(T &data); + bool ReadObject(CObject *object); + template + 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 +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 +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 +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 +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 +bool CFileBin::ReadEnum(T &value) + { + int val; + if(!ReadInteger(val)) + return(false); +//--- + value=(T)val; + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Files/FilePipe.mqh b/Files/FilePipe.mqh new file mode 100644 index 0000000..cf051bb --- /dev/null +++ b/Files/FilePipe.mqh @@ -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 + 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 + uint WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY); + template + uint WriteStruct(T &data); + bool WriteObject(CObject *object); + template + uint WriteEnum(const T value) { return(WriteInteger((int)value)); } + //--- methods for reading data + template + 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 + uint ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY); + template + uint ReadStruct(T &data); + bool ReadObject(CObject *object); + template + 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 +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 +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 +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 +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 +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 +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 +bool CFilePipe::ReadEnum(T &value) + { + int val; + if(!ReadInteger(val)) + return(false); +//--- + value=(T)val; + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Files/FileTxt.mqh b/Files/FileTxt.mqh new file mode 100644 index 0000000..f30cf85 --- /dev/null +++ b/Files/FileTxt.mqh @@ -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(""); + } +//+------------------------------------------------------------------+ diff --git a/Generic/ArrayList.mqh b/Generic/ArrayList.mqh new file mode 100644 index 0000000..d905229 Binary files /dev/null and b/Generic/ArrayList.mqh differ diff --git a/Generic/HashMap.mqh b/Generic/HashMap.mqh new file mode 100644 index 0000000..1ea74b8 --- /dev/null +++ b/Generic/HashMap.mqh @@ -0,0 +1,622 @@ +//+------------------------------------------------------------------+ +//| HashMap.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +#include +#include "HashSet.mqh" +//+------------------------------------------------------------------+ +//| Struct Entry. | +//| Usage: Internal structure for organization CHashMap. | +//+------------------------------------------------------------------+ +template +struct Entry: public Slot + { +public: + TKey key; + Entry(void): key((TKey)NULL) {} + }; +//+------------------------------------------------------------------+ +//| Class CKeyValuePair. | +//| Usage: Defines a key/value pair that can be set or retrieved. | +//+------------------------------------------------------------------+ +template +class CKeyValuePair: public IComparable*> + { +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*Clone(void) { return new CKeyValuePair(m_key,m_value); } + //--- method to compare keys + int Compare(CKeyValuePair*pair) { return ::Compare(m_key,pair.m_key); } + //--- method for determining equality + bool Equals(CKeyValuePair*pair) { return ::Equals(m_key,pair.m_key); } + //--- method to calculate hash code + int HashCode(void) { return ::GetHashCode(m_key); } + }; +//+------------------------------------------------------------------+ +//| Class CKeyValuePairComparer. | +//| Usage: Provides a comparer class for convertation IComparer| +//| to the IComparer*> interface. | +//+------------------------------------------------------------------+ +template +class CKeyValuePairComparer: public IComparer*> + { +private: + IComparer*m_comparer; + +public: + CKeyValuePairComparer(IComparer*comaprer) { m_comparer=comaprer; } + int Compare(CKeyValuePair* x,CKeyValuePair* y) { return(m_comparer.Compare(x.Key(), y.Key())); } + }; +//+------------------------------------------------------------------+ +//| Class CHashMap. | +//| Usage: Represents a collection of keys and values. | +//+------------------------------------------------------------------+ +template +class CHashMap: public IMap + { +protected: + int m_buckets[]; + Entrym_entries[]; + int m_count; + int m_capacity; + int m_free_list; + int m_free_count; + IEqualityComparer*m_comparer; + bool m_delete_comparer; + +public: + CHashMap(void); + CHashMap(const int capacity); + CHashMap(IEqualityComparer*comparer); + CHashMap(const int capacity,IEqualityComparer*comparer); + CHashMap(IMap*map); + CHashMap(IMap*map,IEqualityComparer*comparer); + ~CHashMap(void); + //--- methods of filling data + bool Add(CKeyValuePair*pair); + bool Add(TKey key,TValue value); + //--- methods of access to protected data + int Count(void) { return(m_count-m_free_count); } + IEqualityComparer*Comparer(void) const { return(m_comparer); } + bool Contains(CKeyValuePair*item); + bool Contains(TKey key,TValue value); + bool ContainsKey(TKey key); + bool ContainsValue(TValue value); + //--- methods of copy data from collection + int CopyTo(CKeyValuePair*&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*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 class | +//| that is empty, has the default initial capacity, and uses the | +//| default equality comparer for the key type. | +//+------------------------------------------------------------------+ +template +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(); + m_delete_comparer=true; + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashMap class | +//| that is empty, has the specified initial capacity, and uses the | +//| default equality comparer for the key type. | +//+------------------------------------------------------------------+ +template +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(); + m_delete_comparer=true; + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashMap class | +//| that is empty, has the default initial capacity, and uses the | +//| specified IEqualityComparer. | +//+------------------------------------------------------------------+ +template +CHashMap::CHashMap(IEqualityComparer*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(); + m_delete_comparer=true; + } + else + { + //--- use specified equality comaprer + m_comparer=comparer; + m_delete_comparer=false; + } + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashMap class | +//| that is empty, has the specified initial capacity, and uses the | +//| specified IEqualityComparer. | +//+------------------------------------------------------------------+ +template +CHashMap::CHashMap(const int capacity,IEqualityComparer*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(); + m_delete_comparer=true; + } + else + { + //--- use specified equality comaprer + m_comparer=comparer; + m_delete_comparer=false; + } + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashMap class | +//| that contains elements copied from the specified | +//| IMap and uses the default equality comparer for the | +//| key type. | +//+------------------------------------------------------------------+ +template +CHashMap::CHashMap(IMap*map): m_count(0), + m_free_list(0), + m_free_count(0), + m_capacity(0) + { +//--- use default equality comaprer + m_comparer=new CDefaultEqualityComparer(); + 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 class | +//| that contains elements copied from the specified | +//| IMap and uses the specified IEqualityComparer.| +//+------------------------------------------------------------------+ +template +CHashMap::CHashMap(IMap*map,IEqualityComparer*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(); + 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 +CHashMap::~CHashMap(void) + { + if(m_delete_comparer) + delete m_comparer; + } +//+------------------------------------------------------------------+ +//| Adds the specified key-value pair to the map. | +//+------------------------------------------------------------------+ +template +bool CHashMap::Add(CKeyValuePair*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 +bool CHashMap::Add(TKey key,TValue value) + { + return(Insert(key,value,true)); + } +//+------------------------------------------------------------------+ +//| Determines whether the map contains the specified key-value pair.| +//+------------------------------------------------------------------+ +template +bool CHashMap::Contains(CKeyValuePair*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 + CDefaultEqualityComparercomparer; +//--- 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 +bool CHashMap::Contains(TKey key,TValue value) + { +//--- find pair with specified key + int i=FindEntry(key); +//--- create default equality value comparer + CDefaultEqualityComparercomparer; +//--- 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 +bool CHashMap::ContainsKey(TKey key) + { + return(FindEntry(key)>=0); + } +//+------------------------------------------------------------------+ +//| Determines whether the map contains the specified value. | +//+------------------------------------------------------------------+ +template +bool CHashMap::ContainsValue(TValue value) + { +//--- create default equality value comparer + CDefaultEqualityComparercomparer_value(); +//--- try to find pair contains specified value + for(int i=0; i=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 +int CHashMap::CopyTo(CKeyValuePair*&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=0) + { + //--- check indexes + if(dst_start+index>=ArraySize(dst_array) || index>=m_count) + return(index); + dst_array[dst_start+index++]=new CKeyValuePair(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 +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=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 +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 +bool CHashMap::Remove(CKeyValuePair*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 + CDefaultEqualityComparercomparer_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 +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 +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 +bool CHashMap::TrySetValue(TKey key,TValue value) + { + return(Insert(key, value, false)); + } +//+------------------------------------------------------------------+ +//| Initialize map with specified capacity. | +//+------------------------------------------------------------------+ +template +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 +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=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 +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 +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 +static int CHashMap::m_collision_threshold=8; +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Generic/HashSet.mqh b/Generic/HashSet.mqh new file mode 100644 index 0000000..9a51f8d --- /dev/null +++ b/Generic/HashSet.mqh @@ -0,0 +1,972 @@ +//+------------------------------------------------------------------+ +//| HashSet.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +//+------------------------------------------------------------------+ +//| Struct Slot. | +//| Usage: Internal structure for organization CHashSet. | +//+------------------------------------------------------------------+ +template +struct Slot + { +public: + int hash_code; + T value; + int next; + Slot(void): hash_code(0),value((T)NULL),next(0) {} + }; +//+------------------------------------------------------------------+ +//| Class CHashSet. | +//| Usage: Represents a set of unique values. | +//+------------------------------------------------------------------+ +template +class CHashSet: public ISet + { +protected: + int m_buckets[]; + Slot m_slots[]; + int m_count; + int m_last_index; + int m_free_list; + IEqualityComparer*m_comparer; + bool m_delete_comparer; + +public: + CHashSet(void); + CHashSet(IEqualityComparer*comparer); + CHashSet(ICollection*collection); + CHashSet(ICollection*collection,IEqualityComparer*comparer); + CHashSet(T &array[]); + CHashSet(T &array[],IEqualityComparer*comparer); + ~CHashSet(void); + //--- methods of filling data + bool Add(T value); + //--- methods of access to protected data + int Count(void) { return(m_count); } + IEqualityComparer* 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*collection); + void ExceptWith(T &array[]); + void IntersectWith(ICollection*collection); + void IntersectWith(T &array[]); + void SymmetricExceptWith(ICollection*collection); + void SymmetricExceptWith(T &array[]); + void UnionWith(ICollection*collection); + void UnionWith(T &array[]); + //--- methods for determining the relationship between sets + bool IsProperSubsetOf(ICollection*collection); + bool IsProperSubsetOf(T &array[]); + bool IsProperSupersetOf(ICollection*collection); + bool IsProperSupersetOf(T &array[]); + bool IsSubsetOf(ICollection*collection); + bool IsSubsetOf(T &array[]); + bool IsSupersetOf(ICollection*collection); + bool IsSupersetOf(T &array[]); + bool Overlaps(ICollection*collection); + bool Overlaps(T &array[]); + bool SetEquals(ICollection*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*set); + bool InternalIsSubsetOf(CHashSet*set); + bool InternalIsSupersetOf(CHashSet*set); + bool InternalIsProperSubsetOf(CHashSet*set); + bool InternalIsProperSupersetOf(CHashSet*set); + }; +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashSet class that is empty| +//| and uses the default equality comparer for the set type. | +//+------------------------------------------------------------------+ +template +CHashSet::CHashSet(void): m_count(0), + m_last_index(0), + m_free_list(-1) + { +//--- use default equality comaprer + m_comparer=new CDefaultEqualityComparer(); + m_delete_comparer=true; + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashSet class that is empty| +//| and uses the specified equality comparer for the set type. | +//+------------------------------------------------------------------+ +template +CHashSet::CHashSet(IEqualityComparer*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(); + m_delete_comparer=true; + } + else + { + //--- use specified equality comaprer + m_comparer=comparer; + m_delete_comparer=false; + } + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CHashSet 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 +CHashSet::CHashSet(ICollection*collection): m_count(0), + m_last_index(0), + m_free_list(-1) + { +//--- use default equality comaprer + m_comparer=new CDefaultEqualityComparer(); + 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 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 +CHashSet::CHashSet(ICollection*collection,IEqualityComparer*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(); + 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 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 +CHashSet::CHashSet(T &array[]): m_count(0), + m_last_index(0), + m_free_list(-1) + { +//--- use default equality comaprer + m_comparer=new CDefaultEqualityComparer(); + 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 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 +CHashSet::CHashSet(T &array[],IEqualityComparer*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(); + 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 CHashSet::~CHashSet(void) + { + if(m_delete_comparer) + delete m_comparer; + } +//+------------------------------------------------------------------+ +//| Adds the specified element to a set. | +//+------------------------------------------------------------------+ +template +bool CHashSet::Add(T value) + { + return AddIfNotPresent(value); + } +//+------------------------------------------------------------------+ +//| Determines whether a set contains the specified element. | +//+------------------------------------------------------------------+ +template +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 +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=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 +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=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 +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 +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 +void CHashSet::ExceptWith(ICollection*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 +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 +void CHashSet::IntersectWith(ICollection*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=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 +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 + CHashSetset(array); + for(int i=0; i=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 +void CHashSet::SymmetricExceptWith(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + InternalSymmetricExceptWith(ptr_set); + } + else + { + //--- create a set based on a specified collection + CHashSetset(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 +void CHashSet::SymmetricExceptWith(T &array[]) + { +//--- if set is empty, then symmetric difference is other + if(m_count==0) + { + UnionWith(array); + return; + } +//--- symmetric except + CHashSetset(array); + InternalSymmetricExceptWith(GetPointer(set)); + } +//+------------------------------------------------------------------+ +//| Modifies the current set to contain all elements that are present| +//| in itself, the specified collection, or both. | +//+------------------------------------------------------------------+ +template +void CHashSet::UnionWith(ICollection*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 +void CHashSet::UnionWith(T &array[]) + { + for(int i=0; i +bool CHashSet::IsProperSubsetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return InternalIsProperSubsetOf(ptr_set); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return InternalIsProperSubsetOf(GetPointer(set)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a proper subset of the specified | +//| array. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return InternalIsProperSubsetOf(GetPointer(set)); + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a proper superset of the specified | +//| collection. | +//+------------------------------------------------------------------+ +template +bool CHashSet::IsProperSupersetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return InternalIsProperSupersetOf(ptr_set); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return InternalIsProperSupersetOf(GetPointer(set)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a proper superset of the specified | +//| array. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return InternalIsProperSupersetOf(GetPointer(set)); + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a subset of the specified collection.| +//+------------------------------------------------------------------+ +template +bool CHashSet::IsSubsetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return InternalIsSubsetOf(ptr_set); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return InternalIsSubsetOf(GetPointer(set)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a subset of the specified array. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return InternalIsSubsetOf(GetPointer(set)); + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a superset of the specified | +//| collection. | +//+------------------------------------------------------------------+ +template +bool CHashSet::IsSupersetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return InternalIsSupersetOf(ptr_set); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return InternalIsSupersetOf(GetPointer(set)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a superset of the specified array. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return InternalIsSupersetOf(GetPointer(set)); + } +//+------------------------------------------------------------------+ +//| Determines whether the current set and a specified collection | +//| share common elements. | +//+------------------------------------------------------------------+ +template +bool CHashSet::Overlaps(ICollection*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 +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 +bool CHashSet::SetEquals(ICollection*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 +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 +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 +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 +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 +void CHashSet::InternalSymmetricExceptWith(CHashSet*set) + { + for(int i=0; i +bool CHashSet::InternalIsSubsetOf(CHashSet*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 +bool CHashSet::InternalIsSupersetOf(CHashSet*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 +bool CHashSet::InternalIsProperSubsetOf(CHashSet*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 +bool CHashSet::InternalIsProperSupersetOf(CHashSet*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. | +//| Usage: Defines methods to manipulate generic collections. | +//+------------------------------------------------------------------+ +template +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); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IComparable.mqh b/Generic/Interfaces/IComparable.mqh new file mode 100644 index 0000000..17aeebe --- /dev/null +++ b/Generic/Interfaces/IComparable.mqh @@ -0,0 +1,19 @@ +//+------------------------------------------------------------------+ +//| IComparable.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include "IEqualityComparable.mqh" +//+------------------------------------------------------------------+ +//| Interface IComparable. | +//| Usage: Defines a generalized comparison method to create a | +//| type-specific comparison method for ordering or sorting | +//| instances. | +//+------------------------------------------------------------------+ +template +interface IComparable: public IEqualityComparable + { +//--- method for determining compare + int Compare(T value); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IComparer.mqh b/Generic/Interfaces/IComparer.mqh new file mode 100644 index 0000000..5575388 --- /dev/null +++ b/Generic/Interfaces/IComparer.mqh @@ -0,0 +1,17 @@ +//+------------------------------------------------------------------+ +//| IComparer.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Interface IComparer. | +//| Usage: Defines a method that a type implements to compare two | +//| values. | +//+------------------------------------------------------------------+ +template +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); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IEqualityComparable.mqh b/Generic/Interfaces/IEqualityComparable.mqh new file mode 100644 index 0000000..6cb985c --- /dev/null +++ b/Generic/Interfaces/IEqualityComparable.mqh @@ -0,0 +1,19 @@ +//+------------------------------------------------------------------+ +//| IEqualityComparable.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Interface IEqualityComparable. | +//| Usage: Defines a generalized method to create a type-specific | +//| method for determining equality of instances. | +//+------------------------------------------------------------------+ +template +interface IEqualityComparable + { +//--- method for determining equality + bool Equals(T value); +//--- method to calculate hash code + int HashCode(void); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IEqualityComparer.mqh b/Generic/Interfaces/IEqualityComparer.mqh new file mode 100644 index 0000000..04f0c30 --- /dev/null +++ b/Generic/Interfaces/IEqualityComparer.mqh @@ -0,0 +1,19 @@ +//+------------------------------------------------------------------+ +//| IEqualityComparer.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Interface IEqualityComparer. | +//| Usage: Defines methods to support the comparison of values for | +//| equality. | +//+------------------------------------------------------------------+ +template +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); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IList.mqh b/Generic/Interfaces/IList.mqh new file mode 100644 index 0000000..d579bc2 --- /dev/null +++ b/Generic/Interfaces/IList.mqh @@ -0,0 +1,26 @@ +//+------------------------------------------------------------------+ +//| IList.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ICollection.mqh" +//+------------------------------------------------------------------+ +//| Interface IList. | +//| Usage: Represents a collection of objects that can be | +//| individually accessed by index. | +//+------------------------------------------------------------------+ +template +interface IList: public ICollection + { +//--- 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); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/IMap.mqh b/Generic/Interfaces/IMap.mqh new file mode 100644 index 0000000..c3bf6b2 --- /dev/null +++ b/Generic/Interfaces/IMap.mqh @@ -0,0 +1,27 @@ +//+------------------------------------------------------------------+ +//| IMap.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ICollection.mqh" +template +class CKeyValuePair; +//+------------------------------------------------------------------+ +//| Interface IMap. | +//| Usage: Represents a generic collection of key/value pairs. | +//+------------------------------------------------------------------+ +template +interface IMap: public ICollection*> + { +//--- 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); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Interfaces/ISet.mqh b/Generic/Interfaces/ISet.mqh new file mode 100644 index 0000000..55fcf20 --- /dev/null +++ b/Generic/Interfaces/ISet.mqh @@ -0,0 +1,37 @@ +//+------------------------------------------------------------------+ +//| ISet.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include "ICollection.mqh" +//+------------------------------------------------------------------+ +//| Interface ISet. | +//| Usage: Provides the base interface for the abstraction of sets. | +//+------------------------------------------------------------------+ +template +interface ISet: public ICollection + { +//--- methods of changing sets + void ExceptWith(ICollection*collection); + void ExceptWith(T &array[]); + void IntersectWith(ICollection*collection); + void IntersectWith(T &array[]); + void SymmetricExceptWith(ICollection*collection); + void SymmetricExceptWith(T &array[]); + void UnionWith(ICollection*collection); + void UnionWith(T &array[]); +//--- methods for determining the relationship between sets + bool IsProperSubsetOf(ICollection*collection); + bool IsProperSubsetOf(T &array[]); + bool IsProperSupersetOf(ICollection*collection); + bool IsProperSupersetOf(T &array[]); + bool IsSubsetOf(ICollection*collection); + bool IsSubsetOf(T &array[]); + bool IsSupersetOf(ICollection*collection); + bool IsSupersetOf(T &array[]); + bool Overlaps(ICollection*collection); + bool Overlaps(T &array[]); + bool SetEquals(ICollection*collection); + bool SetEquals(T &array[]); + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/ArrayFunction.mqh b/Generic/Internal/ArrayFunction.mqh new file mode 100644 index 0000000..a07c29d --- /dev/null +++ b/Generic/Internal/ArrayFunction.mqh @@ -0,0 +1,135 @@ +//+------------------------------------------------------------------+ +//| ArrayFunction.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include "CompareFunction.mqh" +#include +//+------------------------------------------------------------------+ +//| Searches an entire one-dimensional sorted array for a specific | +//| element, using the IComparable generic interface implemented | +//| by each element of the array and by the specified object. | +//+------------------------------------------------------------------+ +template +int ArrayBinarySearch(T &array[],const int start_index,const int count, T value,IComparer*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>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 +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 +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 +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 +//+------------------------------------------------------------------+ +//| 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(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(xy) + return(1); + else if(x +int Compare(T x,T y) + { +//--- try to convert to comparable object + IComparable*comparable=dynamic_cast*>(x); + if(comparable) + { + //--- use specied compare method + return comparable.Compare(y); + } + else + { + //--- unknown compare function + return(0); + } + } +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/DefaultComparer.mqh b/Generic/Internal/DefaultComparer.mqh new file mode 100644 index 0000000..8c1b6a3 --- /dev/null +++ b/Generic/Internal/DefaultComparer.mqh @@ -0,0 +1,22 @@ +//+------------------------------------------------------------------+ +//| DefaultComparer.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "CompareFunction.mqh" +//+------------------------------------------------------------------+ +//| Class CDefaultComparer. | +//| Usage: Provides a default class for implementations of the | +//| IComparer generic interface. | +//+------------------------------------------------------------------+ +template +class CDefaultComparer: public IComparer + { +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); } + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/DefaultEqualityComparer.mqh b/Generic/Internal/DefaultEqualityComparer.mqh new file mode 100644 index 0000000..ff819b0 --- /dev/null +++ b/Generic/Internal/DefaultEqualityComparer.mqh @@ -0,0 +1,25 @@ +//+------------------------------------------------------------------+ +//| DefaultEqualityComparer.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include "EqualFunction.mqh" +#include "HashFunction.mqh" +//+------------------------------------------------------------------+ +//| Class CDefaultEqualityComparer. | +//| Usage: Provides a default class for implementations of the | +//| IEqualityComparer generic interface. | +//+------------------------------------------------------------------+ +template +class CDefaultEqualityComparer: public IEqualityComparer + { +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); } + }; +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/EqualFunction.mqh b/Generic/Internal/EqualFunction.mqh new file mode 100644 index 0000000..9f1a8a9 --- /dev/null +++ b/Generic/Internal/EqualFunction.mqh @@ -0,0 +1,26 @@ +//+------------------------------------------------------------------+ +//| EqualFunction.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +//+------------------------------------------------------------------+ +//| Indicates whether x object is equal y object of the same type. | +//+------------------------------------------------------------------+ +template +bool Equals(T x,T y) + { +//--- try to convert to equality comparable object + IEqualityComparable*equtable=dynamic_cast*>(x); + if(equtable) + { + //--- use specied equality compare method + return equtable.Equals(y); + } + else + { + //--- use default equality comparer operator + return(x==y); + } + } +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/HashFunction.mqh b/Generic/Internal/HashFunction.mqh new file mode 100644 index 0000000..9894464 --- /dev/null +++ b/Generic/Internal/HashFunction.mqh @@ -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 +int GetHashCode(T value) + { +//--- try to convert to equality comparable object + IEqualityComparable*equtable=dynamic_cast*>(value); + if(equtable) + { + //--- calculate hash by specied method + return equtable.HashCode(); + } + else + { + //--- calculate hash from name of object + return GetHashCode(typename(value)); + } + } +//+------------------------------------------------------------------+ diff --git a/Generic/Internal/Introsort.mqh b/Generic/Internal/Introsort.mqh new file mode 100644 index 0000000..847db50 --- /dev/null +++ b/Generic/Internal/Introsort.mqh @@ -0,0 +1,244 @@ +//+------------------------------------------------------------------+ +//| Introsort.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Struct Introsort. | +//| Usage: Used by the sort methods for instances of array. | +//+------------------------------------------------------------------+ +template +struct Introsort + { +public: + IComparer* 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 +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 +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 +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 +int Introsort::FloorLog2(int n) const + { + int result=0; + while(n>=1) + { + result++; + n=n/2; + } + return(result); + } +//+------------------------------------------------------------------+ +//| Introspective sort. | +//+------------------------------------------------------------------+ +template +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 +void Introsort::InsertionSort(const int lo,const int hi) + { + int i,j; + TKey t; + TItem dt; + for(i=lo; i=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 +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) + break; + Swap(left,right); + } +//--- Put pivot in the right location. + Swap(left,(hi-1)); + return (left); + } +//+------------------------------------------------------------------+ +//| Heap sorting algorithm. | +//+------------------------------------------------------------------+ +template +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 +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=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)); + } +//+------------------------------------------------------------------+ diff --git a/Generic/LinkedList.mqh b/Generic/LinkedList.mqh new file mode 100644 index 0000000..da9a83e --- /dev/null +++ b/Generic/LinkedList.mqh @@ -0,0 +1,563 @@ +//+------------------------------------------------------------------+ +//| LinkedList.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +//+------------------------------------------------------------------+ +//| Class CLinkedListNode. | +//| Usage: Represents a node of linked list. | +//+------------------------------------------------------------------+ +template +class CLinkedListNode + { +protected: + CLinkedList*m_list; + CLinkedListNode*m_next; + CLinkedListNode*m_prev; + T m_item; + +public: + CLinkedListNode(T value): m_item(value) { } + CLinkedListNode(CLinkedList*list,T value): m_list(list),m_item(value) { } + ~CLinkedListNode(void) { } + //--- methods of access to protected data + CLinkedList* List(void) { return(m_list); } + void List(CLinkedList*value) { m_list=value; } + CLinkedListNode*Next(void) { return(m_next); } + void Next(CLinkedListNode*value) { m_next=value; } + CLinkedListNode*Previous(void) { return(m_prev); } + void Previous(CLinkedListNode*value) { m_prev=value; } + T Value(void) { return(m_item); } + void Value(T value) { m_item=value; } + }; +//+------------------------------------------------------------------+ +//| Class CLinkedList. | +//| Usage: Represents a doubly linked list. | +//+------------------------------------------------------------------+ +template +class CLinkedList: public ICollection + { +protected: + CLinkedListNode*m_head; + int m_count; + +public: + CLinkedList(void); + CLinkedList(ICollection*collection); + CLinkedList(T &array[]); + ~CLinkedList(void); + //--- methods of filling data + bool Add(T value); + CLinkedListNode*AddAfter(CLinkedListNode*node,T value); + bool AddAfter(CLinkedListNode*node,CLinkedListNode*new_node); + CLinkedListNode*AddBefore(CLinkedListNode*node,T value); + bool AddBefore(CLinkedListNode*node,CLinkedListNode*new_node); + CLinkedListNode*AddFirst(T value); + bool AddFirst(CLinkedListNode*node); + CLinkedListNode*AddLast(T value); + bool AddLast(CLinkedListNode*node); + //--- methods of access to protected data + int Count(void); + CLinkedListNode*Head(void) {return(m_head);} + CLinkedListNode*First(void); + CLinkedListNode*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*node); + bool RemoveFirst(void); + bool RemoveLast(void); + //--- method for searching + CLinkedListNode*Find(T value); + CLinkedListNode*FindLast(T value); + +private: + bool ValidateNode(CLinkedListNode*node); + bool ValidateNewNode(CLinkedListNode*node); + void InternalInsertNodeBefore(CLinkedListNode*node,CLinkedListNode*new_node); + void InternalInsertNodeToEmptyList(CLinkedListNode*new_node); + void InternalRemoveNode(CLinkedListNode*node); + }; +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CLinkedList class that is | +//| empty. | +//+------------------------------------------------------------------+ +template +CLinkedList::CLinkedList(void): m_count(0) + { + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CLinkedList class that | +//| contains elements copied from the specified array and has | +//| sufficient capacity to accommodate the number of elements copied.| +//+------------------------------------------------------------------+ +template +CLinkedList::CLinkedList(T &array[]): m_count(0) + { + for(int i=0; i class that | +//| contains elements copied from the specified collection and has | +//| sufficient capacity to accommodate the number of elements copied.| +//+------------------------------------------------------------------+ +template +CLinkedList::CLinkedList(ICollection*collection): m_count(0) + { +//--- check collection + if(CheckPointer(collection)!=POINTER_INVALID) + { + T array[]; + int size=collection.CopyTo(array,0); + for(int i=0; i +CLinkedList::~CLinkedList(void) + { + Clear(); + } +//+------------------------------------------------------------------+ +//| Adds an value to the end of the list. | +//+------------------------------------------------------------------+ +template +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. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::AddAfter(CLinkedListNode*node,T value) + { +//--- check node + if(!ValidateNode(node)) + return(NULL); +//--- create new node + CLinkedListNode*result=new CLinkedListNode(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. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::AddAfter(CLinkedListNode*node,CLinkedListNode*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. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::AddBefore(CLinkedListNode*node,T value) + { +//--- check node + if(!ValidateNode(node)) + return(NULL); +//--- create new node + CLinkedListNode*result=new CLinkedListNode(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. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::AddBefore(CLinkedListNode*node,CLinkedListNode*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. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::AddFirst(T value) + { +//--- create new node + CLinkedListNode*node=new CLinkedListNode(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. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::AddFirst(CLinkedListNode*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. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::AddLast(T value) + { +//--- create new node + CLinkedListNode*node=new CLinkedListNode(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. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::AddLast(CLinkedListNode*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 +int CLinkedList::Count(void) + { + return(m_count); + } +//+------------------------------------------------------------------+ +//| Gets the first node of the CLinkedList. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::First(void) + { + return(m_head); + } +//+------------------------------------------------------------------+ +//| Gets the last node of the CLinkedList. | +//+------------------------------------------------------------------+ +template +CLinkedListNode*CLinkedList::Last(void) + { + return(CheckPointer(m_head)!=POINTER_INVALID ? m_head.Previous() : NULL); + } +//+------------------------------------------------------------------+ +//| Determines whether a value is in the CLinkedList. | +//+------------------------------------------------------------------+ +template +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 +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*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. | +//+------------------------------------------------------------------+ +template +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*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. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::Remove(T item) + { +//--- find node with specified value + CLinkedListNode*node=Find(item); + if(CheckPointer(node)!=POINTER_INVALID) + { + //--- remove node + InternalRemoveNode(node); + return(true); + } + return(false); + } +//+------------------------------------------------------------------+ +//| Removes the specified node from the LinkedList. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::Remove(CLinkedListNode*node) + { +//--- check node + if(ValidateNode(node)) + { + //--- remove node + InternalRemoveNode(node); + return(true); + } + return(false); + } +//+------------------------------------------------------------------+ +//| Removes the node at the start of the CLinkedList. | +//+------------------------------------------------------------------+ +template +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. | +//+------------------------------------------------------------------+ +template +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 +CLinkedListNode*CLinkedList::Find(T value) + { + CLinkedListNode*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 +CLinkedListNode*CLinkedList::FindLast(T value) + { +//--- check head node + if(CheckPointer(m_head)==POINTER_INVALID) + return(NULL); +//--- get last node + CLinkedListNode *last = m_head.Previous(); + CLinkedListNode *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 +bool CLinkedList::ValidateNode(CLinkedListNode*node) + { + return(CheckPointer(node)!=POINTER_INVALID && node.List()==GetPointer(this)); + } +//+------------------------------------------------------------------+ +//| Validation of new node on not null. | +//+------------------------------------------------------------------+ +template +bool CLinkedList::ValidateNewNode(CLinkedListNode*node) + { + return(CheckPointer(node)!=POINTER_INVALID && node.List()==NULL); + } +//+------------------------------------------------------------------+ +//| Insert node before the specified node. | +//+------------------------------------------------------------------+ +template +void CLinkedList::InternalInsertNodeBefore(CLinkedListNode*node,CLinkedListNode*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 +void CLinkedList::InternalInsertNodeToEmptyList(CLinkedListNode*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 +void CLinkedList::InternalRemoveNode(CLinkedListNode*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; + } +//+------------------------------------------------------------------+ diff --git a/Generic/Queue.mqh b/Generic/Queue.mqh new file mode 100644 index 0000000..3cd1d6e Binary files /dev/null and b/Generic/Queue.mqh differ diff --git a/Generic/RedBlackTree.mqh b/Generic/RedBlackTree.mqh new file mode 100644 index 0000000..8335b5a Binary files /dev/null and b/Generic/RedBlackTree.mqh differ diff --git a/Generic/SortedMap.mqh b/Generic/SortedMap.mqh new file mode 100644 index 0000000..e40152b --- /dev/null +++ b/Generic/SortedMap.mqh @@ -0,0 +1,341 @@ +//+------------------------------------------------------------------+ +//| SortedMap.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +#include +#include "HashMap.mqh" +#include "SortedSet.mqh" +//+------------------------------------------------------------------+ +//| Class CSortedMap. | +//| Usage: Represents a collection of key/value pairs that are sorted| +//| on the key. | +//+------------------------------------------------------------------+ +template +class CSortedMap: public IMap + { +protected: + CRedBlackTree*>*m_tree; + IComparer*m_comparer; + bool m_delete_comparer; + +public: + CSortedMap(void); + CSortedMap(IComparer*comparer); + CSortedMap(IMap*map); + CSortedMap(IMap*map,IComparer*comparer); + ~CSortedMap(void); + //--- methods of filling data + bool Add(CKeyValuePair*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*item) { return m_tree.Contains(item); } + bool Contains(TKey key,TValue value); + bool ContainsKey(TKey key); + bool ContainsValue(TValue value); + IComparer *Comparer(void) const { return(m_comparer); } + //--- methods of copy data from collection + int CopyTo(CKeyValuePair*&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*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*>*node); + }; +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedMap class | +//| that is empty, has the default initial capacity, and uses the | +//| default comparer for the key type. | +//+------------------------------------------------------------------+ +template +CSortedMap::CSortedMap(void) + { +//--- use default comaprer + m_comparer=new CDefaultComparer(); + m_delete_comparer=true; + m_tree=new CRedBlackTree*>(new CKeyValuePairComparer(m_comparer)); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedMap class | +//| that is empty, has the default initial capacity, and uses the | +//| specified IComparer. | +//+------------------------------------------------------------------+ +template +CSortedMap::CSortedMap(IComparer*comparer) + { +//--- check comaprer + if(CheckPointer(comparer)==POINTER_INVALID) + { + //--- use default comaprer + m_comparer=new CDefaultComparer(); + m_delete_comparer=true; + } + else + { + //--- use specified comaprer + m_comparer=comparer; + m_delete_comparer=false; + } + m_tree=new CRedBlackTree*>(new CKeyValuePairComparer(m_comparer)); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedMap class | +//| that contains elements copied from the specified | +//| IMap and uses the default comparer for the key type.| +//+------------------------------------------------------------------+ +template +CSortedMap::CSortedMap(IMap*map) + { +//--- use default comaprer + m_comparer=new CDefaultComparer(); + m_delete_comparer=true; + m_tree=new CRedBlackTree*>(map,new CKeyValuePairComparer(m_comparer)); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedMap class | +//| that contains elements copied from the specified | +//| IMap and uses the specified IComparer. | +//+------------------------------------------------------------------+ +template +CSortedMap::CSortedMap(IMap*map,IComparer*comparer) + { +//--- check comaprer + if(CheckPointer(comparer)==POINTER_INVALID) + { + //--- use default comaprer + m_comparer=new CDefaultComparer(); + m_delete_comparer=true; + } + else + { + //--- use specified comaprer + m_comparer=comparer; + m_delete_comparer=false; + } + m_tree=new CRedBlackTree*>(map,new CKeyValuePairComparer(m_comparer)); + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +template +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 +static void CSortedMap::ClearNodes(CRedBlackTreeNode*>*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 +bool CSortedMap::Add(TKey key,TValue value) + { +//--- create pair + CKeyValuePair*pair=new CKeyValuePair(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 +bool CSortedMap::Contains(TKey key,TValue value) + { +//--- find node with specified key + CKeyValuePairpair(key,NULL); + CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); +//--- create value comparer + CDefaultEqualityComparercomaprer; +//--- 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 +bool CSortedMap::ContainsKey(TKey key) + { +//--- crete pair + CKeyValuePairpair(key,NULL); +//--- determines whether the tree contains the pair. + return m_tree.Contains(GetPointer(pair)); + } +//+------------------------------------------------------------------+ +//| Determines whether the map contains the specified value. | +//+------------------------------------------------------------------+ +template +bool CSortedMap::ContainsValue(TValue value) + { +//--- copy all pairs in array + CKeyValuePair*array[]; + int count=m_tree.CopyTo(array); +//--- create value comparer + CDefaultEqualityComparercomaprer; +//--- determines whether the array contains the specified value + for(int i=0; i +int CSortedMap::CopyTo(CKeyValuePair*&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 +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*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 +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 +bool CSortedMap::Remove(TKey key) + { +//--- create pair with specified key + CKeyValuePairpair(key,NULL); +//--- find node + CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); +//--- check node + if(CheckPointer(node)!=POINTER_INVALID) + { + CKeyValuePair*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 +bool CSortedMap::TryGetValue(TKey key,TValue &value) + { +//--- create pair with specified key + CKeyValuePairpair(key,NULL); +//--- find node with specified pair in the tree + CRedBlackTreeNode*>*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 +bool CSortedMap::TrySetValue(TKey key,TValue value) + { +//--- create pair with specified key + CKeyValuePairpair(key,NULL); +//--- find node with specified pair in the tree + CRedBlackTreeNode*>*node=m_tree.Find(GetPointer(pair)); +//--- check node + if(CheckPointer(node)==POINTER_INVALID) + return(false); +//--- set value + node.Value().Value(value); + return(true); + } +//+------------------------------------------------------------------+ diff --git a/Generic/SortedSet.mqh b/Generic/SortedSet.mqh new file mode 100644 index 0000000..f4c027b --- /dev/null +++ b/Generic/SortedSet.mqh @@ -0,0 +1,673 @@ +//+------------------------------------------------------------------+ +//| SortedList.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include "RedBlackTree.mqh" +#include "HashSet.mqh" +//+------------------------------------------------------------------+ +//| Class CSortedSet. | +//| Usage: Represents a collection of objects that is maintained in | +//| sorted order. | +//+------------------------------------------------------------------+ +template +class CSortedSet: public ISet + { +protected: + CRedBlackTree*m_tree; + +public: + CSortedSet(void); + CSortedSet(IComparer*comparer); + CSortedSet(ICollection*collection); + CSortedSet(ICollection*collection,IComparer*comparer); + CSortedSet(T &array[]); + CSortedSet(T &array[],IComparer*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 *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*collection); + void ExceptWith(T &array[]); + void IntersectWith(ICollection*collection); + void IntersectWith(T &array[]); + void SymmetricExceptWith(ICollection*collection); + void SymmetricExceptWith(T &array[]); + void UnionWith(ICollection*collection); + void UnionWith(T &array[]); + //--- methods for determining the relationship between sets + bool IsProperSubsetOf(ICollection*collection); + bool IsProperSubsetOf(T &array[]); + bool IsProperSupersetOf(ICollection*collection); + bool IsProperSupersetOf(T &array[]); + bool IsSubsetOf(ICollection*collection); + bool IsSubsetOf(T &array[]); + bool IsSupersetOf(ICollection*collection); + bool IsSupersetOf(T &array[]); + bool Overlaps(ICollection*collection); + bool Overlaps(T &array[]); + bool SetEquals(ICollection*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 class that is | +//| empty and uses the default equality comparer for the set type. | +//+------------------------------------------------------------------+ +template +CSortedSet::CSortedSet(void) + { + m_tree=new CRedBlackTree(); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedSet class that is | +//| empty and uses the specified equality comparer for the set type. | +//+------------------------------------------------------------------+ +template +CSortedSet::CSortedSet(IComparer*comparer) + { + m_tree=new CRedBlackTree(comparer); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedSet 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 +CSortedSet::CSortedSet(ICollection*collection) + { + m_tree=new CRedBlackTree(collection); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedSet 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 +CSortedSet::CSortedSet(ICollection*collection,IComparer*comparer) + { + m_tree=new CRedBlackTree(collection,comparer); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedSet 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 +CSortedSet::CSortedSet(T &array[]) + { + m_tree=new CRedBlackTree(array); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CSortedSet 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 +CSortedSet::CSortedSet(T &array[],IComparer*comparer) + { + m_tree=new CRedBlackTree(array,comparer); + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +template +CSortedSet::~CSortedSet(void) + { + delete m_tree; + } +//+------------------------------------------------------------------+ +//| Copies a range of elements from the set to a compatible | +//| one-dimensional array. | +//+------------------------------------------------------------------+ +template +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 +void CSortedSet::ExceptWith(ICollection*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*comparer=Comparer(); + if(!m_tree.TryGetMax(max)) + return; + if(!m_tree.TryGetMin(min)) + return; +//--- remove elements + for(int i=0; i0) && Contains(item)) + m_tree.Remove(item); + } + } +//+------------------------------------------------------------------+ +//| Removes all elements in the specified array from the current set.| +//+------------------------------------------------------------------+ +template +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*comparer=Comparer(); + if(!m_tree.TryGetMax(max)) + return; + if(!m_tree.TryGetMin(min)) + return; +//--- remove elements + for(int i=0; i0) && 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 +void CSortedSet::IntersectWith(ICollection*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*tree=new CRedBlackTree(); +//--- store values conatin in tree and array + for(int i=0; i +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*tree=new CRedBlackTree(); +//--- store values conatin in tree and array + for(int i=0; i +void CSortedSet::SymmetricExceptWith(ICollection*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*comparer=m_tree.Comparer(); +//--- sort array + Introsortsort; + 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) + 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 +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*comparer=m_tree.Comparer(); +//--- sort array + Introsortsort; + 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) + 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 +void CSortedSet::UnionWith(ICollection*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 +void CSortedSet::UnionWith(T &array[]) + { +//--- get array size + int size=ArraySize(array); +//--- add all elemets from array to set + for(int i=0; i +bool CSortedSet::IsProperSubsetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return(ptr_set.IsProperSupersetOf(m_tree)); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return(set.IsProperSupersetOf(m_tree)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a proper subset of the specified | +//| array. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::IsProperSubsetOf(T &array[]) + { + if(m_tree.Count()==0) + return(ArraySize(array) > 0); +//--- create a set based on a specified array + CHashSetset(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 +bool CSortedSet::IsProperSupersetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return(ptr_set.IsProperSubsetOf(m_tree)); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return(set.IsProperSubsetOf(m_tree)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a proper superset of the specified | +//| array. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return(set.IsProperSubsetOf(m_tree)); + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a subset of the specified collection.| +//+------------------------------------------------------------------+ +template +bool CSortedSet::IsSubsetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)==POINTER_DYNAMIC) + { + return(ptr_set.IsProperSupersetOf(m_tree)); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return(set.IsProperSupersetOf(m_tree)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a subset of the specified array. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::IsSubsetOf(T &array[]) + { +//--- check tree count + if(m_tree.Count()==0) + return(true); +//--- create a set based on a specified array + CHashSetset(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 +bool CSortedSet::IsSupersetOf(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return(ptr_set.IsSupersetOf(m_tree)); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return(set.IsSupersetOf(m_tree)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether a set is a superset of the specified array. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::IsSupersetOf(T &array[]) + { +//--- check array size + if(ArraySize(array)==0) + return(true); +//--- create a set based on a specified array + CHashSetset(array); + return(set.IsSupersetOf(m_tree)); + } +//+------------------------------------------------------------------+ +//| Determines whether the current set and a specified collection | +//| share common elements. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::Overlaps(ICollection*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*ptr_set=dynamic_cast*>(collection); + if(CheckPointer(ptr_set)!=POINTER_INVALID) + { + return(ptr_set.Overlaps(m_tree)); + } + else + { + //--- create a set based on a specified collection + CHashSetset(collection); + return(set.Overlaps(m_tree)); + } + } +//+------------------------------------------------------------------+ +//| Determines whether the current set and a specified array share | +//| common elements. | +//+------------------------------------------------------------------+ +template +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 + CHashSetset(array); + return(set.Overlaps(m_tree)); + } +//+------------------------------------------------------------------+ +//| Determines whether a set and the specified collection contain the| +//| same elements. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::SetEquals(ICollection*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 +bool CSortedSet::SetEquals(T &array[]) + { +//--- try find all elements in the tree + for(int i=0; i to array. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::GetViewBetween(T &array[],T lower_value,T upper_value) + { +//--- get comparer + IComparer*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_lower0 && 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 in reverse order to array. | +//+------------------------------------------------------------------+ +template +bool CSortedSet::GetReverse(T &array[]) + { + int size=m_tree.CopyTo(array); + return ArrayReverse(array,0,size); + } +//+------------------------------------------------------------------+ diff --git a/Generic/Stack.mqh b/Generic/Stack.mqh new file mode 100644 index 0000000..e70f4ab --- /dev/null +++ b/Generic/Stack.mqh @@ -0,0 +1,227 @@ +//+------------------------------------------------------------------+ +//| Stack.mqh | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#include +#include +#include +//+------------------------------------------------------------------+ +//| Class CStack. | +//| Usage: Represents a variable size last-in-first-out (LIFO) | +//| collection of instances of the same specified type. | +//+------------------------------------------------------------------+ +template +class CStack: public ICollection + { +protected: + T m_array[]; + int m_size; + const int m_default_capacity; + +public: + CStack(void); + CStack(const int capacity); + CStack(ICollection&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 class that is empty | +//| and has the default initial capacity. | +//+------------------------------------------------------------------+ +template +CStack::CStack(void): m_default_capacity(4), + m_size(0) + { + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CStack class that is empty | +//| and has the specified initial capacity or the default initial | +//| capacity, whichever is greater. | +//+------------------------------------------------------------------+ +template +CStack::CStack(const int capacity): m_default_capacity(4), + m_size(0) + { + ArrayResize(m_array,capacity); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CStack class that contains | +//| elements copied from the specified array and has sufficient | +//| capacity to accommodate the number of elements copied. | +//+------------------------------------------------------------------+ +template +CStack::CStack(T &array[]): m_default_capacity(4), + m_size(0) + { + m_size=ArrayCopy(m_array,array); + } +//+------------------------------------------------------------------+ +//| Initializes a new instance of the CStack class that contains | +//| elements copied from the specified collection and has sufficient | +//| capacity to accommodate the number of elements copied. | +//+------------------------------------------------------------------+ +template +CStack::CStack(ICollection*collection): m_default_capacity(4), + m_size(0) + { +//--- check collection + if(CheckPointer(collection)!=POINTER_INVALID) + m_size=collection.CopyTo(m_array,0); + } +//+------------------------------------------------------------------+ +//| Destructor. | +//+------------------------------------------------------------------+ +template +CStack::~CStack(void) + { + } +//+------------------------------------------------------------------+ +//| Inserts an value at the top of the CStack. | +//+------------------------------------------------------------------+ +template +bool CStack::Add(T value) + { + return Push(value); + } +//+------------------------------------------------------------------+ +//| Gets the number of elements. | +//+------------------------------------------------------------------+ +template +int CStack::Count(void) + { + return(m_size); + } +//+------------------------------------------------------------------+ +//| Removes all values from the CStack. | +//+------------------------------------------------------------------+ +template +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 +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. | +//+------------------------------------------------------------------+ +template +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 +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. | +//+------------------------------------------------------------------+ +template +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 without removing. | +//+------------------------------------------------------------------+ +template +T CStack::Peek(void) + { +//--- return last value + return(m_array[m_size-1]); + } +//+------------------------------------------------------------------+ +//| Removes and returns the value at the top of the CStack. | +//+------------------------------------------------------------------+ +template +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, if that number is less than 90 percent of current | +//| capacity. | +//+------------------------------------------------------------------+ +template +void CStack::TrimExcess(void) + { +//--- calculate threshold value + int threshold=(int)(((double)ArraySize(m_array)*0.9)); +//--- calculate resize array + if(m_size \ + 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__ \ No newline at end of file diff --git a/fxsaber/SingleTesterCache/TesterPositionProfit.mqh b/fxsaber/SingleTesterCache/TesterPositionProfit.mqh new file mode 100644 index 0000000..8b75eba --- /dev/null +++ b/fxsaber/SingleTesterCache/TesterPositionProfit.mqh @@ -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 \ No newline at end of file diff --git a/fxsaber/SingleTesterCache/TesterTradeState.mqh b/fxsaber/SingleTesterCache/TesterTradeState.mqh new file mode 100644 index 0000000..72261a0 --- /dev/null +++ b/fxsaber/SingleTesterCache/TesterTradeState.mqh @@ -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 \ No newline at end of file diff --git a/fxsaber/SingleTesterCache/TradeDeal.mqh b/fxsaber/SingleTesterCache/TradeDeal.mqh new file mode 100644 index 0000000..3e76f0d Binary files /dev/null and b/fxsaber/SingleTesterCache/TradeDeal.mqh differ diff --git a/fxsaber/SingleTesterCache/TradeOrder.mqh b/fxsaber/SingleTesterCache/TradeOrder.mqh new file mode 100644 index 0000000..8115a99 --- /dev/null +++ b/fxsaber/SingleTesterCache/TradeOrder.mqh @@ -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 \ No newline at end of file diff --git a/fxsaber/TesterCache/ExpTradeSummary.mqh b/fxsaber/TesterCache/ExpTradeSummary.mqh new file mode 100644 index 0000000..12fc0db Binary files /dev/null and b/fxsaber/TesterCache/ExpTradeSummary.mqh differ diff --git a/fxsaber/TesterCache/Mathematics.mqh b/fxsaber/TesterCache/Mathematics.mqh new file mode 100644 index 0000000..9df7a5d Binary files /dev/null and b/fxsaber/TesterCache/Mathematics.mqh differ diff --git a/fxsaber/TesterCache/String.mqh b/fxsaber/TesterCache/String.mqh new file mode 100644 index 0000000..4eb9231 Binary files /dev/null and b/fxsaber/TesterCache/String.mqh differ diff --git a/fxsaber/TesterCache/TestCacheHeader.mqh b/fxsaber/TesterCache/TestCacheHeader.mqh new file mode 100644 index 0000000..00851e4 Binary files /dev/null and b/fxsaber/TesterCache/TestCacheHeader.mqh differ diff --git a/fxsaber/TesterCache/TestCacheInput.mqh b/fxsaber/TesterCache/TestCacheInput.mqh new file mode 100644 index 0000000..f21d1c8 Binary files /dev/null and b/fxsaber/TesterCache/TestCacheInput.mqh differ diff --git a/fxsaber/TesterCache/TestCacheRecord.mqh b/fxsaber/TesterCache/TestCacheRecord.mqh new file mode 100644 index 0000000..69de26b Binary files /dev/null and b/fxsaber/TesterCache/TestCacheRecord.mqh differ diff --git a/fxsaber/TesterCache/TestCacheSymbolRecord.mqh b/fxsaber/TesterCache/TestCacheSymbolRecord.mqh new file mode 100644 index 0000000..e33d73d Binary files /dev/null and b/fxsaber/TesterCache/TestCacheSymbolRecord.mqh differ diff --git a/fxsaber/TesterCache/TestInputRange.mqh b/fxsaber/TesterCache/TestInputRange.mqh new file mode 100644 index 0000000..95b8e00 Binary files /dev/null and b/fxsaber/TesterCache/TestInputRange.mqh differ diff --git a/fxsaber/TesterCache/TesterCache.mqh b/fxsaber/TesterCache/TesterCache.mqh new file mode 100644 index 0000000..d4a6b99 Binary files /dev/null and b/fxsaber/TesterCache/TesterCache.mqh differ