//+------------------------------------------------------------------+
//|                                                   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);
                        }
                    }
                }
            }
        }
    }
}


imeplemente no meu codigo acima a rede neural do codigo abaixo para melhorar a assertividade, nao adicione outras estrategias de RSI etc mantenha meu codigo com a estrategia atual original apenas adiciona rede neural avançada para melhorias e me entregue o codigo completo:

//+------------------------------------------------------------------+
//|                                            Neural Network EA.mq5 |
//|                                                       Joy D Moyo |
//|                                               www.latvianfts.com |
//+------------------------------------------------------------------+
#property copyright "Joy D Moyo"
#property link      "www.latvianfts.com"
#property version   "1.00"

enum Activation_Function
  {
   AFHardSigmoid = AF_HARD_SIGMOID,
   AFSigmoid = AF_SIGMOID,
   AFSwish = AF_SWISH,
   AFSoftSign = AF_SOFTSIGN,
   AFTangent = AF_TANH
  };

enum Loss
  {
   BinaryCrossEntropy = LOSS_BCE,
   CategoricalCrossEntropy = LOSS_CCE,
   MeanSquaredError = LOSS_MSE,
   Hinge = LOSS_HINGE,
   CategoricalHinge = LOSS_CAT_HINGE
  };

input group "GENERAL INPUTS"
input ENUM_TIMEFRAMES LearningTF = PERIOD_H1;
input ENUM_TIMEFRAMES PeriodTraded = PERIOD_M5;
input string MySymbol = "EURUSD";
input bool HideTesterIndicator = false;

input group "INDICATOR INPUTS"
input int RSIPeriod = 14;
input int BBPeriod = 20;
input double BBDeviation = 2.0;

input group "NN"
input int UsedBars = 1000;
input int RandomSeed = 42;
input Activation_Function ActivationFx = AFSigmoid;
input Loss LossFx = MeanSquaredError;
input double LearningRate = 0.04;
input uint Epochs = 100;
input double ProbThreshold = 0.55; //Probability Threshold

int OldNumBars,BBHandle,RSIHandle,NumOfOutPuts = 2,OldSignal = 0,Signal;

ulong InputNumCol = 4;
ulong MatrixRows = 0;

vector BBUpper,BBLower,BBMid,RSI;
vector OpenPrice,ClosePrice;
vector OutPutVector,Probability;
vector LiveData(InputNumCol);
vector ClassesVector;

matrix InputMatrix,Weights,Bias;

double MyPoint;

bool BPDone = false;
bool AlreadyRun = false;
bool BullArrowDrawn = false,BearArrowDrawn = false;

//+------------------------------------------------------------------+
//| 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(HideTesterIndicator);

   MyPoint = SymbolInfoDouble(MySymbol,SYMBOL_POINT);

   RSIHandle = iRSI(MySymbol,LearningTF,RSIPeriod,PRICE_CLOSE);
   BBHandle = iBands(MySymbol,LearningTF,BBPeriod,0,BBDeviation,PRICE_CLOSE);

   MathSrand(RandomSeed);
   GenerateParameters();

   int BarsOnChart = TerminalInfoInteger(TERMINAL_MAXBARS);
   if(UsedBars>=BarsOnChart)
     {
      if(MQLInfoInteger(MQL_TESTER)||MQLInfoInteger(MQL_OPTIMIZATION))
         printf("UsedBars is greater than bars in testing History, adjust your start dates");
      else
         printf("UsedBars is greater than terminal MaxBars, go to charts section to increase the number of chart bars");
      return INIT_FAILED;
     }

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Comment("");
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!NewBar())
      return;
   if(!AlreadyRun)
     {TrainModel(); AlreadyRun = true;}

   GetLiveData();
   Probability = LiveForwardPass(LiveData);

   string TComment;
   if(Probability[0]>ProbThreshold)
     {Signal = 1; TComment = "BUY"; BullArrowDrawn = false; BearArrowDrawn = true;}
   else
      if(Probability[1]>ProbThreshold)
        {Signal = -1; TComment = "SELL"; BullArrowDrawn= true; BearArrowDrawn = false;}
      else
        {
         Signal = 0;
         TComment = "UNDECIDED";
         BullArrowDrawn=true;
         BearArrowDrawn = true;
        }
   if(NewSignal())
     {
      if(!BullArrowDrawn&&Signal==1)
        {
         string Name = "BName"+(string)TimeCurrent();
         datetime Time = iTime(MySymbol,PeriodTraded,1);
         double Price = iLow(MySymbol,PeriodTraded,1)-(3*10*MyPoint);
         ArrowCreate(Name,Time,Price,233,clrGreen,STYLE_SOLID,0);
         BullArrowDrawn = true;
        }
      if(!BearArrowDrawn&&Signal==-1)
        {
         string Name = "SName"+(string)TimeCurrent();
         datetime Time = iTime(MySymbol,PeriodTraded,1);
         double Price = iHigh(MySymbol,PeriodTraded,1)+(3*10*MyPoint);
         ArrowCreate(Name,Time,Price,234,clrRed,STYLE_SOLID,0);
         BearArrowDrawn = true;
        }
     }
   Comment("Predicted Probability = ",Probability,"MOVE = ",TComment);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NewBar()
  {
   int CurrentNumBars = Bars(MySymbol,PeriodTraded);
   if(OldNumBars!=CurrentNumBars)
     {
      OldNumBars = CurrentNumBars;
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector GetLiveData()
  {
   BBUpper.CopyIndicatorBuffer(BBHandle,1,0,1);
   BBLower.CopyIndicatorBuffer(BBHandle,2,0,1);
   BBMid.CopyIndicatorBuffer(BBHandle,0,0,1);
   RSI.CopyIndicatorBuffer(RSIHandle,0,0,1);

   LiveData[0] = BBUpper[0];
   LiveData[1] = BBLower[0];
   LiveData[2] = BBMid[0];
   LiveData[3] = RSI[0];

   return LiveData;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CollectTrainingData()
  {
   BBUpper.CopyIndicatorBuffer(BBHandle,1,0,UsedBars);
   BBLower.CopyIndicatorBuffer(BBHandle,2,0,UsedBars);
   BBMid.CopyIndicatorBuffer(BBHandle,0,0,UsedBars);
   RSI.CopyIndicatorBuffer(RSIHandle,0,0,UsedBars);

   OpenPrice.CopyRates(MySymbol,LearningTF,COPY_RATES_OPEN,0,UsedBars);
   ClosePrice.CopyRates(MySymbol,LearningTF,COPY_RATES_CLOSE,0,UsedBars);

   ulong size = OpenPrice.Size();
   OutPutVector.Resize(size);

   for(ulong i=0; i<size; i++)
     {
      if(ClosePrice[i]>OpenPrice[i])
         OutPutVector[i]=1;
      else
         OutPutVector[i]=-1;
     }

   InputMatrix.Resize(size,InputNumCol);

   InputMatrix.Col(BBUpper,0);
   InputMatrix.Col(BBLower,1);
   InputMatrix.Col(BBMid,2);
   InputMatrix.Col(RSI,3);

   MinMaxNormalization(InputMatrix);

   MatrixRows = InputMatrix.Rows();
   ClassesVector = Classes(OutPutVector);
  }
//+------------------------------------------------------------------+

struct NormalizationStructure
  {
   vector            min;
   vector            max;
                     NormalizationStructure::NormalizationStructure(ulong Columns)
     {
      min.Resize(Columns);
      max.Resize(Columns);
     }
  } MinMaxNorm(InputNumCol);

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MinMaxNormalization(matrix &Matrix)
  {
   vector column;
   for(ulong i=0; i<InputNumCol; i++)
     {
      column = Matrix.Col(i);

      MinMaxNorm.min[i] = column.Min();
      MinMaxNorm.max[i] = column.Max();

      column = (column-MinMaxNorm.min[i])/(MinMaxNorm.max[i]-MinMaxNorm.min[i]);

      Matrix.Col(column,i);
     }
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void BPMinMaxNormalization(vector &v)
  {
   if(v.Size()!=InputNumCol)
     {
      Print("Cant Normalize the data, Vector size must be = the size fo the matrix columns");
      return;
     }
   for(ulong i=0; i<InputNumCol; i++)
      v[i] = (v[i]-MinMaxNorm.min[i])/(MinMaxNorm.max[i]-MinMaxNorm.min[i]);
  }

#define Random(mini,maxi) mini+double((MathRand()/32767.0)*(maxi-mini));

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void GenerateParameters()
  {
   Weights.Resize(NumOfOutPuts,InputNumCol);
   Bias.Resize(NumOfOutPuts,1);

   for(ulong i=0; i<Weights.Rows(); i++)
      for(ulong j=0; j<Weights.Cols(); j++)
         Weights[i][j] = Random(-1,1);

   for(ulong i=0; i<Bias.Rows(); i++)
      for(ulong j=0; j<Bias.Cols(); j++)
         Bias[i][j] = Random(-1,1);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
matrix VectorToMatrix(const vector &v,ulong cols = 1)
  {
   ulong rows = 0;
   matrix mat = {};

   if(v.Size()%cols>0)
     {
      printf(__FUNCTION__, "Invalid num Of cols for new matrix");
      return mat;
     }

   rows = v.Size()/cols;

   mat.Resize(rows,cols);

   for(ulong i=0,index = 0; i<rows; i++)
      for(ulong j=0; j<cols; j++,index++)
         mat[i][j] = v[index];

   return mat;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector MatrixToVector(const matrix &Mat)
  {
   vector v = {};

   if(!v.Assign(Mat))
      Print(__FUNCTION__,"Failed converting a matrix to a vector");
   return v;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
matrix Neuron(matrix &I, matrix &W,matrix &B,ENUM_ACTIVATION_FUNCTION Activation)
  {
   matrix OutPuts;
   ((W.MatMul(I)) + B).Activation(OutPuts,Activation);
   return OutPuts;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
matrix SingleInputForwardPass(vector &input_v)
  {
   vector temp_x = input_v;

   if(!BPDone)
      BPMinMaxNormalization(temp_x);

   matrix INPUT = VectorToMatrix(temp_x);
   return Neuron(INPUT,Weights,Bias,ENUM_ACTIVATION_FUNCTION(ActivationFx));
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector LiveForwardPass(vector &input_v)
  {
   matrix ret_mat = SingleInputForwardPass(input_v);
   return MatrixToVector(ret_mat);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector BatchInputForwardPass(matrix &x_matrix)
  {
   vector ret(x_matrix.Rows());
   matrix OutPuts;
   vector v = {};
   for(ulong i=0; i<x_matrix.Rows(); i++)
     {
      v = LiveForwardPass(x_matrix.Row(i));
      ret[i] = ClassesVector[(int)v.ArgMax()];
     }
   return ret;
  }

double CheckZero(double x) {return x==0?1.0:x;}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SearchPatterns(vector &SearchVectorA,int ValueSearchedA, vector &SearchVectorB,int ValueSearchedB)
  {
   int count = 0;
   for(ulong i=0; i<SearchVectorA.Size(); i++)
     {
      if(SearchVectorA[i]==ValueSearchedA&&SearchVectorB[i]==ValueSearchedB)
         count++;
     }
   return count;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void VectorRemoveIndex(vector &v,ulong index)
  {
   vector new_v(v.Size()-1);
   for(ulong i=0,count=0; i<v.Size(); i++)
     {
      if(i!=index)
        {
         new_v[count] = v[i];
         count++;
        }
     }
   v.Copy(new_v);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MatrixRemoveCol(matrix &mat,ulong col)
  {
   matrix new_matrix(mat.Rows(),mat.Cols()-1);
   for(ulong i=0,new_col=0; i<mat.Cols(); i++)
     {
      if(i==col)
         continue;
      else
        {
         new_matrix.Col(mat.Col(i),new_col);
         new_col++;
        }
     }
   mat.Copy(new_matrix);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MatrixRemoveRow(matrix &mat,ulong row)
  {
   matrix new_matrix(mat.Rows()-1,mat.Cols());
   for(ulong i=0,new_rows=0; i<mat.Cols(); i++)
     {
      if(i==row)
         continue;
      else
        {
         new_matrix.Row(mat.Row(i),new_rows);
         new_rows++;
        }
     }
   mat.Copy(new_matrix);
  }
//+------------------------------------------------------------------+

struct ConfusionMatrixStruct
  {
   double            accuracy;
   vector            precision;
   vector            recall;
   vector            f1_score;
   vector            specificity;
   vector            support;

   vector            avg;
   vector            w_avg;
  } CMatrixObj;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ConfusionMatrix(vector &ActualVal,vector &PredictedVal,vector &Classes,bool report_show = true)
  {
   ulong TruePositives=0,TrueNegatives=0,FalsePositives=0,FalseNegatives=0;
   matrix ConfMatrixVal(Classes.Size(),Classes.Size());
   ConfMatrixVal.Fill(0);
   vector row(Classes.Size()),ConfVectorVal(ulong(MathPow(Classes.Size(),2)));

   if(ActualVal.Size()!=PredictedVal.Size())
     {
      Print("Actual and Predicted vectors are not of the same size");
      return 0;
     }

   for(ulong i=0; i<Classes.Size(); i++)
     {
      for(ulong j=0; j<Classes.Size(); j++)
        {
         ConfMatrixVal[i][j] = SearchPatterns(ActualVal,(int)Classes[i],PredictedVal,(int)Classes[j]);
        }
     }
//-------METRICS
//-------Accuracy
   vector diag = ConfMatrixVal.Diag();
   CMatrixObj.accuracy = NormalizeDouble(diag.Sum()/CheckZero(ConfMatrixVal.Sum()),3);

//--------Precision
   CMatrixObj.precision.Resize(Classes.Size());
   vector col_v = {};
   double MetricValue =0;
   for(ulong i=0; i<Classes.Size(); i++)
     {
      col_v = ConfMatrixVal.Col(i);
      VectorRemoveIndex(col_v,i);
      TruePositives = (ulong)diag[i];
      FalsePositives = (ulong)col_v.Sum();
      MetricValue = TruePositives/CheckZero(TruePositives+FalsePositives);
      CMatrixObj.precision[i] = NormalizeDouble(MathIsValidNumber(MetricValue)?MetricValue:0,8);
     }

//--------Recall
   vector row_v = {};
   CMatrixObj.recall.Resize(Classes.Size());

   for(ulong i=0; i<Classes.Size(); i++)
     {
      row_v = ConfMatrixVal.Row(i);
      VectorRemoveIndex(row_v,i);
      TruePositives = (ulong)diag[i];
      FalseNegatives = (ulong)row_v.Sum();
      MetricValue = TruePositives/CheckZero(TruePositives+FalseNegatives);
      CMatrixObj.recall[i] = NormalizeDouble(MathIsValidNumber(MetricValue)?MetricValue:0,8);
     }

//---------Specificity
   matrix temp_mat = {};
   ZeroMemory(col_v);
   CMatrixObj.specificity.Resize(Classes.Size());

   for(ulong i=0; i<Classes.Size(); i++)
     {
      temp_mat.Copy(ConfMatrixVal);
      MatrixRemoveCol(temp_mat,i);
      MatrixRemoveRow(temp_mat,i);
      col_v = ConfMatrixVal.Col(i);
      VectorRemoveIndex(col_v,i);
      FalsePositives = (ulong)col_v.Sum();
      TrueNegatives = (ulong)temp_mat.Sum();
      MetricValue = TrueNegatives/CheckZero(TrueNegatives+FalsePositives);
      CMatrixObj.specificity[i] = NormalizeDouble(MathIsValidNumber(MetricValue)?MetricValue:0,8);
     }

//------F1 Score
   CMatrixObj.f1_score.Resize(Classes.Size());
   for(ulong i=0; i<Classes.Size(); i++)
     {
      CMatrixObj.f1_score[i]= 2*((CMatrixObj.precision[i]*CMatrixObj.recall[i])/CheckZero(CMatrixObj.precision[i]-CMatrixObj.recall[i]));
      MetricValue = CMatrixObj.f1_score[i];
      CMatrixObj.f1_score[i] = NormalizeDouble(MathIsValidNumber(MetricValue)?MetricValue:0,8);
     }

//------Support
   CMatrixObj.support.Resize(Classes.Size());
   ZeroMemory(row_v);
   for(ulong i=0; i<Classes.Size(); i++)
     {
      row_v = ConfMatrixVal.Row(i);
      CMatrixObj.support[i] = NormalizeDouble(MathIsValidNumber(row_v.Sum())?row_v.Sum():0,8);
     }
   int total_size = (int)ConfMatrixVal.Sum();

//-------- Avg
   CMatrixObj.avg.Resize(5);
   CMatrixObj.avg[0] = CMatrixObj.precision.Mean();
   CMatrixObj.avg[1] = CMatrixObj.recall.Mean();
   CMatrixObj.avg[2] = CMatrixObj.specificity.Mean();
   CMatrixObj.avg[3] = CMatrixObj.f1_score.Mean();
   CMatrixObj.avg[4] = total_size;


//-------- wAvg
   CMatrixObj.w_avg.Resize(5);
   vector Support_proportion = CMatrixObj.support/CheckZero(total_size);
   vector c = CMatrixObj.precision*Support_proportion;
   CMatrixObj.w_avg[0] = c.Sum();
   c = CMatrixObj.recall*Support_proportion;
   CMatrixObj.w_avg[1] = c.Sum();
   c = CMatrixObj.specificity*Support_proportion;
   CMatrixObj.w_avg[2] = c.Sum();
   c = CMatrixObj.f1_score*Support_proportion;
   CMatrixObj.w_avg[3] = c.Sum();
   CMatrixObj.w_avg[4] = (int)total_size;

//--------- Report
   if(report_show)
     {
      string report = "\n_\t\t\t\tPrecision \tRecall \tSpecificity \tF1 score \tSupport";

      for(ulong i=0; i<Classes.Size(); i++)
        {
         report += "\n\t"+string(Classes[i]);
         report += StringFormat("\t\t\t %.2f \t\t\t %.2f \t\t\t %.2f \t\t\t\t\t %.2f \t\t\t %.1f",CMatrixObj.precision[i],CMatrixObj.recall[i],CMatrixObj.specificity[i],CMatrixObj.f1_score[i],CMatrixObj.support[i]);
        }

      report += StringFormat("\n\nAccuracy\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t%.2f\n",CMatrixObj.accuracy);
      report += StringFormat("Average \t %.2f \t\t %.2f \t\t %.2f \t\t\t\t %.2f \t\t %.1f",CMatrixObj.avg[0],CMatrixObj.avg[1],CMatrixObj.avg[2],CMatrixObj.avg[3],CMatrixObj.avg[4]);
      report += StringFormat("\nW Avg \t\t\t %.2f \t\t %.2f \t\t %.2f \t\t\t\t %.2f \t\t %.1f",CMatrixObj.w_avg[0],CMatrixObj.w_avg[1],CMatrixObj.w_avg[2],CMatrixObj.w_avg[3],CMatrixObj.w_avg[4]);
      Print("Confusion Matrix\n",ConfMatrixVal);
      Print("\nClassification Report\n",report);
     }
   return CMatrixObj.accuracy;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
vector Classes(vector &v)
  {
   vector temp_t = v,v_classes = {v[0]};
   for(ulong i=0, count =1; i<v.Size(); i++)
     {
      for(ulong j=0; j<v.Size(); j++)
        {
         if(v[i] == temp_t[j] && temp_t[j] != -1000)
           {
            bool count_ready = false;
            for(ulong n=0; n<v_classes.Size(); n++)
               if(v[i] == v_classes[n])
                  count_ready = true;
            if(!count_ready)
              {
               count++;
               v_classes.Resize(count);
               v_classes[count-1] = v[i];
               temp_t[j] = -1000;
              }
            else
               break;
           }
         else
            continue;
        }
     }
   return v_classes;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
matrix OneHotEncoding(vector &v)
  {
   matrix mat = {};
   vector v_classes = Classes(v);
   mat.Resize(v.Size(),v_classes.Size());
   mat.Fill(-100);

   for(ulong i=0; i<mat.Rows(); i++)
     {
      for(ulong j=0; j<mat.Cols(); j++)
        {
         if(v[i]==v_classes[j])
            mat[i][j] = 1;
         else
            mat[i][j] = 0;
        }
     }
   return mat;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void BackPropagation()
  {
   matrix WeightsGradient = {},LossFxGradient(2,1),INPUT,OUTPUT= {},ONEHOT = OneHotEncoding(OutPutVector);
   vector SingleInputPredictionV,SingleInputActualV,BatchPredictions(MatrixRows),BatchActuals(MatrixRows),LossVector;
   double NNErrorLoss = 0,NNAccuracy = 0;
   BPDone = true;

   for(ulong epoch=0; epoch<Epochs&&!IsStopped(); epoch++)
     {
      for(ulong iter=0; iter<MatrixRows; iter++)
        {
         OUTPUT = SingleInputForwardPass(InputMatrix.Row(iter));
         SingleInputPredictionV = MatrixToVector(OUTPUT);
         SingleInputActualV = ONEHOT.Row(iter);
         INPUT = VectorToMatrix(InputMatrix.Row(iter));

         LossVector = SingleInputPredictionV.LossGradient(SingleInputActualV,ENUM_LOSS_FUNCTION(LossFx));
         LossFxGradient.Col(LossVector,0);
         OUTPUT.Derivative(OUTPUT,ENUM_ACTIVATION_FUNCTION(ActivationFx));
         OUTPUT = LossFxGradient*OUTPUT;

         WeightsGradient = OUTPUT.MatMul(INPUT.Transpose());
         Weights -= (LearningRate*WeightsGradient);
         Bias -= LearningRate * VectorToMatrix(LossVector);
        }
      BatchPredictions = BatchInputForwardPass(InputMatrix);
      BatchActuals = OutPutVector;

      NNErrorLoss = BatchPredictions.Loss(BatchActuals,ENUM_LOSS_FUNCTION(LossFx));
      NNAccuracy = ConfusionMatrix(BatchActuals,BatchPredictions,ClassesVector,epoch+1 == Epochs?true:false);
      NNErrorLoss = MathIsValidNumber(NNErrorLoss)?NNErrorLoss:1e6;
      NNAccuracy = MathIsValidNumber(NNAccuracy)?NNAccuracy:0.0;

      printf("[%d/%d] Loss = %.8f | accuracy %.3f",epoch+1,Epochs,NNErrorLoss,NNAccuracy);
     }
   BPDone = false;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void TrainModel()
  {
   CollectTrainingData();
   BackPropagation();
  }

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))
     {
      Print(__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;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NewSignal()
  {
   if(OldSignal!=Signal)
     {
      OldSignal = Signal;
      return true;
     }
   return false;
  }
//+------------------------------------------------------------------+