//+------------------------------------------------------------------+
//|                                                       DeepNN.mq5 |
//|                                                       Joy D Moyo |
//|                                               www.latvianfts.com |
//+------------------------------------------------------------------+
#property copyright "Joy D Moyo"
#property link      "www.latvianfts.com"
#property version   "1.00"
#include <NeuralNet Functions.mqh>

enum ENUM_ACTIVATIONFX
  {
   Sigmoid_AF = AF_SIGMOID,
   HyperbolicTan_AF = AF_TANH,
   LeakyRELU_AF = AF_LRELU,
   RELU_AF = AF_RELU
  };

enum ENUM_LOSSFX
  {
   BinaryCrossEntropy = LOSS_BCE,
   CategoricalCrossEntropy = LOSS_CCE,
   MeanSquaredError = LOSS_MSE,
   Hinge = LOSS_HINGE
  };

input group "OTHER INPUTS"
input bool HideTesterIndicators = true;

input group "NN INPUTS"
input int NumTrainingBars = 5000;
input int RandomSeed = 42;
input ENUM_ACTIVATIONFX ActivationFx = LeakyRELU_AF;
input ENUM_LOSSFX LossFunction = MeanSquaredError;
input uint Epochs = 1000;
input double LearningRate = 0.0001;
input double PercTrainingSize = 0.7;
input string HiddenLayers = "15,10,7";

input group "MACDHISTOGRAMS"
input int FastEMA = 12;
input int SlowEMA = 26;
input int SignalLine = 9;

input group "RSI"
input int RSIPeriod = 13;

int MACDHandle,RSIHandle,OldSignal=0,Signal;
matrix DataSet(NumTrainingBars,3);
vector HiddenLayer,DataClasses;
bool InBackPropagation = false,IsTrained = false,BullArrowDrawn=false,BearArrowDrawn = false;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CMatrix
  {
public:
   matrix            Matrix;

  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTensor
  {
   CMatrix*          matrices[];
public:
                     CTensor(uint size);
                    ~CTensor(void);

   uint              TensorSize;
   bool              Add(matrix& mat,ulong index);
   matrix            Get(ulong index);
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTensor::CTensor(uint size)
  {
   TensorSize = size;
   ArrayResize(matrices,TensorSize);
   for(uint i=0; i<TensorSize; i++)
      matrices[i] = new CMatrix;

   for(uint i=0; i<TensorSize; i++)
     {
      if(CheckPointer(matrices[i])==POINTER_INVALID)
        {
         printf("Cant create a tensor, Invalid Matrix pointer. ERROR code = ",GetLastError());
         return;
        }
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CTensor::Add(matrix &mat,ulong index)
  {
   if(index>TensorSize)
     {
      printf("Index stated is greater than the tensor size in the function ",__FUNCTION__);
      return false;
     }
   this.matrices[index].Matrix = mat;
   return true;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
matrix CTensor::Get(ulong index)
  {
   if(index>TensorSize)
     {
      printf("%s index %d out of range, Tensor size = %d", __FUNCTION__,index,TensorSize);
      matrix mat = {};
      return (mat);
     }
   return(this.matrices[index].Matrix);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTensor::~CTensor(void)
  {
   for(uint i=0; i<TensorSize; i++)
     {
      if(CheckPointer(matrices[i])!=POINTER_INVALID)
         delete matrices[i];
     }
   ArrayFree(matrices);
  }

CTensor* WeightsTensor;
CTensor* BiasTensor;
CTensor* InputsTensor;
CTensor* OutPutsTensor;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ChartSetInteger(0,CHART_SHOW_GRID,false);
   ChartSetInteger(0,CHART_MODE,CHART_CANDLES);
   ChartSetInteger(0,CHART_COLOR_BACKGROUND,clrBlack);
   ChartSetInteger(0,CHART_COLOR_FOREGROUND,clrWhite);
   ChartSetInteger(0,CHART_COLOR_CHART_UP,clrDodgerBlue);
   ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,clrDodgerBlue);
   ChartSetInteger(0,CHART_COLOR_CHART_DOWN,clrWhite);
   ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,clrWhite);
   ChartSetInteger(0,CHART_COLOR_STOP_LEVEL,clrGold);
   ChartSetInteger(0,CHART_SHOW_VOLUMES,false);
   TesterHideIndicators(HideTesterIndicators);

   IsTrained = false;

   ushort Sep = StringGetCharacter(",",0);
   string Layers[];
   int size = StringSplit(HiddenLayers,Sep,Layers);

   HiddenLayer.Resize(size);

   for(int i=0; i<size; i++)
     {
      HiddenLayer[i]=(int)Layers[i];
     }

   MACDHandle = iMACD(_Symbol,PERIOD_CURRENT,FastEMA,SlowEMA,SignalLine,PRICE_CLOSE);
   RSIHandle = iRSI(_Symbol,PERIOD_CURRENT,RSIPeriod,PRICE_OPEN);

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(CheckPointer(WeightsTensor)!=POINTER_INVALID)
      delete WeightsTensor;
   if(CheckPointer(BiasTensor)!=POINTER_INVALID)
      delete BiasTensor;
   if(CheckPointer(InputsTensor)!=POINTER_INVALID)
      delete InputsTensor;
   if(CheckPointer(OutPutsTensor)!=POINTER_INVALID)
      delete OutPutsTensor;
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!IsTrained)
     {
      CollectTrainTest(1,NumTrainingBars);
      IsTrained = true;
     }

   vector IndicatorBuffer;
   vector inputs(2);

   IndicatorBuffer.CopyIndicatorBuffer(MACDHandle,0,0,1);
   inputs[0] = IndicatorBuffer[0];

   IndicatorBuffer.CopyIndicatorBuffer(RSIHandle,0,0,1);
   inputs[1] = IndicatorBuffer[0];

   if(NewBar())
     {
      BPMinMaxNormalization(inputs);
      Signal = SingleForwardPass(inputs);

      if(Signal == 1 && !BullArrowDrawn)
        {
         string Name = "BName" + (string)TimeCurrent();
         datetime Time = iTime(_Symbol,PERIOD_CURRENT,1);
         double Price = iLow(_Symbol,PERIOD_CURRENT,1)-(3*10*_Point);
         ArrowCreate(Name,Time,Price,233,clrLimeGreen,STYLE_SOLID,0);
         BullArrowDrawn = true;
         BearArrowDrawn = false;
        }

      if(Signal ==0 && !BearArrowDrawn)
        {
         string Name = "SName"+(string)TimeCurrent();
         datetime Time = iTime(_Symbol,PERIOD_CURRENT,1);
         double Price = iHigh(_Symbol,PERIOD_CURRENT,1)+(3*10*_Point);
         ArrowCreate(Name,Time,Price,234,clrRed, STYLE_SOLID,0);
         BearArrowDrawn = true;
         BullArrowDrawn = false;
        }
     }
  }
//+------------------------------------------------------------------+

int OldNumBars = 0;
bool NewBar()
  {
   if(OldNumBars!=Bars(_Symbol,PERIOD_CURRENT))
     {
      OldNumBars = Bars(_Symbol,PERIOD_CURRENT);
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CollectTrainTest(int StartBar,int TotalBars)
  {
   vector IndicatorBuffer;

   DataSet.Resize(NumTrainingBars,3);

   IndicatorBuffer.CopyIndicatorBuffer(MACDHandle,0,StartBar,TotalBars);
   DataSet.Col(IndicatorBuffer,0);

   IndicatorBuffer.CopyIndicatorBuffer(RSIHandle,0,StartBar,TotalBars);
   DataSet.Col(IndicatorBuffer,1);

   int size = TotalBars-StartBar;
   vector y(size);

   for(int i=0; i<size; i++)
     {
      if(iClose(_Symbol,PERIOD_CURRENT,i)>iOpen(_Symbol,PERIOD_CURRENT,i))
         y[i] = 1; //Bullish
      if(iClose(_Symbol,PERIOD_CURRENT,i)<iOpen(_Symbol,PERIOD_CURRENT,i))
         y[i] = 0; //Bearish
     }

   DataSet.Col(y,2);

   matrix xTrain,xTest;
   vector yTrain,yTest;

   TrainTestSplitMatrices(DataSet,xTrain,yTrain,xTest,yTest,PercTrainingSize);

   Print("\n-----> Training the NN\n");

   MinMaxNormalization(xTrain);
   BackPropagation(xTrain,yTrain,Epochs,LearningRate);

   Print("\n------> Testing the NN\n");
   BPMinMaxNormalization(xTest);
   vector preds = BatchForwardPass(xTest);

   Print("Actual Values: ",yTest, "\nPredictions\n", preds);

   ConfusionMatrix(yTest,preds,DataClasses,true);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Randomize(matrix& matrix_)
  {
   MathSrand(RandomSeed);
   int ROWS = (int)matrix_.Rows(), COL = (int)matrix_.Cols();
   int SwapIndex;
   matrix temp_m = matrix_;
   vector temp_v(COL);

   for(int i=0; i<ROWS; i++)
     {
      SwapIndex = MathRand()%ROWS;
      temp_v = matrix_.Row(i);
      matrix_.Row(matrix_.Row(SwapIndex),i);
      matrix_.Row(temp_v,SwapIndex);
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Copy(const vector& CopyFrom, vector& CopyTo, ulong StartFrom,ulong Total = WHOLE_ARRAY)
  {
   if(Total == WHOLE_ARRAY)
      Total = CopyFrom.Size()-StartFrom;

   if(Total<=0||CopyFrom.Size()==0)
     {
      printf("%s Can't copy a vector | Size %d total %d StartFrom %d ",__FUNCTION__,CopyFrom.Size(),Total,StartFrom);
      return false;
     }
   CopyTo.Resize(Total);
   CopyTo.Fill(0);

   for(ulong i=StartFrom, index = 0; i<Total+StartFrom; i++)
     {
      CopyTo[index] = CopyFrom[i];
      index++;
     }
   return true;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void TrainTestSplitMatrices(matrix& matrix_,matrix& x_train,vector& y_train,matrix& x_test,vector& y_test,double TrainSampleSize = 0.7)
  {
   ulong total = matrix_.Rows(), cols = matrix_.Cols();
   ulong last_col = cols-1;

   Randomize(matrix_);

   int TrainSize = (int)MathFloor(total*TrainSampleSize);
   int TestSize = (int)total - TrainSize;

   x_train.Resize(TrainSize,cols-1);
   x_test.Resize(TestSize,cols-1);

   y_train.Resize(TrainSize);
   y_test.Resize(TestSize);

   int TrainCount = 0,TestCount = 0;

   Copy(matrix_.Col(last_col),y_train,0,TrainSize);
   Copy(matrix_.Col(last_col),y_test,TrainSize);

   for(ulong i=0; i<matrix_.Rows(); i++)
     {
      if(i<(ulong)TrainSize)
        {
         x_train.Row(matrix_.Row(i),TrainCount);
         TrainCount++;
        }
      else
        {
         x_test.Row(matrix_.Row(i),TestCount);
         TestCount++;
        }
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Random(double mini, double maxi)
  {
   return mini+double((MathRand()/32767.0)*(maxi-mini));
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void GenerateTensorParameters(uint Inputsf,vector& HiddenLayersf)
  {
   MathSrand(RandomSeed);

   WeightsTensor = new CTensor((uint)HiddenLayersf.Size());
   BiasTensor = new CTensor((uint)HiddenLayersf.Size());

   uint LayerInput = Inputsf;

   matrix Weights,Bias;

   for(ulong layer=0; layer<HiddenLayersf.Size(); layer++)
     {
      Weights.Resize((uint)HiddenLayersf[layer],LayerInput);
      for(ulong i=0; i<Weights.Rows(); i++)
        {
         for(ulong j=0; j<Weights.Cols(); j++)
           {
            Weights[i][j] = Random(-1,1);
           }
        }
      WeightsTensor.Add(Weights,layer);
      Bias.Resize((uint)HiddenLayersf[layer],1);
      for(ulong i=0; i<Bias.Rows(); i++)
        {
         for(ulong j=0; j<Bias.Cols(); j++)
           {
            Bias[i][j] = Random(-1,1);
           }
        }
      BiasTensor.Add(Bias,layer);
      LayerInput = (int)HiddenLayersf[layer];
     }
     Print("Weights = ",WeightsTensor.Get(0),"\nBias = ",BiasTensor.Get(0));
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector ForwardPass(vector &x)
  {
   matrix LayerInput = VectorToMatrix(x);
   matrix LayerOutPut = {};
   matrix W,B;
   ulong NumHiddenLayers = HiddenLayer.Size();

   for(ulong i=0; i<NumHiddenLayers; i++)
     {
      W = WeightsTensor.Get(i);
      B = BiasTensor.Get(i);

      if(InBackPropagation)
         InputsTensor.Add(LayerInput,i);

      LayerOutPut = W.MatMul(LayerInput) + B;
      if(!LayerOutPut.Activation(LayerOutPut,i+1==NumHiddenLayers?AF_SOFTMAX:ENUM_ACTIVATION_FUNCTION(ActivationFx)))
        {
         printf("%s failed to calculate the activation function Err = %d",__FUNCTION__,GetLastError());
        }
      if(InBackPropagation)
         OutPutsTensor.Add(LayerOutPut,i);

      LayerInput = LayerOutPut;
     }
   return MatrixToVector(LayerOutPut);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SingleForwardPass(vector& x)
  {
   vector v = ForwardPass(x);
   return (int)DataClasses[v.ArgMax()];
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector BatchForwardPass(matrix& x)
  {
   vector v(x.Rows());
   for(ulong i=0; i<x.Rows(); i++)
     {
      v[i] = SingleForwardPass(x.Row(i));
     }
   return v;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void BackPropagation(matrix& x, vector& y, uint epochs = 100,double learning_rate = 0.001)
  {
   DataClasses = Classes(y);

   uint OutPutsNode = (uint)DataClasses.Size();

   HiddenLayer.Resize(HiddenLayer.Size()+1);

   HiddenLayer[HiddenLayer.Size()-1] = OutPutsNode;

   uint NumHiddenLayers = (uint)HiddenLayer.Size();

   GenerateTensorParameters((uint)x.Cols(),HiddenLayer);

   vector Predictions, NetworkPred,ActualValues;

   matrix ONE_HOT_MATRIX = OneHotEncoding(y);

   matrix PartialDerivatives, Delta(HiddenLayer[NumHiddenLayers-1],1);
   vector LossGradient;

   InputsTensor = new CTensor(NumHiddenLayers);
   OutPutsTensor = new CTensor(NumHiddenLayers);

   if(MQLInfoInteger(MQL_DEBUG))
      Print("Hidden Layers: ",HiddenLayer,"\nClasses in data: ",DataClasses);

   matrix weights,bias,dW,dB,layer_inputs;

   InBackPropagation = true;

   for(uint epoch=0; epoch<epochs && !IsStopped(); epoch++)
     {
      for(ulong iteration=0; iteration<x.Rows() && !IsStopped(); iteration++)
        {
         NetworkPred = ForwardPass(x.Row(iteration));
         ActualValues = ONE_HOT_MATRIX.Row(iteration);

         Delta.Resize((uint)HiddenLayer[NumHiddenLayers-1],1);

         for(int layer=(int)NumHiddenLayers-1; layer>=0; layer--)
           {
            PartialDerivatives = OutPutsTensor.Get(layer);
            PartialDerivatives.Derivative(PartialDerivatives,layer == NumHiddenLayers-1?AF_SOFTMAX:ENUM_ACTIVATION_FUNCTION(ActivationFx));
            layer_inputs = InputsTensor.Get(layer);

            if(layer == NumHiddenLayers-1)
              {
               LossGradient = NetworkPred.LossGradient(ActualValues,ENUM_LOSS_FUNCTION(LossFunction));
               Delta.Col(LossGradient,0);
              }
            else
              {
               weights = WeightsTensor.Get(layer+1);
               Delta = (weights.Transpose().MatMul(Delta))*PartialDerivatives;
              }

            dB = Delta;
            dW = Delta.MatMul(layer_inputs.Transpose());

            weights = WeightsTensor.Get(layer);
            bias = BiasTensor.Get(layer);

            WeightsTensor.Add(weights -= dW * learning_rate,layer);
            BiasTensor.Add(bias -= dB*learning_rate,layer);
           }
        }
      vector preds = BatchForwardPass(x);
      double loss = preds.Loss(y,ENUM_LOSS_FUNCTION(LossFunction));
      printf("[ Epoch %d/%d Cost %.8f Accuracy %.3f]",epoch+1,epochs,loss,ConfusionMatrix(y,preds,DataClasses,false));

      if(epoch+1 == epochs)
         Print("ActualValues: ",y,"\nPredictions: ",preds);
     }
   InBackPropagation = false;
  }
//+------------------------------------------------------------------+

bool ArrowCreate
(
   const string name,
   datetime time,
   double price,
   const uchar arrowcode,
   const color clr = clrRed,
   const ENUM_LINE_STYLE style = STYLE_SOLID,
   const int width = 3
)
  {
   if(!ObjectCreate(0,name,OBJ_ARROW,0,time,price))
     {
      printf(__FUNCTION__," : Failed to create an arrow, Error code = ", GetLastError());
      return false;
     }
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,arrowcode);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_STYLE,style);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,width);
   return true;
  }
//+------------------------------------------------------------------+



use de exemplo a estrutura deepleaning do codigo acima e implemente no meu codigo abaixo o deeplearning para aumentar a assertividade no trading, nao altere a estrategia original do meu codigo abaixo apenas adicione a rede neural deeplearing para melhor assertividade e depois me entregue o codigo completo:

//+------------------------------------------------------------------+
//|                                                   Scalping Robot |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>

CTrade           trade;
CPositionInfo    pos;
COrderInfo       ord;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

input group "*** Trading Inputs ***"
input double LotSize             = 0.01;  // Lot size for trading
input int    Tppoints            = 800;   // Take Profit (10 points = 1 pip)
input int    Slpoints            = 800;   // Stoploss Points (10 points = 1 pip)
input int    TslTriggerPoints    = 35;    // Points in profit before Trailing SL is activated (10 points = 1 pip)
input int    TslPoints           = 10;    // Trailing Stoploss (10 points = 1 pip)
input ENUM_TIMEFRAMES Timeframe  = PERIOD_CURRENT; // Time frame to run
input int    InpMagic            = 891245; // EA identification no
input string TradeComment        = "Wendel Cassiano";
input int    MaxSpread           = 100;   // Maximum spread allowed (in points)
input int    Slippage            = 50;    // Slippage in points
input int    MaxOrders           = 2;     // Máximo de ordens permitidas simultaneamente

enum StarHour { Inactive=0, _0100=1, _0200=2, _0300=3, _0400=4, _0500=5, _0600=6, _0700=7, _0800=8, _0900=9, _1000=10, _1100=11, _1200=12, _1300=13, _1400=14, _1500=15, _1600=16, _1700=17, _1800=18, _1900=19, _2000=20, _2100=21, _2200=22, _2300=23 };
input StarHour SHInput = 0; // Start Hour

enum EndHour { Inactive=0, _0100=1, _0200=2, _0300=3, _0400=4, _0500=5, _0600=6, _0700=7, _0800=8, _0900=9, _1000=10, _1100=11, _1200=12, _1300=13, _1400=14, _1500=15, _1600=16, _1700=17, _1800=18, _1900=19, _2000=20, _2100=21, _2200=22, _2300=23 };
input EndHour EHInput = 0; // End Hour

int SHChoice;
int EHChoice;

int BarsN            = 5;
int ExpirationBars   = 100;
int OrderDistPoints  = 100;

int OnInit()
{
    //---
    trade.SetExpertMagicNumber(InpMagic);
    ChartSetInteger(0, CHART_SHOW_GRID, false);

    return (INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    //---

    TrailStop();

    if (!IsNewBar()) return;

    MqlDateTime time;
    TimeToStruct(TimeCurrent(), time);

    int Hournow = time.hour;

    SHChoice = SHInput;
    EHChoice = EHInput;

     if (Hournow < SHChoice) { CloseAllOrders(); return; }
    if (Hournow >= EHChoice && EHChoice != 0) { CloseAllOrders(); return; }

    double spread = (SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID)) / _Point;
    if (spread > MaxSpread) return;

    int BuyTotal = 0;
    int SellTotal = 0;

    for (int i = PositionsTotal() - 1; i >= 0; i--)
    {
        pos.SelectByIndex(i);
        if (pos.PositionType() == POSITION_TYPE_BUY && pos.Symbol() == _Symbol && pos.Magic() == InpMagic) BuyTotal++;
        if (pos.PositionType() == POSITION_TYPE_SELL && pos.Symbol() == _Symbol && pos.Magic() == InpMagic) SellTotal++;
    }

    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ord.SelectByIndex(i);
        if (ord.OrderType() == ORDER_TYPE_BUY_STOP && ord.Symbol() == _Symbol && ord.Magic() == InpMagic) BuyTotal++;
        if (ord.OrderType() == ORDER_TYPE_SELL_STOP && ord.Symbol() == _Symbol && ord.Magic() == InpMagic) SellTotal++;
    }

    int TotalOrders = BuyTotal + SellTotal;
    if (TotalOrders >= MaxOrders) return;

    if (BuyTotal <= 0)
    {
        double high = findHigh();
        if (high > 0)
        {
            SendBuyOrder(high);
        }
    }

    if (SellTotal <= 0)
    {
        double low = findLow();
        if (low > 0)
        {
            SendSellOrder(low);
        }
    }
}
//+------------------------------------------------------------------+

double findHigh()
{
    double highestHigh = 0;
    for (int i = 0; i < 200; i++)
    {
        double high = iHigh(_Symbol, Timeframe, i);
        if (i > BarsN && iHighest(_Symbol, Timeframe, MODE_HIGH, BarsN * 2 + 1, i - BarsN) == i)
        {
            if (high > highestHigh)
            {
                return high;
            }
        }
        highestHigh = MathMax(high, highestHigh);
    }
    return -1;
}

double findLow()
{
    double LowestLow = DBL_MAX;
    for (int i = 0; i < 200; i++)
    {
        double Low = iLow(_Symbol, Timeframe, i);
        if (i > BarsN && iLowest(_Symbol, Timeframe, MODE_LOW, BarsN * 2 + 1, i - BarsN) == i)
        {
            if (Low < LowestLow)
            {
                return Low;
            }
        }
        LowestLow = MathMin(Low, LowestLow);
    }
    return -1;
}

bool IsNewBar()
{
    static datetime previousTime = 0;
    datetime currentTime = iTime(_Symbol, Timeframe, 0);
    if (previousTime != currentTime)
    {
        previousTime = currentTime;
        return true;
    }
    return false;
}

void SendBuyOrder(double entry)
{
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

    if (ask > entry - OrderDistPoints * _Point) return;

    double tp = entry + Tppoints * _Point;
    double sl = entry - Slpoints * _Point;

    // Use configured lot size
    double lots = LotSize;

    datetime expiration = iTime(_Symbol, Timeframe, 0) + ExpirationBars * PeriodSeconds(Timeframe);

    trade.BuyStop(lots, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, Slippage);
}

void SendSellOrder(double entry)
{
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    if (bid < entry + OrderDistPoints * _Point) return;

    double tp = entry - Tppoints * _Point;
    double sl = entry + Slpoints * _Point;

    // Use configured lot size
    double lots = LotSize;

    datetime expiration = iTime(_Symbol, Timeframe, 0) + ExpirationBars * PeriodSeconds(Timeframe);

    trade.SellStop(lots, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, expiration, Slippage);
}

double calcLots(double slPoints)
{
    // Return the configured lot size
    return LotSize;
}

void CloseAllOrders()
{
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        ord.SelectByIndex(i);
        ulong ticket = ord.Ticket();
        if (ord.Symbol() == _Symbol && ord.Magic() == InpMagic)
        {
            trade.OrderDelete(ticket);
        }
    }
}

void TrailStop()
{
    double sl = 0;
    double tp = 0;

    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    for (int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if (pos.SelectByIndex(i))
        {
            ulong ticket = pos.Ticket();

            if (pos.Magic() == InpMagic && pos.Symbol() == _Symbol)
            {

                if (pos.PositionType() == POSITION_TYPE_BUY)
                {
                    if (bid - pos.PriceOpen() > TslTriggerPoints * _Point)
                    {
                        tp = pos.TakeProfit();
                        sl = bid - (TslPoints * _Point);

                        if (sl > pos.StopLoss() && sl != 0)
                        {
                            trade.PositionModify(ticket, sl, tp);
                        }
                    }
                }
                else if (pos.PositionType() == POSITION_TYPE_SELL)
                {
                    if (ask + (TslTriggerPoints * _Point) < pos.PriceOpen())
                    {
                        tp = pos.TakeProfit();
                        sl = ask + (TslPoints * _Point);

                        if (sl < pos.StopLoss() && sl != 0)
                        {
                            trade.PositionModify(ticket, sl, tp);
                        }
                    }
                }
            }
        }
    }
}