#property copyright "Your Name"
#property link      "Your Website"

#property indicator_separate_window

extern int Key_Value = 1;            // Key Value. This changes the sensitivity
extern int ATR_Period = 10;          // ATR Period
extern bool Use_HeikinAshi = false;  // Signals from Heikin Ashi Candles

double xATRTrailingStopBuffer[];
double nLossBuffer[];
int posBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexStyle(0, DRAW_ARROW, EMPTY, 2);
   SetIndexArrow(0, 233);
   SetIndexLabel(0, "Buy");

   SetIndexStyle(1, DRAW_ARROW, EMPTY, 2);
   SetIndexArrow(1, 234);
   SetIndexLabel(1, "Sell");

   SetIndexEmptyValue(0, 0.0);
   SetIndexEmptyValue(1, 0.0);
   SetIndexEmptyValue(2, 0);

   ArraySetAsSeries(xATRTrailingStopBuffer, true);
   ArraySetAsSeries(nLossBuffer, true);
   ArraySetAsSeries(posBuffer, true);

   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
{
   int limit;
   int counted_bars = prev_calculated;
   if (counted_bars < 0) return 0;

   if (counted_bars > 0)
      limit = rates_total - counted_bars;
   else
      limit = rates_total - ATR_Period;

   double src;
   double ema;
   bool buy, sell;
   bool barbuy, barsell;

   for (int i = limit; i >= 0; i--)
   {
      src = Use_HeikinAshi ? iCustom(NULL, 0, "Heiken_Ashi", ATR_Period, i) : close[i];
      if (i == limit)
      {
         xATRTrailingStopBuffer[i] = src;
         nLossBuffer[i] = Key_Value * iATR(NULL, 0, ATR_Period, i);
      }

      xATRTrailingStopBuffer[i] = CalculateTrailingStop(src, xATRTrailingStopBuffer[i], nLossBuffer[i], close);

      if (i == 0)
         posBuffer[i] = 0;
      else
         posBuffer[i] = CalculatePosition(src, xATRTrailingStopBuffer[i], posBuffer[i], i, close);

      ema = iMA(NULL, 0, 1, 0, MODE_EMA, PRICE_CLOSE, i);
      buy = src > xATRTrailingStopBuffer[i] && src > ema;
      sell = src < xATRTrailingStopBuffer[i] && src < ema;
      barbuy = src > xATRTrailingStopBuffer[i];
      barsell = src < xATRTrailingStopBuffer[i];

      if (buy)
         PlotSignal(0, i, src, true);
      if (sell)
         PlotSignal(1, i, src, false);
   }

   return rates_total;
}

double CalculateTrailingStop(double currentPrice, double prevTrailingStop, double lossValue, const double& close[])
{
   int i = ArraySize(close) - 1; // Get the last index of the 'close' array
   if (currentPrice > prevTrailingStop && close[i - 1] > prevTrailingStop)
      return MathMax(prevTrailingStop, currentPrice - lossValue);
   else if (currentPrice < prevTrailingStop && close[i - 1] < prevTrailingStop)
      return MathMin(prevTrailingStop, currentPrice + lossValue);
   else if (currentPrice > prevTrailingStop)
      return currentPrice - lossValue;
   else
      return currentPrice + lossValue;
}

int CalculatePosition(double currentPrice, double trailingStop, int prevPosition, int i, const double& close[])
{
   if (close[i - 1] < trailingStop && currentPrice > trailingStop)
      return 1;
   else if (close[i - 1] > trailingStop && currentPrice < trailingStop)
      return -1;
   else
      return prevPosition;
}

void PlotSignal(int index, int bar, double price, bool isBuySignal)
{
   double yShift = isBuySignal ? Low[bar] - MathAbs(High[bar] - Low[bar]) * 0.1 : High[bar] + MathAbs(High[bar] - Low[bar]) * 0.1;
   string text = isBuySignal ? "Buy" : "Sell";
   color arrowColor = isBuySignal ? clrGreen : clrRed;
   int arrowCode = isBuySignal ? 233 : 234;

   double symbolSize = 2; // Adjust the size of the arrow as needed
   if (isBuySignal)
      yShift -= symbolSize * Point;
   else
      yShift += symbolSize * Point;

   ObjectCreate("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJ_ARROW, 0, Time[bar], price);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_ARROWCODE, arrowCode);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_COLOR, arrowColor);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_SELECTABLE, false);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_SELECTED, false);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_WIDTH, 1);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet("Arrow" + IntegerToString(index) + "_" + IntegerToString(bar), OBJPROP_YDISTANCE, yShift);
}
