From a9340e5d4e4aec76cf3372f2bf7c3cfa4984e0fe Mon Sep 17 00:00:00 2001 From: amirghadiri1987 <144431373+amirghadiri1987@users.noreply.github.com> Date: Fri, 7 Feb 2025 19:08:31 +0330 Subject: [PATCH] Add files via upload --- Expert/Expert.mqh | Bin 0 -> 122604 bytes Expert/ExpertBase.mqh | 715 +++++++++++++ Expert/ExpertMoney.mqh | 124 +++ Expert/ExpertSignal.mqh | 464 +++++++++ Expert/ExpertTrade.mqh | 171 +++ Expert/ExpertTrailing.mqh | 33 + Expert/Money/MoneyFixedLot.mqh | 73 ++ Expert/Money/MoneyFixedMargin.mqh | 76 ++ Expert/Money/MoneyFixedRisk.mqh | 109 ++ Expert/Money/MoneyNone.mqh | 71 ++ Expert/Money/MoneySizeOptimized.mqh | 155 +++ Expert/Signal/SignalAC.mqh | 173 ++++ Expert/Signal/SignalAMA.mqh | 265 +++++ Expert/Signal/SignalAO.mqh | 339 ++++++ Expert/Signal/SignalBearsPower.mqh | 289 ++++++ Expert/Signal/SignalBullsPower.mqh | 289 ++++++ Expert/Signal/SignalCCI.mqh | 382 +++++++ Expert/Signal/SignalDEMA.mqh | 257 +++++ Expert/Signal/SignalDeMarker.mqh | 378 +++++++ Expert/Signal/SignalEnvelopes.mqh | 193 ++++ Expert/Signal/SignalFrAMA.mqh | 257 +++++ Expert/Signal/SignalITF.mqh | 91 ++ Expert/Signal/SignalMA.mqh | 261 +++++ Expert/Signal/SignalMACD.mqh | 408 ++++++++ Expert/Signal/SignalRSI.mqh | 400 +++++++ Expert/Signal/SignalRVI.mqh | 180 ++++ Expert/Signal/SignalSAR.mqh | 168 +++ Expert/Signal/SignalStoch.mqh | 426 ++++++++ Expert/Signal/SignalTEMA.mqh | 257 +++++ Expert/Signal/SignalTRIX.mqh | 395 +++++++ Expert/Signal/SignalWPR.mqh | 371 +++++++ Expert/Signal/mySignals/supertrendsignal.mqh | 278 +++++ Expert/Signal/signalcrossema.mqh | 246 +++++ Expert/Trailing/TrailingFixedPips.mqh | 132 +++ Expert/Trailing/TrailingMA.mqh | 157 +++ Expert/Trailing/TrailingNone.mqh | 40 + Expert/Trailing/TrailingParabolicSAR.mqh | 123 +++ Files/File.mqh | 292 ++++++ Files/FileBMP.mqh | 183 ++++ Files/FileBin.mqh | 517 ++++++++++ Files/FilePipe.mqh | 347 +++++++ Files/FileTxt.mqh | 64 ++ Generic/ArrayList.mqh | Bin 0 -> 50384 bytes Generic/HashMap.mqh | 622 +++++++++++ Generic/HashSet.mqh | 972 ++++++++++++++++++ Generic/Interfaces/ICollection.mqh | 24 + Generic/Interfaces/IComparable.mqh | 19 + Generic/Interfaces/IComparer.mqh | 17 + Generic/Interfaces/IEqualityComparable.mqh | 19 + Generic/Interfaces/IEqualityComparer.mqh | 19 + Generic/Interfaces/IList.mqh | 26 + Generic/Interfaces/IMap.mqh | 27 + Generic/Interfaces/ISet.mqh | 37 + Generic/Internal/ArrayFunction.mqh | 135 +++ Generic/Internal/CompareFunction.mqh | 209 ++++ Generic/Internal/DefaultComparer.mqh | 22 + Generic/Internal/DefaultEqualityComparer.mqh | 25 + Generic/Internal/EqualFunction.mqh | 26 + Generic/Internal/HashFunction.mqh | 176 ++++ Generic/Internal/Introsort.mqh | 244 +++++ Generic/Internal/PrimeGenerator.mqh | 81 ++ Generic/LinkedList.mqh | 563 ++++++++++ Generic/Queue.mqh | Bin 0 -> 29814 bytes Generic/RedBlackTree.mqh | Bin 0 -> 74814 bytes Generic/SortedMap.mqh | 341 ++++++ Generic/SortedSet.mqh | 673 ++++++++++++ Generic/Stack.mqh | 227 ++++ .../SingleTesterCache/ExpTradeSummaryExt.mqh | Bin 0 -> 10322 bytes .../ExpTradeSummarySingle.mqh | 201 ++++ .../SingleTestCacheHeader.mqh | Bin 0 -> 14926 bytes .../SingleTesterCache/SingleTesterCache.mqh | Bin 0 -> 34190 bytes fxsaber/SingleTesterCache/String.mqh | 50 + .../TesterPositionProfit.mqh | 44 + .../SingleTesterCache/TesterTradeState.mqh | 29 + fxsaber/SingleTesterCache/TradeDeal.mqh | Bin 0 -> 16914 bytes fxsaber/SingleTesterCache/TradeOrder.mqh | 237 +++++ fxsaber/TesterCache/ExpTradeSummary.mqh | Bin 0 -> 19408 bytes fxsaber/TesterCache/Mathematics.mqh | Bin 0 -> 896 bytes fxsaber/TesterCache/String.mqh | Bin 0 -> 2642 bytes fxsaber/TesterCache/TestCacheHeader.mqh | Bin 0 -> 16734 bytes fxsaber/TesterCache/TestCacheInput.mqh | Bin 0 -> 7076 bytes fxsaber/TesterCache/TestCacheRecord.mqh | Bin 0 -> 396 bytes fxsaber/TesterCache/TestCacheSymbolRecord.mqh | Bin 0 -> 1150 bytes fxsaber/TesterCache/TestInputRange.mqh | Bin 0 -> 530 bytes fxsaber/TesterCache/TesterCache.mqh | Bin 0 -> 20798 bytes 85 files changed, 15214 insertions(+) create mode 100644 Expert/Expert.mqh create mode 100644 Expert/ExpertBase.mqh create mode 100644 Expert/ExpertMoney.mqh create mode 100644 Expert/ExpertSignal.mqh create mode 100644 Expert/ExpertTrade.mqh create mode 100644 Expert/ExpertTrailing.mqh create mode 100644 Expert/Money/MoneyFixedLot.mqh create mode 100644 Expert/Money/MoneyFixedMargin.mqh create mode 100644 Expert/Money/MoneyFixedRisk.mqh create mode 100644 Expert/Money/MoneyNone.mqh create mode 100644 Expert/Money/MoneySizeOptimized.mqh create mode 100644 Expert/Signal/SignalAC.mqh create mode 100644 Expert/Signal/SignalAMA.mqh create mode 100644 Expert/Signal/SignalAO.mqh create mode 100644 Expert/Signal/SignalBearsPower.mqh create mode 100644 Expert/Signal/SignalBullsPower.mqh create mode 100644 Expert/Signal/SignalCCI.mqh create mode 100644 Expert/Signal/SignalDEMA.mqh create mode 100644 Expert/Signal/SignalDeMarker.mqh create mode 100644 Expert/Signal/SignalEnvelopes.mqh create mode 100644 Expert/Signal/SignalFrAMA.mqh create mode 100644 Expert/Signal/SignalITF.mqh create mode 100644 Expert/Signal/SignalMA.mqh create mode 100644 Expert/Signal/SignalMACD.mqh create mode 100644 Expert/Signal/SignalRSI.mqh create mode 100644 Expert/Signal/SignalRVI.mqh create mode 100644 Expert/Signal/SignalSAR.mqh create mode 100644 Expert/Signal/SignalStoch.mqh create mode 100644 Expert/Signal/SignalTEMA.mqh create mode 100644 Expert/Signal/SignalTRIX.mqh create mode 100644 Expert/Signal/SignalWPR.mqh create mode 100644 Expert/Signal/mySignals/supertrendsignal.mqh create mode 100644 Expert/Signal/signalcrossema.mqh create mode 100644 Expert/Trailing/TrailingFixedPips.mqh create mode 100644 Expert/Trailing/TrailingMA.mqh create mode 100644 Expert/Trailing/TrailingNone.mqh create mode 100644 Expert/Trailing/TrailingParabolicSAR.mqh create mode 100644 Files/File.mqh create mode 100644 Files/FileBMP.mqh create mode 100644 Files/FileBin.mqh create mode 100644 Files/FilePipe.mqh create mode 100644 Files/FileTxt.mqh create mode 100644 Generic/ArrayList.mqh create mode 100644 Generic/HashMap.mqh create mode 100644 Generic/HashSet.mqh create mode 100644 Generic/Interfaces/ICollection.mqh create mode 100644 Generic/Interfaces/IComparable.mqh create mode 100644 Generic/Interfaces/IComparer.mqh create mode 100644 Generic/Interfaces/IEqualityComparable.mqh create mode 100644 Generic/Interfaces/IEqualityComparer.mqh create mode 100644 Generic/Interfaces/IList.mqh create mode 100644 Generic/Interfaces/IMap.mqh create mode 100644 Generic/Interfaces/ISet.mqh create mode 100644 Generic/Internal/ArrayFunction.mqh create mode 100644 Generic/Internal/CompareFunction.mqh create mode 100644 Generic/Internal/DefaultComparer.mqh create mode 100644 Generic/Internal/DefaultEqualityComparer.mqh create mode 100644 Generic/Internal/EqualFunction.mqh create mode 100644 Generic/Internal/HashFunction.mqh create mode 100644 Generic/Internal/Introsort.mqh create mode 100644 Generic/Internal/PrimeGenerator.mqh create mode 100644 Generic/LinkedList.mqh create mode 100644 Generic/Queue.mqh create mode 100644 Generic/RedBlackTree.mqh create mode 100644 Generic/SortedMap.mqh create mode 100644 Generic/SortedSet.mqh create mode 100644 Generic/Stack.mqh create mode 100644 fxsaber/SingleTesterCache/ExpTradeSummaryExt.mqh create mode 100644 fxsaber/SingleTesterCache/ExpTradeSummarySingle.mqh create mode 100644 fxsaber/SingleTesterCache/SingleTestCacheHeader.mqh create mode 100644 fxsaber/SingleTesterCache/SingleTesterCache.mqh create mode 100644 fxsaber/SingleTesterCache/String.mqh create mode 100644 fxsaber/SingleTesterCache/TesterPositionProfit.mqh create mode 100644 fxsaber/SingleTesterCache/TesterTradeState.mqh create mode 100644 fxsaber/SingleTesterCache/TradeDeal.mqh create mode 100644 fxsaber/SingleTesterCache/TradeOrder.mqh create mode 100644 fxsaber/TesterCache/ExpTradeSummary.mqh create mode 100644 fxsaber/TesterCache/Mathematics.mqh create mode 100644 fxsaber/TesterCache/String.mqh create mode 100644 fxsaber/TesterCache/TestCacheHeader.mqh create mode 100644 fxsaber/TesterCache/TestCacheInput.mqh create mode 100644 fxsaber/TesterCache/TestCacheRecord.mqh create mode 100644 fxsaber/TesterCache/TestCacheSymbolRecord.mqh create mode 100644 fxsaber/TesterCache/TestInputRange.mqh create mode 100644 fxsaber/TesterCache/TesterCache.mqh diff --git a/Expert/Expert.mqh b/Expert/Expert.mqh new file mode 100644 index 0000000000000000000000000000000000000000..487938910d37edec5642754fc576aad4858f7df3 GIT binary patch literal 122604 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 +#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 0000000000000000000000000000000000000000..d90522928cb3d64101d3baec14ce810bcad67b73 GIT binary patch literal 50384 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 xRXa@ysO!H@BHH_ +#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 0000000000000000000000000000000000000000..3cd1d6e58d257a033ce28c7ed7a522bd09779267 GIT binary patch literal 29814 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 BEe-$x literal 0 HcmV?d00001 diff --git a/Generic/RedBlackTree.mqh b/Generic/RedBlackTree.mqh new file mode 100644 index 0000000000000000000000000000000000000000..8335b5a31ea04919bd0bad040ff6fd61648dbff4 GIT binary patch literal 74814 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 ZN7||D^*$n|x#*jYJ4Rvn1M8_z{~t7*Y0v-w literal 0 HcmV?d00001 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_sizeP-KG3NO$!!Ppp#0fTL5+G$c|3Vos-#(XoygxXHhw8>v@d(ORH zBw4a7*&;BR9i+AP>+Jp7yC?bY-+8%~TRD{*c`IjfF22mkp8O?uawt9N=(hv3bx}I_ z@<9%C#3e?Y%L{z{Q?4-PYxzq5=5@q{_Tg;5%8&9h=JGKIR~jVtvOcS_f_`UMXMni} z=-jK(O@$FW}#BDM<+Ly&heAf!(D1F^^ zS&n2`YV!L~F6@5>O`1(HA|;ngSOM*3V@!K|6#btbzT;KB6>kgAD!jLXXT#gXlTo4O zy+o}Ee{N`N6FuqCi~~+%dC=Wqk3Co>Eq9QLbyjq~lri-K;Xrj;;uq{tY{4B%zOIvsGsaRh8m8H2IUa4&AoYGF!Pc8eTn{+$ODF zgiLPKCn%Gw{%fe{m9M>Blp1WjHneiYIegzip{MR^3(sht)bw&nu%QxUkBatd!pCbU zd3>6v8HJg35jpXvYt+e-ImH$t2`#UMT1j(_hW7&yENkxIO9L%+;BP4AEwnHnSw`Ot z9o@v!dga?$kk7>sQ!3a)9?hD6_Hgp?M7hAbi)Wg@2K$fN9d*V% zuR_~x)NLNhgn1HehMBhI)RbhFvm^;!ryz8krzmu`SIVw#n2&(LG!o6Piit{&-aiMN12i&itg@;4(yH*WFz^Jb|FXJFs>Bi zGGrN-99uuuG0^GpAXi=BYxMLBSNATOYc(4iIr~hvvE^K(OP`4X< zStG=zX3uT)tQ}-y%)c$8CR?|LI`0pG$IXhg13qj#(h@Rz-Z!2C)(&{Kq-0=4T<_}m;@{TsbSis*P4P*8v ztyI1rIesmkCX~jD2)7yM5t9)(xrOnPV~q2*@9^y!5g;2Y8|6x~|I3GQp`)uCQ|hor zBNKncHRO0l$Fau8jDAV>to*#==)7s@qFhfJ)>+X_;)AlFcFbNH&geYJsIxPBc{J|O z%_`IE=!%eOnEA^lS0~d+ykk@o{1x|-@aoy*Hfi-DWD@2b^T@>A>Wk+cv&b@ucT7j` zWcir9W0svodB^lU*?hJ$>f>|pj#>7Q#LkgB9KV}j53_NH)1o66Pz1VUP9aZZ4P@td zEaMJ~MHl4`vq;UM>7>XhI?t>+Et+qNqT{c4jCQ*``NDT;tlC59GT8$jN0+wChtTCy z*(L8Rlh}gM$YFk2ELSkuwZ*v^;|5#zmFaQ7m literal 0 HcmV?d00001 diff --git a/fxsaber/SingleTesterCache/ExpTradeSummarySingle.mqh b/fxsaber/SingleTesterCache/ExpTradeSummarySingle.mqh new file mode 100644 index 0000000..7f896d9 --- /dev/null +++ b/fxsaber/SingleTesterCache/ExpTradeSummarySingle.mqh @@ -0,0 +1,201 @@ +#include "String.mqh" + +//+------------------------------------------------------------------+ +//| Структура для статистики торговли | +//+------------------------------------------------------------------+ +struct ExpTradeSummarySingle +{ +public: + int Offset1[10]; + int bars; + int ticks; + STRING32 symbol; + double initial_deposit; // начальный депозит + double withdrawal; // снято средств + double profit; // общая прибыль (+) + double grossprofit; // общий плюс + double grossloss; // общий минус + double maxprofit; // максимально прибыльная сделка + double minprofit; // максимально убыточная сделка + double conprofitmax; // прибыль максимальной последовательности прибыльных сделок + double maxconprofit; // максимальная прибыль среди последовательностей + double conlossmax; // убыток максимальной последовательности убыточных сделок + double maxconloss; // максимальный убыток среди последовательностей + double balance_min; // минимальное значение баланса (для расчёта абсолютной просадки) + double maxdrawdown; // максимальная просадка по балансу + double drawdownpercent; // отношение максимальной просадки по балансу к её пику + double reldrawdown; // максимальная относительная просадка по балансу в деньгах + double reldrawdownpercent; // максимальная относительная просадка по балансу в процентах + double equity_min; // минимальное значение equity (для расчёта абсолютной просадки по equity) + double maxdrawdown_e; // максимальная просадка по equity + double drawdownpercent_e; // отношение максимальной просадки по equity к её пику (+) + double reldrawdown_e; // максимальная относительная просадка по equity в деньгах + double reldrawdownpercnt_e; // максимальная относительная просадка по equity в процентах + double expected_payoff; // матожидание выигрыша (+) + double profit_factor; // показатель прибыльности (+) + double recovery_factor; // фактор восстановления (+) + double sharpe_ratio; // коэффициент Шарпа (+) + double margin_level; // минимальный уровень маржи + double custom_fitness; // пользовательский фитнесс - результат OnTester (+) + int deals; // общее количество сделок + int trades; // количество сделок out/inout + int profittrades; // количество прибыльных + int losstrades; // количество убыточных + int shorttrades; // количество шортов + int longtrades; // количество лонгов + int winshorttrades; // количество прибыльных шортов + int winlongtrades; // количество прибыльных лонгов + int conprofitmax_trades; // максимальная последовательность прибыльных сделок + int maxconprofit_trades; // последовательность максимальной прибыли + int conlossmax_trades; // максимальная последовательность убыточных сделок + int maxconloss_trades; // последовательность максимального убытка + int avgconwinners; // среднее количество последовательных прибыльных сделок + int avgconloosers; // среднее количество последовательных убыточных сделок + +#define TOSTRING(A) #A + " = " + (string)(A) + "\n" +#define TOSTRING3(A) #A + " = " + this.A[] + "\n" + + string ToString( void ) const + { + return( + TOSTRING(bars) + + TOSTRING(ticks) + + TOSTRING3(symbol) + + TOSTRING(initial_deposit) + // начальный депозит + TOSTRING(withdrawal) + // снято средств + TOSTRING(profit) + // общая прибыль (+) + TOSTRING(grossprofit) + // общий плюс + TOSTRING(grossloss) + // общий минус + TOSTRING(maxprofit) + // максимально прибыльная сделка + TOSTRING(minprofit) + // максимально убыточная сделка + TOSTRING(conprofitmax) + // прибыль максимальной последовательности прибыльных сделок + TOSTRING(maxconprofit) + // максимальная прибыль среди последовательностей + TOSTRING(conlossmax) + // убыток максимальной последовательности убыточных сделок + TOSTRING(maxconloss) + // максимальный убыток среди последовательностей + TOSTRING(balance_min) + // минимальное значение баланса (для расчёта абсолютной просадки) + TOSTRING(maxdrawdown) + // максимальная просадка по балансу + TOSTRING(drawdownpercent) + // отношение максимальной просадки по балансу к её пику + TOSTRING(reldrawdown) + // максимальная относительная просадка по балансу в деньгах + TOSTRING(reldrawdownpercent) + // максимальная относительная просадка по балансу в процентах + TOSTRING(equity_min) + // минимальное значение equity (для расчёта абсолютной просадки по equity) + TOSTRING(maxdrawdown_e) + // максимальная просадка по equity + TOSTRING(drawdownpercent_e) + // отношение максимальной просадки по equity к её пику (+) + TOSTRING(reldrawdown_e) + // максимальная относительная просадка по equity в деньгах + TOSTRING(reldrawdownpercnt_e) + // максимальная относительная просадка по equity в процентах + TOSTRING(expected_payoff) + // матожидание выигрыша (+) + TOSTRING(profit_factor) + // показатель прибыльности (+) + TOSTRING(recovery_factor) + // фактор восстановления (+) + TOSTRING(sharpe_ratio) + // коэффициент Шарпа (+) + TOSTRING(margin_level) + // минимальный уровень маржи + TOSTRING(custom_fitness) + // пользовательский фитнесс - результат OnTester (+) + TOSTRING(deals) + // общее количество сделок + TOSTRING(trades) + // количество сделок out/inout + TOSTRING(profittrades) + // количество прибыльных + TOSTRING(losstrades) + // количество убыточных + TOSTRING(shorttrades) + // количество шортов + TOSTRING(longtrades) + // количество лонгов + TOSTRING(winshorttrades) + // количество прибыльных шортов + TOSTRING(winlongtrades) + // количество прибыльных лонгов + TOSTRING(conprofitmax_trades) + // максимальная последовательность прибыльных сделок + TOSTRING(maxconprofit_trades) + // последовательность максимальной прибыли + TOSTRING(conlossmax_trades) + // максимальная последовательность убыточных сделок + TOSTRING(maxconloss_trades) + // последовательность максимального убытка + TOSTRING(avgconwinners) + // среднее количество последовательных прибыльных сделок + TOSTRING(avgconloosers) // среднее количество последовательных убыточных сделок + ); + } + +#undef TOSTRING3 +#undef TOSTRING + + double TesterStatistics( const ENUM_STATISTICS Statistic_ID ) const + { + switch (Statistic_ID) + { + case STAT_INITIAL_DEPOSIT: + return(this.initial_deposit); + case STAT_WITHDRAWAL: + return(this.withdrawal); + case STAT_PROFIT: + return(this.profit); + case STAT_GROSS_PROFIT: + return(this.grossprofit); + case STAT_GROSS_LOSS: + return(-this.grossloss); + case STAT_MAX_PROFITTRADE: + return(this.maxprofit); + case STAT_MAX_LOSSTRADE: + return(-this.minprofit); + case STAT_CONPROFITMAX: + return(this.maxconprofit); + case STAT_CONPROFITMAX_TRADES: + return(this.maxconprofit_trades); + case STAT_MAX_CONWINS: + return(this.conprofitmax); + case STAT_MAX_CONPROFIT_TRADES: + return(this.conprofitmax_trades); + case STAT_CONLOSSMAX: + return(-this.conlossmax); + case STAT_CONLOSSMAX_TRADES: + return(this.conlossmax_trades); + case STAT_MAX_CONLOSSES: + return(-this.maxconloss); + case STAT_MAX_CONLOSS_TRADES: + return(this.maxconloss_trades); + case STAT_BALANCEMIN: + return(this.balance_min); + case STAT_BALANCE_DD: + return(this.maxdrawdown); + case STAT_BALANCEDD_PERCENT: + return(this.drawdownpercent); + case STAT_BALANCE_DDREL_PERCENT: + return(this.reldrawdownpercent); + case STAT_BALANCE_DD_RELATIVE: + return(this.reldrawdown); + case STAT_EQUITYMIN: + return(this.equity_min); + case STAT_EQUITY_DD: + return(this.maxdrawdown_e); + case STAT_EQUITYDD_PERCENT: + return(this.drawdownpercent_e); + case STAT_EQUITY_DDREL_PERCENT: + return(this.reldrawdownpercnt_e); + case STAT_EQUITY_DD_RELATIVE: + return(this.reldrawdown_e); + case STAT_EXPECTED_PAYOFF: + return(this.expected_payoff); + case STAT_PROFIT_FACTOR: + return(this.profit_factor); + case STAT_RECOVERY_FACTOR: + return(this.recovery_factor); + case STAT_SHARPE_RATIO: + return(this.sharpe_ratio); + case STAT_MIN_MARGINLEVEL: + return(this.margin_level); + case STAT_CUSTOM_ONTESTER: + return(this.custom_fitness); + case STAT_DEALS: + return(this.deals); + case STAT_TRADES: + return(this.trades); + case STAT_PROFIT_TRADES: + return(this.profittrades); + case STAT_LOSS_TRADES: + return(this.losstrades); + case STAT_SHORT_TRADES: + return(this.shorttrades); + case STAT_LONG_TRADES: + return(this.longtrades); + case STAT_PROFIT_SHORTTRADES: + return(this.winshorttrades); + case STAT_PROFIT_LONGTRADES: + return(this.winlongtrades); + case STAT_PROFITTRADES_AVGCON: + return(this.avgconwinners); + case STAT_LOSSTRADES_AVGCON: + return(this.avgconloosers); + } + + return(0); + } +}; \ No newline at end of file diff --git a/fxsaber/SingleTesterCache/SingleTestCacheHeader.mqh b/fxsaber/SingleTesterCache/SingleTestCacheHeader.mqh new file mode 100644 index 0000000000000000000000000000000000000000..9984dc134c064dfb934403d3be26b059a3d22a30 GIT binary patch literal 14926 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 Cd-3G} literal 0 HcmV?d00001 diff --git a/fxsaber/SingleTesterCache/String.mqh b/fxsaber/SingleTesterCache/String.mqh new file mode 100644 index 0000000..e1f50be --- /dev/null +++ b/fxsaber/SingleTesterCache/String.mqh @@ -0,0 +1,50 @@ +#ifndef __STRING__ + +#define __STRING__ + +#define NULL_CHAR (short)0xFFFF + +#define DEFINE_STRING(A) \ + struct STRING##A \ + { \ + public : \ + short Array[A]; \ + \ + public: \ + void operator =( const string &Str ) \ + { \ + ::ArrayInitialize(Array, 0); \ + this.Array[0] = NULL_CHAR; \ + ::StringToShortArray(Str, this.Array); \ + \ + return; \ + } \ + \ + template \ + 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 0000000000000000000000000000000000000000..3e76f0d130cd645e1ff140cf421a73f920aea6b6 GIT binary patch literal 16914 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 DCZA4$ literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/Mathematics.mqh b/fxsaber/TesterCache/Mathematics.mqh new file mode 100644 index 0000000000000000000000000000000000000000..9df7a5d80fc31bc50210b17df0dcada3dadb74c4 GIT binary patch literal 896 zcmaJ9!A3N_38B`i0ZkxHyh#7LI`g(kKM7&8U$gJc z%zJ;o3zR5OVaD0v9z(>q!)Ub%ag8S&;|M?Ycf@=mM}~K<9x%m%-=*CNrTbUjS9l?A z&fSb_<;d}c1aC;W&UoYB315GG^mp)X2k&r7M8x;8MJV|%cv9G|Vn%5QaDraLs7pR` zi=(WLFC!|7@rV#(+!8$`+M&zY@ufqDW3ZaF4~&07=2G2jUU=*?Pdkk_-c65GuAI5# zuRjSG?VD#QIXTNZ<1VxKwR>xy<%^V+bg&>QIKaKGfE0+&zPdL5d*tA2r(8=@(Pg%5 z<=K8bv8IiX2*zXhL5gE6LEMs!j{fIrI+*ceWK1|(NYkxaj5PN>WWwBn; F`+pbmhQ|N^ literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/String.mqh b/fxsaber/TesterCache/String.mqh new file mode 100644 index 0000000000000000000000000000000000000000..4eb92311731042a65c31413fab55580737805f4d GIT binary patch literal 2642 zcmcguYfAz_6g{7V{=T-aH$7KVbA~sO^*0=`TblLjj{Rg?RM@2@?}|TZRSXpX literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/TestCacheHeader.mqh b/fxsaber/TesterCache/TestCacheHeader.mqh new file mode 100644 index 0000000000000000000000000000000000000000..00851e43d94db58beb2aeffc9d11bcb2eb7bded8 GIT binary patch literal 16734 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 literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/TestCacheInput.mqh b/fxsaber/TesterCache/TestCacheInput.mqh new file mode 100644 index 0000000000000000000000000000000000000000..f21d1c84ea9a7dae88ef60aa6a342595a6910329 GIT binary patch literal 7076 zcmd5>ZEq7t5T4JK`X5e-RM{jXKq)QZMS>(0OKDQYPG1Dba%?9=^-JnILsQ6KZ~Htu z9`Ek?%$-XkA8>k>2V zxF_$0myR3AclgzXh9TZffMMI+(VlI&D-YzJ{2+In1!@J~oH+|=aZ7%epJiX#awIQs zHSxQJ=ifsw#}~;ouF-nW6W|WKhF5PC~wkUiqRzAPhDqN8D#LIPmT&Ts7+(=f!rA4^EW)ugFM$l%n*8m zvQ>~|vn;bJ5}z4<6JBJl=Brg^?*ZdEJ{eeD4T1V0bMa5$X=a8~w=NQ7iZkF~2J1rS z5Plip{?hrni>K*4vQ<1oZD)|-x?2TX3TzjUBnLPTJwvu8z&Uj~xrz<#V)Rx+nPLty zp&CN6LOp15hQlx};z{J4^W@aou-u}2+)rTpANY*13P-?a?>WEb-~^fZHawg;24}K~ ztgZKbL~RqbN$<#dlb%A?g{vwFsu3@HxXb`day*U(0*n3FR1i?QSrM$!9Z z-L2EG(>TH?pKojOOo(nB-->Y!-%s%2H!;^Df7WrY5`4ENui*>r%x=c>vDagdo9&z_ zzSe+3Yj=#@p1zVdkO&d;Zn?e|`moqbR!KCHt4LbDUR^TG+N(>4d3AMZ%UflV%Q;xg z>Sdk_*{)1q$4VQ`*vmWbB(ozw-tN6zoY_+3Fx&ev?qiqL>%IdE8eY%Sj0;KYd)Z`>fB`32liz)`d0f*h1OoSaU~U|4t-F*?3K! z!Utni@>qY7#$9;{-yN4~GzOGwJV6Ai>GUx!*V=^6Bj9Y6B4y9YeRfvC`V;WJs@^H0 zQC;({ixUx-#fmG3XA6@Gc=bG@Oe4FpYSvfNHwDA1Y1{*sTJBt>0Y>hZ+TH`l*{$k6 zuwTIg2k(zOiiTS)QPdl9xR&-)CMMXWz`e?ZW))r8WQBxu5kRVZJwQVP&A^=6uch48K^f z{7k0X^x1bG%3!Ox+n2zObz~^bmI2aBWPpB>f$~=#bP$I9X-1Oo|=UE6#-|}^PF&&`n(@u z&DVZO&kMO5<}><`ST!ot!o4@&r8Bm2t{P4rcyi?P1W{0ur%1Gv9^m|4C*?7xh?sRg z%g%UWdzYQs5eNSrptsGpJdp@JXTJ8UagnEC+1qu8#z}Wr`&b2Rp!TJ`sqB)?6$Pb-m z6LiY)?A{0QO6;N2wQA6YH`oz81=l{$CyV|onkSz}_E4GFTkYkr7ke)5s~I=E5f-cEItEc0=Cr1Z14h>C~rgywOKSAHu3>yd_j`f(6FB z)v2=tnnf_eo|>H7^*>Bnhg}Mt8|XG;*Yqck&XivNC*RkL_IdMKv$|fQ#-j!24 A{r~^~ literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/TestCacheSymbolRecord.mqh b/fxsaber/TesterCache/TestCacheSymbolRecord.mqh new file mode 100644 index 0000000000000000000000000000000000000000..e33d73d2e4d9eed13a9e6bbdab6d06d8c477b118 GIT binary patch literal 1150 zcmd6n%SyvQ6o&t`;5!7nX(?9FUB!inh#Q5byDHMV0h`n|_1eC=`kfPdHR!@k8OY3> zoH>^-|K#(dph&UWdeB52bron&p;C?9-d9BfJ?b9ou6C5?eXbV`Rp&(0BZNd6Fq&9i zH_ls(14dc}r_6CZ)eRl+1DljW)XIqLw9t+8VUdu;FqY4r z!<2OA+4K0WeuIXNbf{Y$dld5ysko*~UFpK#-^7Pr&(bMW3EMj}Y7P&GlpXoIA zQ&y)%$hghBGcBi(AK_K}gL+lfoQ#&m>d)(Wm3WE%m$YZjy+G#J{{?o3enzmGXPo*1 D*xZ)p literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/TestInputRange.mqh b/fxsaber/TesterCache/TestInputRange.mqh new file mode 100644 index 0000000000000000000000000000000000000000..95b8e0095dddef2a55bec5d33ac7be0b694ca63d GIT binary patch literal 530 zcmaKoL2JTL5QOI}^glezCDNZ@EA&*nRIoYrA~pu0MoFVkiho`G<|Ud#M8eCyH#@sK zv*%N-TpR85qlJ7AdLjOS4sRG>W|M(A) z8T3hhL3OQh56`LZquU$mZi&9>yV9Bo)|qKW&y1N=iaXtn|jRf)<%5YK9A8=!t}D;VZXaoAE~(jpl3{_ literal 0 HcmV?d00001 diff --git a/fxsaber/TesterCache/TesterCache.mqh b/fxsaber/TesterCache/TesterCache.mqh new file mode 100644 index 0000000000000000000000000000000000000000..d4a6b994357625097f2b151df429215a2f51eb0c GIT binary patch literal 20798 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 literal 0 HcmV?d00001