Watch how to download trading robots for free
Find us on Telegram!
Join our fan page
Interesting script?
So post a link to it -
let others appraise it
You liked the script? Try it in the MetaTrader 5 terminal
Libraries

ATR Based Stop Loss Manager - library for MetaTrader 5

Emmanuel Nana Nana
Published by:
Muharrem Rogova
Views:
91
Rating:
(1)
Published:
MQL5 Freelance Need a robot or indicator based on this code? Order it on Freelance Go to Freelance
screen//+------------------------------------------------------------------+
//|                                              StopLossManager.mqh |
//|                                        Copyright 2026, Algosphere |
//|                                      https://algosphere-quant.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Algosphere"
#property link      "https://algosphere-quant.com"
#property version   "1.00"
#property strict

//+------------------------------------------------------------------+
//| Enumeration of stop loss calculation methods                     |
//+------------------------------------------------------------------+
enum ENUM_SL_METHOD
  {
   SL_METHOD_FIXED_PIPS=0,    // Fixed Pips
   SL_METHOD_ATR=1,           // ATR Based
   SL_METHOD_SWING=2,         // Swing High/Low
   SL_METHOD_PERCENT=3        // Percentage of Price
  };

//+------------------------------------------------------------------+
//| Enumeration of trailing stop methods                             |
//+------------------------------------------------------------------+
enum ENUM_TRAIL_METHOD
  {
   TRAIL_NONE=0,              // No Trailing
   TRAIL_FIXED=1,             // Fixed Distance
   TRAIL_ATR=2,               // ATR Based
   TRAIL_STEP=3,              // Step Trailing
   TRAIL_BREAKEVEN=4          // Breakeven Only
  };

//+------------------------------------------------------------------+
//| Structure for stop loss calculation result                       |
//+------------------------------------------------------------------+
struct SStopLossResult
  {
   double            price;            // Stop loss price level
   double            distance_points;  // Distance in points
   double            distance_pips;    // Distance in pips
   bool              valid;            // Calculation valid flag
   string            error;            // Error message if invalid
  };

//+------------------------------------------------------------------+
//| Class for managing stop loss calculations and trailing           |
//+------------------------------------------------------------------+
class CStopLossManager
  {
private:
   string            m_symbol;         // Trading symbol
   ENUM_TIMEFRAMES   m_timeframe;      // Calculation timeframe
   int               m_atr_handle;     // ATR indicator handle
   int               m_atr_period;     // ATR period
   double            m_point;          // Symbol point size
   double            m_pip_size;       // Pip size in points
   int               m_digits;         // Symbol digits
   int               m_stops_level;    // Broker minimum stops level
   bool              m_initialized;    // Initialization flag

   //--- Private methods
   double            GetATRValue(const int shift=0);
   double            GetSwingHigh(const int lookback);
   double            GetSwingLow(const int lookback);
   double            NormalizePrice(const double price);
   double            AdjustForStopsLevel(const double sl_price,
                                         const double entry_price,
                                         const bool is_buy);

public:
   //--- Constructor and destructor
                     CStopLossManager(void);
                    ~CStopLossManager(void);

   //--- Initialization
   bool              Init(const string symbol,
                          const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT,
                          const int atr_period=14);

   //--- Stop loss calculation methods
   SStopLossResult   CalculateStopLoss(const ENUM_SL_METHOD method,
                                       const bool is_buy,
                                       const double entry_price,
                                       const double param1=0.0,
                                       const double param2=0.0);

   SStopLossResult   CalculateFixedPipsSL(const bool is_buy,
                                          const double entry_price,
                                          const double pips);

   SStopLossResult   CalculateATRSL(const bool is_buy,
                                    const double entry_price,
                                    const double atr_multiplier=1.5);

   SStopLossResult   CalculateSwingSL(const bool is_buy,
                                      const double entry_price,
                                      const int lookback=10,
                                      const double buffer_pips=5.0);

   SStopLossResult   CalculatePercentSL(const bool is_buy,
                                        const double entry_price,
                                        const double percent=1.0);

   //--- Take profit calculation
   double            CalculateTakeProfit(const bool is_buy,
                                         const double entry_price,
                                         const double sl_price,
                                         const double rr_ratio=2.0);

   //--- Trailing stop methods
   double            CalculateTrailingStop(const ENUM_TRAIL_METHOD method,
                                           const bool is_buy,
                                           const double entry_price,
                                           const double current_sl,
                                           const double current_price,
                                           const double param1=0.0,
                                           const double param2=0.0);

   double            TrailFixed(const bool is_buy,
                                const double current_sl,
                                const double current_price,
                                const double trail_distance_pips);

   double            TrailATR(const bool is_buy,
                              const double current_sl,
                              const double current_price,
                              const double atr_multiplier=2.0);

   double            TrailStep(const bool is_buy,
                               const double entry_price,
                               const double current_sl,
                               const double current_price,
                               const double step_pips=10.0);

   double            TrailBreakeven(const bool is_buy,
                                    const double entry_price,
                                    const double current_sl,
                                    const double current_price,
                                    const double trigger_pips=20.0,
                                    const double be_offset_pips=2.0);

   //--- Utility methods
   double            PipsToPoints(const double pips);
   double            PointsToPips(const double points);
   double            PipsToPrice(const double pips);

   //--- Information methods
   double            GetCurrentATR(void)     { return(GetATRValue(0)); }
   int               GetStopsLevel(void)     { return(m_stops_level); }
   double            GetPipSize(void)        { return(m_pip_size); }
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CStopLossManager::CStopLossManager(void) : m_symbol(""),
                                           m_timeframe(PERIOD_CURRENT),
                                           m_atr_handle(INVALID_HANDLE),
                                           m_atr_period(14),
                                           m_point(0),
                                           m_pip_size(0),
                                           m_digits(0),
                                           m_stops_level(0),
                                           m_initialized(false)
  {
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CStopLossManager::~CStopLossManager(void)
  {
//--- Release indicator handle
   if(m_atr_handle!=INVALID_HANDLE)
      IndicatorRelease(m_atr_handle);
  }

//+------------------------------------------------------------------+
//| Initialize the stop loss manager                                 |
//+------------------------------------------------------------------+
bool CStopLossManager::Init(const string symbol,
                            const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT,
                            const int atr_period=14)
  {
   m_symbol=symbol;
   m_timeframe=(timeframe==PERIOD_CURRENT) ? Period() : timeframe;
   m_atr_period=atr_period;

//--- Get symbol specifications
   m_point=SymbolInfoDouble(symbol,SYMBOL_POINT);
   m_digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
   m_stops_level=(int)SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL);

//--- Calculate pip size (10 points for 5-digit, 1 point for 4-digit)
   m_pip_size=(m_digits==5 || m_digits==3) ? m_point*10 : m_point;

//--- Validate symbol data
   if(m_point==0)
     {
      Print("Error: Invalid symbol point value for ",symbol);
      return(false);
     }

//--- Create ATR indicator handle
   m_atr_handle=iATR(symbol,m_timeframe,m_atr_period);
   if(m_atr_handle==INVALID_HANDLE)
     {
      Print("Error: Failed to create ATR indicator handle");
      return(false);
     }

   m_initialized=true;
   return(true);
  }

//+------------------------------------------------------------------+
//| Get ATR indicator value                                          |
//+------------------------------------------------------------------+
double CStopLossManager::GetATRValue(const int shift=0)
  {
   if(m_atr_handle==INVALID_HANDLE)
      return(0.0);

   double atr_buffer[1];
   if(CopyBuffer(m_atr_handle,0,shift,1,atr_buffer)!=1)
      return(0.0);

   return(atr_buffer[0]);
  }

//+------------------------------------------------------------------+
//| Get swing high price                                             |
//+------------------------------------------------------------------+
double CStopLossManager::GetSwingHigh(const int lookback)
  {
   double high_buffer[];
   ArraySetAsSeries(high_buffer,true);

   if(CopyHigh(m_symbol,m_timeframe,0,lookback,high_buffer)!=lookback)
      return(0.0);

   double highest=high_buffer[0];
   for(int i=1; i<lookback; i++)
     {
      if(high_buffer[i]>highest)
         highest=high_buffer[i];
     }

   return(highest);
  }

//+------------------------------------------------------------------+
//| Get swing low price                                              |
//+------------------------------------------------------------------+
double CStopLossManager::GetSwingLow(const int lookback)
  {
   double low_buffer[];
   ArraySetAsSeries(low_buffer,true);

   if(CopyLow(m_symbol,m_timeframe,0,lookback,low_buffer)!=lookback)
      return(0.0);

   double lowest=low_buffer[0];
   for(int i=1; i<lookback; i++)
     {
      if(low_buffer[i]<lowest)
         lowest=low_buffer[i];
     }

   return(lowest);
  }

//+------------------------------------------------------------------+
//| Normalize price to symbol digits                                 |
//+------------------------------------------------------------------+
double CStopLossManager::NormalizePrice(const double price)
  {
   return(NormalizeDouble(price,m_digits));
  }

//+------------------------------------------------------------------+
//| Adjust stop loss for broker minimum stops level                  |
//+------------------------------------------------------------------+
double CStopLossManager::AdjustForStopsLevel(const double sl_price,
                                             const double entry_price,
                                             const bool is_buy)
  {
   if(m_stops_level==0)
      return(sl_price);

   double min_distance=m_stops_level*m_point;
   double current_distance=MathAbs(entry_price-sl_price);

   if(current_distance>=min_distance)
      return(sl_price);

//--- Adjust stop loss to meet minimum distance
   if(is_buy)
      return(NormalizePrice(entry_price-min_distance));
   else
      return(NormalizePrice(entry_price+min_distance));
  }

//+------------------------------------------------------------------+
//| Universal stop loss calculation method                           |
//+------------------------------------------------------------------+
SStopLossResult CStopLossManager::CalculateStopLoss(const ENUM_SL_METHOD method,
                                                    const bool is_buy,
                                                    const double entry_price,
                                                    const double param1=0.0,
                                                    const double param2=0.0)
  {
   SStopLossResult result;
   ZeroMemory(result);

   if(!m_initialized)
     {
      result.valid=false;
      result.error="Stop loss manager not initialized";
      return(result);
     }

   switch(method)
     {
      case SL_METHOD_FIXED_PIPS:
         result=CalculateFixedPipsSL(is_buy,entry_price,param1);
         break;
      case SL_METHOD_ATR:
         result=CalculateATRSL(is_buy,entry_price,param1>0 ? param1 : 1.5);
         break;
      case SL_METHOD_SWING:
         result=CalculateSwingSL(is_buy,entry_price,(int)(param1>0 ? param1 : 10),param2>0 ? param2 : 5.0);
         break;
      case SL_METHOD_PERCENT:
         result=CalculatePercentSL(is_buy,entry_price,param1>0 ? param1 : 1.0);
         break;
     }

   return(result);
  }

//+------------------------------------------------------------------+
//| Calculate fixed pips stop loss                                   |
//+------------------------------------------------------------------+
SStopLossResult CStopLossManager::CalculateFixedPipsSL(const bool is_buy,
                                                       const double entry_price,
                                                       const double pips)
  {
   SStopLossResult result;
   ZeroMemory(result);

   if(pips<=0)
     {
      result.valid=false;
      result.error="Invalid pips value";
      return(result);
     }

   double distance=pips*m_pip_size;

   if(is_buy)
      result.price=NormalizePrice(entry_price-distance);
   else
      result.price=NormalizePrice(entry_price+distance);

//--- Adjust for stops level
   result.price=AdjustForStopsLevel(result.price,entry_price,is_buy);

//--- Calculate final distances
   result.distance_points=MathAbs(entry_price-result.price)/m_point;
   result.distance_pips=result.distance_points/(m_pip_size/m_point);
   result.valid=true;

   return(result);
  }

//+------------------------------------------------------------------+
//| Calculate ATR-based stop loss                                    |
//+------------------------------------------------------------------+
SStopLossResult CStopLossManager::CalculateATRSL(const bool is_buy,
                                                 const double entry_price,
                                                 const double atr_multiplier=1.5)
  {
   SStopLossResult result;
   ZeroMemory(result);

   double atr=GetATRValue(0);
   if(atr==0)
     {
      result.valid=false;
      result.error="Failed to get ATR value";
      return(result);
     }

   double distance=atr*atr_multiplier;

   if(is_buy)
      result.price=NormalizePrice(entry_price-distance);
   else
      result.price=NormalizePrice(entry_price+distance);

//--- Adjust for stops level
   result.price=AdjustForStopsLevel(result.price,entry_price,is_buy);

//--- Calculate final distances
   result.distance_points=MathAbs(entry_price-result.price)/m_point;
   result.distance_pips=result.distance_points/(m_pip_size/m_point);
   result.valid=true;

   return(result);
  }

//+------------------------------------------------------------------+
//| Calculate swing-based stop loss                                  |
//+------------------------------------------------------------------+
SStopLossResult CStopLossManager::CalculateSwingSL(const bool is_buy,
                                                   const double entry_price,
                                                   const int lookback=10,
                                                   const double buffer_pips=5.0)
  {
   SStopLossResult result;
   ZeroMemory(result);

   double buffer=buffer_pips*m_pip_size;

   if(is_buy)
     {
      double swing_low=GetSwingLow(lookback);
      if(swing_low==0)
        {
         result.valid=false;
         result.error="Failed to find swing low";
         return(result);
        }
      result.price=NormalizePrice(swing_low-buffer);
     }
   else
     {
      double swing_high=GetSwingHigh(lookback);
      if(swing_high==0)
        {
         result.valid=false;
         result.error="Failed to find swing high";
         return(result);
        }
      result.price=NormalizePrice(swing_high+buffer);
     }

//--- Adjust for stops level
   result.price=AdjustForStopsLevel(result.price,entry_price,is_buy);

//--- Calculate final distances
   result.distance_points=MathAbs(entry_price-result.price)/m_point;
   result.distance_pips=result.distance_points/(m_pip_size/m_point);
   result.valid=true;

   return(result);
  }

//+------------------------------------------------------------------+
//| Calculate percentage-based stop loss                             |
//+------------------------------------------------------------------+
SStopLossResult CStopLossManager::CalculatePercentSL(const bool is_buy,
                                                     const double entry_price,
                                                     const double percent=1.0)
  {
   SStopLossResult result;
   ZeroMemory(result);

   if(percent<=0 || percent>100)
     {
      result.valid=false;
      result.error="Invalid percentage value";
      return(result);
     }

   double distance=entry_price*(percent/100.0);

   if(is_buy)
      result.price=NormalizePrice(entry_price-distance);
   else
      result.price=NormalizePrice(entry_price+distance);

//--- Adjust for stops level
   result.price=AdjustForStopsLevel(result.price,entry_price,is_buy);

//--- Calculate final distances
   result.distance_points=MathAbs(entry_price-result.price)/m_point;
   result.distance_pips=result.distance_points/(m_pip_size/m_point);
   result.valid=true;

   return(result);
  }

//+------------------------------------------------------------------+
//| Calculate take profit based on risk:reward ratio                 |
//+------------------------------------------------------------------+
double CStopLossManager::CalculateTakeProfit(const bool is_buy,
                                             const double entry_price,
                                             const double sl_price,
                                             const double rr_ratio=2.0)
  {
   double sl_distance=MathAbs(entry_price-sl_price);
   double tp_distance=sl_distance*rr_ratio;

   if(is_buy)
      return(NormalizePrice(entry_price+tp_distance));
   else
      return(NormalizePrice(entry_price-tp_distance));
  }

//+------------------------------------------------------------------+
//| Universal trailing stop calculation                              |
//+------------------------------------------------------------------+
double CStopLossManager::CalculateTrailingStop(const ENUM_TRAIL_METHOD method,
                                               const bool is_buy,
                                               const double entry_price,
                                               const double current_sl,
                                               const double current_price,
                                               const double param1=0.0,
                                               const double param2=0.0)
  {
   if(!m_initialized)
      return(current_sl);

   switch(method)
     {
      case TRAIL_NONE:
         return(current_sl);
      case TRAIL_FIXED:
         return(TrailFixed(is_buy,current_sl,current_price,param1>0 ? param1 : 20.0));
      case TRAIL_ATR:
         return(TrailATR(is_buy,current_sl,current_price,param1>0 ? param1 : 2.0));
      case TRAIL_STEP:
         return(TrailStep(is_buy,entry_price,current_sl,current_price,param1>0 ? param1 : 10.0));
      case TRAIL_BREAKEVEN:
         return(TrailBreakeven(is_buy,entry_price,current_sl,current_price,
                               param1>0 ? param1 : 20.0,param2>0 ? param2 : 2.0));
     }

   return(current_sl);
  }

//+------------------------------------------------------------------+
//| Fixed distance trailing stop                                     |
//+------------------------------------------------------------------+
double CStopLossManager::TrailFixed(const bool is_buy,
                                    const double current_sl,
                                    const double current_price,
                                    const double trail_distance_pips)
  {
   double distance=trail_distance_pips*m_pip_size;
   double new_sl;

   if(is_buy)
     {
      new_sl=NormalizePrice(current_price-distance);
      if(new_sl>current_sl)
         return(new_sl);
     }
   else
     {
      new_sl=NormalizePrice(current_price+distance);
      if(new_sl<current_sl || current_sl==0)
         return(new_sl);
     }

   return(current_sl);
  }

//+------------------------------------------------------------------+
//| ATR-based trailing stop                                          |
//+------------------------------------------------------------------+
double CStopLossManager::TrailATR(const bool is_buy,
                                  const double current_sl,
                                  const double current_price,
                                  const double atr_multiplier=2.0)
  {
   double atr=GetATRValue(0);
   if(atr==0)
      return(current_sl);

   double distance=atr*atr_multiplier;
   double new_sl;

   if(is_buy)
     {
      new_sl=NormalizePrice(current_price-distance);
      if(new_sl>current_sl)
         return(new_sl);
     }
   else
     {
      new_sl=NormalizePrice(current_price+distance);
      if(new_sl<current_sl || current_sl==0)
         return(new_sl);
     }

   return(current_sl);
  }

//+------------------------------------------------------------------+
//| Step trailing stop                                               |
//+------------------------------------------------------------------+
double CStopLossManager::TrailStep(const bool is_buy,
                                   const double entry_price,
                                   const double current_sl,
                                   const double current_price,
                                   const double step_pips=10.0)
  {
   double step=step_pips*m_pip_size;
   double profit_distance;
   int steps_in_profit;

   if(is_buy)
     {
      profit_distance=current_price-entry_price;
      if(profit_distance<=0)
         return(current_sl);

      steps_in_profit=(int)MathFloor(profit_distance/step);
      if(steps_in_profit>0)
        {
         double new_sl=NormalizePrice(entry_price+(steps_in_profit-1)*step);
         if(new_sl>current_sl)
            return(new_sl);
        }
     }
   else
     {
      profit_distance=entry_price-current_price;
      if(profit_distance<=0)
         return(current_sl);

      steps_in_profit=(int)MathFloor(profit_distance/step);
      if(steps_in_profit>0)
        {
         double new_sl=NormalizePrice(entry_price-(steps_in_profit-1)*step);
         if(new_sl<current_sl || current_sl==0)
            return(new_sl);
        }
     }

   return(current_sl);
  }

//+------------------------------------------------------------------+
//| Breakeven trailing stop                                          |
//+------------------------------------------------------------------+
double CStopLossManager::TrailBreakeven(const bool is_buy,
                                        const double entry_price,
                                        const double current_sl,
                                        const double current_price,
                                        const double trigger_pips=20.0,
                                        const double be_offset_pips=2.0)
  {
   double trigger=trigger_pips*m_pip_size;
   double offset=be_offset_pips*m_pip_size;

   if(is_buy)
     {
      //--- Check if price has moved enough to trigger breakeven
      if(current_price-entry_price>=trigger)
        {
         double be_level=NormalizePrice(entry_price+offset);
         if(be_level>current_sl)
            return(be_level);
        }
     }
   else
     {
      //--- Check if price has moved enough to trigger breakeven
      if(entry_price-current_price>=trigger)
        {
         double be_level=NormalizePrice(entry_price-offset);
         if(be_level<current_sl || current_sl==0)
            return(be_level);
        }
     }

   return(current_sl);
  }

//+------------------------------------------------------------------+
//| Convert pips to points                                           |
//+------------------------------------------------------------------+
double CStopLossManager::PipsToPoints(const double pips)
  {
   return(pips*(m_pip_size/m_point));
  }

//+------------------------------------------------------------------+
//| Convert points to pips                                           |
//+------------------------------------------------------------------+
double CStopLossManager::PointsToPips(const double points)
  {
   if(m_pip_size==0)
      return(0);
   return(points/(m_pip_size/m_point));
  }

//+------------------------------------------------------------------+
//| Convert pips to price distance                                   |
//+------------------------------------------------------------------+
double CStopLossManager::PipsToPrice(const double pips)
  {
   return(pips*m_pip_size);
  }
//+------------------------------------------------------------------+
KSQ CommandCenter Remote Google Sheets Trade Manager KSQ CommandCenter Remote Google Sheets Trade Manager

KSQ Command Centre is a production-ready, two-way bridge between MetaTrader 5 and Google Sheets. It was originally designed to help fund managers and quantitative traders remotely monitor and manage large, funded accounts (e.g., Darwinex Zero, Prop Firms, PAM, MAM) directly from a mobile browser, without needing to log in to a VPS. This Expert Advisor not only exports data—it actively listens for commands typed into your Google Sheet and executes them in MT5 in near real-time.

ASQ Command Desk ASQ Command Desk

ASQ CommandDesk is a professional order management panel for manual traders on MetaTrader 5. You make the trading decisions — CommandDesk handles execution, risk control, and exit management automatically.

Hon APS Advanced Pattern Scanner with DOM and  News Integration Hon APS Advanced Pattern Scanner with DOM and News Integration

Hon-APS (Advanced Pattern Scanner) is a sophisticated, open-source Expert Advisor for MT5. Unlike typical retail bots relying on lagging indicators, Hon-APS trades structural breakouts backed by quantitative Order Flow algorithms. It actively scans for classical chart patterns (e.g., Head & Shoulders, Bottoms, Triangles) and validates entries using L2 Order Book absorption and bid/ask imbalances. Complete with a polished on-chart UI, true Kelly Criterion risk management, and a robust macroeconomic news scraper, it's designed for prop-firm viability and high-end capital preservation.

MACD Signals MACD Signals

Indicator edition for new platform.