//+------------------------------------------------------------------+ //| CTrailingATR.mqh | //| AnimateDread | //| https://tawarriors.com| //+------------------------------------------------------------------+ #property copyright "AnimateDread" #include // wizard description start //+----------------------------------------------------------------------+ //| Description of the class | //| Title=Trailing Stop based on ATR Indicator | //| Type=Trailing | //| Name=ATR | //| Class=CTrailingATR | //| Page= | //| Parameter=Multiplier,double,2, ATR Multiplier | //| Parameter=Periods,int,14, ATR Periods | //| Parameter=Shift,int,0, ATR Shift | //+----------------------------------------------------------------------+ // wizard description end //+------------------------------------------------------------------+ //| Class CTrailingATR. | //| Purpose: Class of trailing stops based on ATR * Multiplier. | //| Derives from class CExpertTrailing. | //+------------------------------------------------------------------+ class CTrailingATR : public CExpertTrailing { protected: CiATR m_ATR; // ATR indicator //--- input parameters double m_multiplier; // Configurable multiple for ATR int m_periods; // Configurable periods for ATR int m_shift; // Configurable shift for ATR public: CTrailingATR(void); ~CTrailingATR(void); //--- methods of initialization of protected data void Multiplier(double multiplier) { m_multiplier = multiplier; } void Periods(int periods) { m_periods = periods; } void Shift(int shift) { m_shift = shift; } virtual bool InitIndicators(CIndicators* indicators); virtual bool ValidationSettings(); virtual bool CheckTrailingStopLong(CPositionInfo* position, double& sl, double& tp); virtual bool CheckTrailingStopShort(CPositionInfo* position, double& sl, double& tp); protected: bool AdjustStopLoss(double& sl, double currentPrice, double atrValue, bool isLong); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ void CTrailingATR::CTrailingATR(void) : m_multiplier(2), m_periods(14), m_shift(0) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ void CTrailingATR::~CTrailingATR(void) { } //+------------------------------------------------------------------+ //| Validation settings protected data. | //+------------------------------------------------------------------+ bool CTrailingATR::ValidationSettings() { if(!CExpertTrailing::ValidationSettings()) return (false); // Check multiplier if(m_multiplier <= 0.0 || m_multiplier > 100) { printf(__FUNCTION__ + ": multiplier must be greater than 0 and lesser than 100"); return (false); } // Check ATR Periods if(m_periods <= 0 || m_periods > 200) { printf(__FUNCTION__ + ": ATR Periods must be greater than 0 and lesser than 200"); return (false); } // Check ATR shift if(m_shift < 0 || m_shift > 200) { printf(__FUNCTION__ + ": ATR shift must be 0-200"); return (false); } //--- ok return (true); } //+------------------------------------------------------------------+ //| Checking for input parameters and setting protected data. | //+------------------------------------------------------------------+ bool CTrailingATR::InitIndicators(CIndicators* indicators) { if(indicators == NULL) return (false); // Add ATR indicator to the collection if(!indicators.Add(GetPointer(m_ATR))) { printf(__FUNCTION__ + ": error adding object"); return (false); } // Initialize ATR indicator if(!m_ATR.Create(m_symbol.Name(), m_period, m_periods)) { return (false); } //--- ok return (true); } //+------------------------------------------------------------------+ //| Common logic for adjusting SL considering freeze level | //+------------------------------------------------------------------+ bool CTrailingATR::AdjustStopLoss(double& sl, double currentPrice, double atrValue, bool isLong) { double freezeLevel = m_symbol.FreezeLevel() * m_symbol.Point(); int digits = m_symbol.Digits(); // Get the number of digits after the decimal for the instrument // Calculate new SL based on position type (Long or Short) double new_sl = isLong ? NormalizeDouble(currentPrice - atrValue * m_multiplier, digits) : NormalizeDouble(currentPrice + atrValue * m_multiplier, digits); // Calculate the level beyond which SL cannot be set due to freeze level double level = isLong ? currentPrice - freezeLevel : currentPrice + freezeLevel; // Check if new SL is in the correct direction and respects the freeze level bool isSlValid = isLong ? (new_sl > sl && new_sl < level) : (new_sl < sl && new_sl > level); if(isSlValid) { sl = new_sl; return true; } return false; } //+------------------------------------------------------------------+ //| Checking trailing stop and/or profit for long position. | //+------------------------------------------------------------------+ bool CTrailingATR::CheckTrailingStopLong(CPositionInfo* position, double& sl, double& tp) { if(position == NULL) return false; double atr = m_ATR.Main(m_shift); // Get the current value of ATR double new_sl = position.StopLoss(); sl = EMPTY_VALUE; tp = EMPTY_VALUE; // Adjust SL considering freeze level and ensure it respects the freeze level if(AdjustStopLoss(new_sl, m_symbol.Bid(), atr, true)) { sl = new_sl; // Update the reference only if AdjustStopLoss returns true return true; } return false; } //+------------------------------------------------------------------+ //| Checking trailing stop and/or profit for short position. | //+------------------------------------------------------------------+ bool CTrailingATR::CheckTrailingStopShort(CPositionInfo* position, double& sl, double& tp) { if(position == NULL) return false; double atr = m_ATR.Main(m_shift); // Get the current value of ATR double new_sl = position.StopLoss(); sl = EMPTY_VALUE; tp = EMPTY_VALUE; // Adjust SL considering freeze level and ensure it respects the freeze level if(AdjustStopLoss(new_sl, m_symbol.Ask(), atr, false)) { sl = new_sl; // Update the reference only if AdjustStopLoss returns true return true; } return false; } //+------------------------------------------------------------------+