Author: Max Berilo
ModiSimple

This script is designed as a sophisticated technical analysis tool for the MetaTrader platform. It combines momentum oscillators, trend-following logic, and dynamic risk management to provide visual cues on a price chart.

Core Logic Overview

The indicator functions by processing three primary layers of data: Trend Analysis, Momentum Filtering, and Dynamic Trailing Stops.

1. Multi-Layered Signal Filtering

The script evaluates market conditions using two major technical indicators: the RSI (Relative Strength Index) and the MACD (Moving Average Convergence Divergence). It doesn't just look at these in isolation; it offers a highly customizable "logic gate" system to determine whether a trend is valid:

  • Momentum Analysis: The script can monitor RSI levels, direction, historical highs/lows, and even the speed of momentum (acceleration).
  • Trend Confirmation: It uses the MACD to identify long-term trends, checking for signal line intersections, histogram movements, and price direction.
  • Combined Logic: By enabling various "Use" switches, a user can require multiple conditions to be met simultaneously—for example, requiring the market to show both an RSI upward acceleration and a positive MACD trend before highlighting a potential move.

2. Dynamic Price Body Tracking

When the specific buy or sell conditions defined above are met, the script identifies the "body" of the price candle. It captures the high and low extremes of these candles to establish a baseline for where the current price action is moving. This provides a visual representation of the "active zone" of the market.

3. Intelligent Trailing Stop System

One of the most complex parts of this script is its Trailing Stop logic. Instead of using a fixed profit target, it calculates a "moving floor" (for long positions) or a "moving ceiling" (for short positions) that adjusts in real-time based on market volatility:

  • Volatility Adaptation: It utilizes the ATR (Average True Range) to measure how much the market is currently swinging. This ensures the trailing stop stays wide enough during volatile periods and tightens during calm periods.
  • Customizable Calculation Methods: The script offers six different mathematical ways to anchor this trailing stop, ranging from simple moving averages and closing prices to complex weighted median calculations (such as specialized median formulas).
  • Protection Mechanisms: It includes logic to ensure the stop loss only moves in your favor (it won't move backward) and can be capped at a maximum distance to prevent it from becoming too wide during extreme market outliers.

Summary of User Experience

For a visitor watching the chart, this script acts as a comprehensive "trend-following" assistant. It filters out "noise" by requiring complex agreement between RSI and MACD indicators before highlighting a move. Once a move is confirmed, it automatically calculates and draws a dynamic safety line (the Trailing Stop) that follows the price action, attempting to lock in profits while protecting against sudden reversals.

Indicators Used
Indicator of the average true rangeMoving average indicatorRelative strength indexMACD HistogramMoving average indicator
Miscellaneous
Implements a curve of type %1
9 Views
0 Downloads
0 Favorites
ModiSimple
#property copyright "Max Berilo"
//----
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1 Red
#property indicator_color2 LimeGreen
#property indicator_color3 Black
#property indicator_color4 Red
#property indicator_color5 Green
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 0
#property indicator_width4 1
#property indicator_width5 1
//---- input parameters
extern bool ShowBody     = True;
extern bool UseRSI       = True;
extern bool UseRSIaccel  = True;
extern bool UseRSIvalue  = False;
extern bool UseRSIdir    = True;
extern bool UseRSIhist   = True;
extern bool UseRSIisect  = True;
extern bool UseRSIsign   = False;
extern int  RSIperiod    = 14;
extern int  RSIfast      = 12;
extern int  RSIslow      = 26;
extern int  RSIsignal    = 9;
extern int  RSIbuyThreshold  = 40;
extern int  RSIsellThreshold = 60;
extern bool UseMACD      = True;
extern bool UseMACDaccel = True;
extern bool UseMACDvalue = False;
extern bool UseMACDdir   = True;
extern bool UseMACDhist  = False;
extern bool UseMACDisect = False;
extern bool UseMACDsign  = False;
extern int  FastMA       = 12;
extern int  SlowMA       = 26;
extern int  SignalMA     =  9;
//----
extern bool   ShowTrail   = True;
extern string TrlComment  = "SATL-1,FATL-2,EMA(HLC/3)-3,(HLC/3)-4,EMA(C)-5,C-6";
extern int    TrlMethod   = 5;
extern int    TrlPeriod   = 5;
extern double TrlInitMul  = 1.0;
extern double TrlMul      = 2.0;
extern int    TrlAtrPer   = 21;
extern int    TrlTrap     = 0;
extern bool   TrlUseMax   = False;
extern int    TrlMaxTrap  = 45;
//---- buffers
double ExtMap1[];
double ExtMap2[];
double TrlBegin[];
double TrlStopDn[];
double TrlStopUp[];
double RSI[];
double RSImacd[];
double MACD[];
//---- defines
int nFATL = 39;
int nSATL = 65;
//---- static parameters
double Spread;
static int nDrawBegin;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//----
    IndicatorBuffers(8);
    SetIndexStyle(0, DRAW_HISTOGRAM, EMPTY, 2);
    SetIndexStyle(1, DRAW_HISTOGRAM, EMPTY, 2);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_LINE);
    SetIndexStyle(4, DRAW_LINE);
    SetIndexArrow(2, 159);
    SetIndexBuffer(0, ExtMap1);
    SetIndexBuffer(1, ExtMap2);
    SetIndexBuffer(2, TrlBegin);
    SetIndexBuffer(3, TrlStopDn);
    SetIndexBuffer(4, TrlStopUp);
    SetIndexBuffer(5, RSI);
    SetIndexBuffer(6, RSImacd);
    SetIndexBuffer(7, MACD);
//----
    nDrawBegin = TrlPeriod + TrlAtrPer;
    if(TrlMethod == 1) {
      nDrawBegin += nSATL;
    }
    SetIndexDrawBegin(2, nDrawBegin);
    SetIndexDrawBegin(3, nDrawBegin);
    SetIndexDrawBegin(4, nDrawBegin);
//---- labels
    string short_name = "Simple";
    SetIndexLabel(0, short_name);
    SetIndexLabel(1, short_name);
    SetIndexLabel(2, "TrlBegin");
    SetIndexLabel(3, "TrlStopDn");
    SetIndexLabel(4, "TrlStopUp");
//----
    return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator function                                        |
//+------------------------------------------------------------------+
double CalcTrailStop(int shift, bool uptrend, bool initial)
  {
    double res, atr, sl = TrlTrap;
    if(!initial) {
      shift++;
    }
    atr = iATR(NULL, 0, TrlAtrPer, shift) / Point;
    if(initial) {
      sl  += TrlInitMul * atr;
    } else {
      sl  += TrlMul * atr;
    }
    if(TrlUseMax && sl > TrlMaxTrap) {
      sl = TrlMaxTrap;
    }
    switch(TrlMethod) {
      case 1:
        res = CalcSATLonMedian(shift);
        break;
      case 2:
        res = CalcFATLonMedian(shift);
        break;
      case 3:
        res = iMA(NULL, 0, TrlPeriod, 0, MODE_EMA, PRICE_TYPICAL, shift);
        break;
      case 4:
        res = (High[shift] + Low[shift] + Close[shift]) / 3.0;
        break;
      case 5:
        res = iMA(NULL, 0, TrlPeriod, 0, MODE_EMA, PRICE_CLOSE, shift);
        break;
      case 6:
      default:
        res = Close[shift];
        break;
    }
    if(uptrend) {
      res -= sl * Point;
    } else {
      res += (sl + Spread) * Point;
    }
    res = NormalizeDouble(res, Digits);
    return(res);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
    int    limit, shift, counted_bars = IndicatorCounted();
    double val1, val2, ma, signal, prevsign, atr;
    bool   buy, sell, bRSIbuy, bRSIsell, bMACDbuy, bMACDsell;
//----
    double StopLoss;
    bool   TrlLong, TrlPrevLong, TrlShort, TrlPrevShort;
//----
    Spread = MarketInfo(Symbol(), MODE_SPREAD);
    if(!ShowTrail) {
      SetIndexDrawBegin(2, Bars);
      SetIndexDrawBegin(3, Bars);
      SetIndexDrawBegin(4, Bars);
    }
//---- last counted bar will be recounted
    if(Bars <= RSIperiod) return(0);
    if(counted_bars > 0) {
      counted_bars--;
    } else {
      ArrayInitialize(TrlBegin,  EMPTY_VALUE);
      ArrayInitialize(TrlStopDn, EMPTY_VALUE);
      ArrayInitialize(TrlStopUp, EMPTY_VALUE);
    }
    limit = Bars - counted_bars - 1;
//----
    for(shift = limit; shift >= 0; shift--) {
      if(UseRSI) {
        RSI[shift] = iRSI(NULL, 0, RSIperiod, PRICE_CLOSE, shift);
      } else {
        RSI[shift] = 0;
      }
      if(UseMACD) {
        MACD[shift] = iMACD(NULL, 0, FastMA, SlowMA, SignalMA, PRICE_CLOSE, MODE_MAIN, shift);
      } else {
        MACD[shift] = 0;
      }
    }
//----
    for(shift = limit; UseRSI && (shift >= 0); shift--) {
      if(shift < Bars - (RSIperiod + RSIslow)) {
        RSImacd[shift] = iMAOnArray(RSI,0,RSIfast,0,MODE_EMA,shift)-iMAOnArray(RSI,0,RSIslow,0,MODE_EMA,shift);
      } else {
        RSImacd[shift] = 0;
      }
    }
//----
    for(shift = limit; shift >= 0; shift--) {
      val1 = EMPTY_VALUE; val2 = EMPTY_VALUE;
      if(UseRSI) {
        bRSIbuy  = False; bRSIsell = False;
        if(shift < Bars - (RSIperiod+RSIslow+2)) {
          if(UseRSIaccel) {
            prevsign = iMAOnArray(RSImacd,0,RSIsignal,0,MODE_EMA,shift+1);
            signal   = iMAOnArray(RSImacd,0,RSIsignal,0,MODE_EMA,shift);
            bRSIbuy  = (RSImacd[shift] - signal) > (RSImacd[shift+1] - prevsign);
            bRSIsell = (RSImacd[shift] - signal) < (RSImacd[shift+1] - prevsign);
          }
          if(UseRSIvalue) {
            buy  = RSI[shift] > RSIbuyThreshold;
            sell = RSI[shift] < RSIsellThreshold;
            if(UseRSIaccel) {
              bRSIbuy  = bRSIbuy  && buy;
              bRSIsell = bRSIsell && sell;
            } else {
              bRSIbuy  = buy;
              bRSIsell = sell;
            }
          }
          if(UseRSIdir) {
            buy  = (RSImacd[shift] > RSImacd[shift+1]);
            sell = (RSImacd[shift] < RSImacd[shift+1]);
            if(UseRSIaccel || UseRSIvalue) {
              bRSIbuy  = bRSIbuy  && buy;
              bRSIsell = bRSIsell && sell;
            } else {
              bRSIbuy  = buy;
              bRSIsell = sell;
            }
          }
          if(UseRSIhist) {
            buy  = RSImacd[shift] > RSImacd[shift+2];
            sell = RSImacd[shift] < RSImacd[shift+2];
            if(UseRSIaccel || UseRSIvalue || UseRSIdir) {
              bRSIbuy  = bRSIbuy  && buy;
              bRSIsell = bRSIsell && sell;
            } else {
              bRSIbuy  = buy;
              bRSIsell = sell;
            }
          }
          if(UseRSIisect) {
            if(!UseRSIaccel) {
              signal = iMAOnArray(RSImacd,0,RSIsignal,0,MODE_EMA,shift);
            }
            buy  = RSImacd[shift] > signal;
            sell = RSImacd[shift] < signal;
            if(UseRSIaccel || UseRSIvalue || UseRSIdir || UseRSIhist) {
              bRSIbuy  = bRSIbuy  && buy;
              bRSIsell = bRSIsell && sell;
            } else {
              bRSIbuy  = buy;
              bRSIsell = sell;
            }
          }
          if(UseRSIsign) {
            bRSIbuy  = bRSIbuy  && (RSImacd[shift] >= 0);
            bRSIsell = bRSIsell && (RSImacd[shift] <= 0);
            if(UseRSIaccel || UseRSIvalue || UseRSIdir || UseRSIhist || UseRSIisect) {
              bRSIbuy  = bRSIbuy  && buy;
              bRSIsell = bRSIsell && sell;
            } else {
              bRSIbuy  = buy;
              bRSIsell = sell;
            }
          }
        }
      }
      if(UseMACD) {
        bMACDbuy  = False; bMACDsell = False;
        if(shift <= Bars - (SlowMA+2)) {
          if(UseMACDaccel) {
            prevsign  = iMAOnArray(MACD,0,SignalMA,0,MODE_EMA,shift+1);
            signal    = iMAOnArray(MACD,0,SignalMA,0,MODE_EMA,shift);
            bMACDbuy  = (MACD[shift] - signal) > (MACD[shift+1] - prevsign);
            bMACDsell = (MACD[shift] - signal) < (MACD[shift+1] - prevsign);
          }
          if(UseMACDvalue) {
            atr = iATR(NULL, 0, 21, shift);
            buy  = MACD[shift] > -atr;
            sell = MACD[shift] <  atr;
            if(UseMACDaccel) {
              bMACDbuy  = bMACDbuy  && buy;
              bMACDsell = bMACDsell && sell;
            } else {
              bMACDbuy  = buy;
              bMACDsell = sell;
            }
          }
          if(UseMACDdir) {
            buy  = (MACD[shift] > MACD[shift+1]);
            sell = (MACD[shift] < MACD[shift+1]);
            if(UseMACDaccel || UseMACDvalue) {
              bMACDbuy  = bMACDbuy  && buy;
              bMACDsell = bMACDsell && sell;
            } else {
              bMACDbuy  = buy;
              bMACDsell = sell;
            }
          }
          if(UseMACDhist) {
            buy  = MACD[shift] > MACD[shift+2];
            sell = MACD[shift] < MACD[shift+2];
            if(UseMACDaccel || UseMACDvalue || UseMACDdir) {
              bMACDbuy  = bMACDbuy  && buy;
              bMACDsell = bMACDsell && sell;
            } else {
              bMACDbuy  = buy;
              bMACDsell = sell;
            }
          }
          if(UseMACDisect) {
            if(!UseMACDaccel) {
              signal = iMAOnArray(MACD,0,SignalMA,0,MODE_EMA,shift);
            }
            buy  = MACD[shift] > signal;
            sell = MACD[shift] < signal;
            if(UseMACDaccel || UseMACDvalue || UseMACDdir || UseMACDhist) {
              bMACDbuy  = bMACDbuy  && buy;
              bMACDsell = bMACDsell && sell;
            } else {
              bMACDbuy  = buy;
              bMACDsell = sell;
            }
          }
          if(UseMACDsign) {
            buy  = MACD[shift] >= 0;
            sell = MACD[shift] <= 0;
            if(UseMACDaccel || UseMACDvalue || UseMACDdir || UseMACDhist || UseMACDsign) {
              bMACDbuy  = bMACDbuy  && buy;
              bMACDsell = bMACDsell && sell;
            } else {
              bMACDbuy  = buy;
              bMACDsell = sell;
            }
          }
        }
      }
//----
      if((!UseRSI || (UseRSI && bRSIbuy)) && (!UseMACD || (UseMACD && bMACDbuy))) {
        if(ShowBody) {
          if(Open[shift] < Close[shift]) {
            val1 = Open[shift];
            val2 = Close[shift];
          } else {
            val2 = Open[shift];
            val1 = Close[shift];
          }
        }
        TrlLong = True;
      } else {
        TrlLong = False;
      }
      if((!UseRSI || (UseRSI && bRSIsell)) && (!UseMACD || (UseMACD && bMACDsell))) {
        if(ShowBody) {
          if(Open[shift] > Close[shift]) {
            val1 = Open[shift];
            val2 = Close[shift];
          } else {
            val2 = Open[shift];
            val1 = Close[shift];
          }
        }
        TrlShort = True;
      } else {
        TrlShort = False;
      }
      ExtMap1[shift] = val1;
      ExtMap2[shift] = val2;
//----
      if(shift < Bars - nDrawBegin) {
        TrlPrevLong  = (TrlStopUp[shift+1] != EMPTY_VALUE) &&
          ((TrlStopUp[shift+1] < Low[shift+1]) || (TrlStopUp[shift+1] == TrlBegin[shift+1]));
        TrlPrevShort = (TrlStopDn[shift+1] != EMPTY_VALUE) &&
          ((TrlStopDn[shift+1] > High[shift+1] + Spread * Point) || (TrlStopDn[shift+1] == TrlBegin[shift+1]));
        if(TrlLong || TrlPrevLong) {
          StopLoss = CalcTrailStop(shift, true, !TrlPrevLong);
          if(TrlPrevLong && StopLoss < TrlStopUp[shift+1]) {
            TrlStopUp[shift] = TrlStopUp[shift+1];
          } else {
            TrlStopUp[shift] = StopLoss;
            if(!TrlPrevLong) {
              TrlBegin[shift] = StopLoss;
            }
          }
        } else {
          TrlStopUp[shift] = EMPTY_VALUE;
        }
        if(TrlShort || TrlPrevShort) {
          StopLoss = CalcTrailStop(shift, false, !TrlPrevShort);
          if(TrlPrevShort && StopLoss > TrlStopDn[shift+1]) {
            TrlStopDn[shift] = TrlStopDn[shift+1];
          } else {
            TrlStopDn[shift] = StopLoss;
            if(!TrlPrevShort) {
              TrlBegin[shift] = StopLoss;
            }
          }
        } else {
          TrlStopDn[shift] = EMPTY_VALUE;
        }
        if((TrlBegin[shift] != EMPTY_VALUE)&&(TrlBegin[shift] != TrlStopUp[shift])&&(TrlBegin[shift] != TrlStopDn[shift])) {
          TrlBegin[shift] = EMPTY_VALUE;
        }
      }
    }
//----
    return(0);
  }
//----
double ATLprice(int i)
  {
    return((High[i] + Low[i]) / 2.0);
  }
//----
double CalcFATLonMedian(int i)
  {
    double res =
      0.4360409450*ATLprice(i+0) +0.3658689069*ATLprice(i+1) +0.2460452079*ATLprice(i+2) +0.1104506886*ATLprice(i+3)
     -0.0054034585*ATLprice(i+4) -0.0760367731*ATLprice(i+5) -0.0933058722*ATLprice(i+6) -0.0670110374*ATLprice(i+7) -0.0190795053*ATLprice(i+8)
     +0.0259609206*ATLprice(i+9) +0.0502044896*ATLprice(i+10)+0.0477818607*ATLprice(i+11)+0.0249252327*ATLprice(i+12)
     -0.0047706151*ATLprice(i+13)-0.0272432537*ATLprice(i+14)-0.0338917071*ATLprice(i+15)-0.0244141482*ATLprice(i+16)-0.0055774838*ATLprice(i+17)
     +0.0128149838*ATLprice(i+18)+0.0226522218*ATLprice(i+19)+0.0208778257*ATLprice(i+20)+0.0100299086*ATLprice(i+21)
     -0.0036771622*ATLprice(i+22)-0.0136744850*ATLprice(i+23)-0.0160483392*ATLprice(i+24)-0.0108597376*ATLprice(i+25)-0.0016060704*ATLprice(i+26)
     +0.0069480557*ATLprice(i+27)+0.0110573605*ATLprice(i+28)+0.0095711419*ATLprice(i+29)+0.0040444064*ATLprice(i+30)
     -0.0023824623*ATLprice(i+31)-0.0067093714*ATLprice(i+32)-0.0072003400*ATLprice(i+33)-0.0047717710*ATLprice(i+34)
     +0.0005541115*ATLprice(i+35)+0.0007860160*ATLprice(i+36)+0.0130129076*ATLprice(i+37)+0.0040364019*ATLprice(i+38);
    return(res);
  }
//----
double CalcSATLonMedian(int i)
  {
    double res = 0.0982862174*ATLprice(i+0)
      +0.0975682269*ATLprice(i+1) +0.0961401078*ATLprice(i+2) +0.0940230544*ATLprice(i+3) +0.0912437090*ATLprice(i+4) +0.0878391006*ATLprice(i+5)
      +0.0838544303*ATLprice(i+6) +0.0793406350*ATLprice(i+7) +0.0743569346*ATLprice(i+8) +0.0689666682*ATLprice(i+9) +0.0632381578*ATLprice(i+10)
      +0.0572428925*ATLprice(i+11)+0.0510534242*ATLprice(i+12)+0.0447468229*ATLprice(i+13)+0.0383959950*ATLprice(i+14)+0.0320735368*ATLprice(i+15)
      +0.0258537721*ATLprice(i+16)+0.0198005183*ATLprice(i+17)+0.0139807863*ATLprice(i+18)+0.0084512448*ATLprice(i+19)+0.0032639979*ATLprice(i+20)
      -0.0015350359*ATLprice(i+21)-0.0059060082*ATLprice(i+22)-0.0098190256*ATLprice(i+23)-0.0132507215*ATLprice(i+24)-0.0161875265*ATLprice(i+25)
      -0.0186164872*ATLprice(i+26)-0.0205446727*ATLprice(i+27)-0.0219739146*ATLprice(i+28)-0.0229204861*ATLprice(i+29)-0.0234080863*ATLprice(i+30)
      -0.0234566315*ATLprice(i+31)-0.0231017777*ATLprice(i+32)-0.0223796900*ATLprice(i+33)-0.0213300463*ATLprice(i+34)-0.0199924534*ATLprice(i+35)
      -0.0184126992*ATLprice(i+36)-0.0166377699*ATLprice(i+37)-0.0147139428*ATLprice(i+38)-0.0126796776*ATLprice(i+39)-0.0105938331*ATLprice(i+40)
      -0.0084736770*ATLprice(i+41)-0.0063841850*ATLprice(i+42)-0.0043466731*ATLprice(i+43)-0.0023956944*ATLprice(i+44)-0.0005535180*ATLprice(i+45)
      +0.0011421469*ATLprice(i+46)+0.0026845693*ATLprice(i+47)+0.0040471369*ATLprice(i+48)+0.0052380201*ATLprice(i+49)+0.0062194591*ATLprice(i+50)
      +0.0070340085*ATLprice(i+51)+0.0076266453*ATLprice(i+52)+0.0080376628*ATLprice(i+53)+0.0083037666*ATLprice(i+54)+0.0083694798*ATLprice(i+55)
      +0.0082901022*ATLprice(i+56)+0.0080741359*ATLprice(i+57)+0.0077543820*ATLprice(i+58)+0.0073260526*ATLprice(i+59)+0.0068163569*ATLprice(i+60)
      +0.0062325477*ATLprice(i+61)+0.0056078229*ATLprice(i+62)+0.0049516078*ATLprice(i+63)+0.0161380976*ATLprice(i+64); 
    return(res);
  }
//+------------------------------------------------------------------+

Comments