//+------------------------------------------------------------------+
//|                                                RedFairy v1.4.mq5 |
//|                 Integrando RSI e MACD com Redes Neurais          |
//|                                                       Joy D Moyo |
//|                                               www.latvianfts.com |
//+------------------------------------------------------------------+
#property copyright "Joy D Moyo"
#property link      "www.latvianfts.com"
#property version   "1.4"

#include <Trade\Trade.mqh>

#define NumNodes 10      // Número de nodos na rede neural

CTrade *Trade;
CPositionInfo PositionInfo;

input group "GENERAL INPUTS"
input string SymbolTraded = "EURUSD";
input ENUM_TIMEFRAMES PeriodTraded = PERIOD_M5;
input int EAMagic = 76755544;
input int MaxSlippage = 1;

input group "RSI INPUTS"
input int RSIPeriod = 14;
input ENUM_APPLIED_PRICE RSIAppliedPrice = PRICE_CLOSE;
input int OSLevel = 30;        // Zona sobrevendida
input int OBLevel = 70;        // Zona sobrecomprada
input int BuyCloseLevel = 60;  // Fechar trades de compra acima desse nível
input int SellCloseLevel = 40; // Fechar trades de venda abaixo desse nível

input group "MACD INPUTS"
input int FastEMA = 12;         // Período da EMA rápida
input int SlowEMA = 26;         // Período da EMA lenta
input int SignalSMA = 9;        // Período da linha de sinal
input ENUM_APPLIED_PRICE MACDAppliedPrice = PRICE_CLOSE;

input group "TRADE MANAGEMENT INPUTS"
input bool UseCostAveraging = false;
input double LotMultiplier = 2;
input double GridDistance = 20;

input group "RISK INPUTS"
input double BalanceIncrease = 200;
input double VolumeIncrease = 0.01;

input group "NEURAL NETWORK INPUTS"
input double Coefficient = 0.1;
input double BuyTargetOutput = 0.3;
input double SellTargetOutput = -0.3;
input double LearningRate = 0.1;

int RSIHandle, MACDHandle, OldNumBars = 0, MyDigits;
double RSIBuffer[], MACDBuffer[], SignalBuffer[], MyPoint, NormalizedInputs[NumNodes], NNOutPut, NextBuyPrice = 0, NextSellPrice = 0, NextBuyLot = 0, NextSellLot = 0, GridDistancePoints;
double Weight[];
int DataUsed = NumNodes;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Configuração visual do gráfico
   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_CANDLE_BULL, clrWhite);
   ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrRed);

   // Inicializa a classe de negociação
   Trade = new CTrade;
   ulong MaxSlippagePoints = MaxSlippage * 10;
   Trade.SetDeviationInPoints(MaxSlippagePoints);
   Trade.SetExpertMagicNumber(EAMagic);

   // Configura os pesos iniciais da rede neural
   ArrayResize(Weight, NumNodes);
   for (int i = 0; i < NumNodes; i++)
      Weight[i] = 0.5;

   // Configura informações do ativo
   MyPoint = SymbolInfoDouble(SymbolTraded, SYMBOL_POINT);
   MyDigits = (int)SymbolInfoInteger(SymbolTraded, SYMBOL_DIGITS);
   GridDistancePoints = GridDistance * 10 * MyPoint;

   // Inicializa os indicadores RSI e MACD
   RSIHandle = iRSI(SymbolTraded, PeriodTraded, RSIPeriod, RSIAppliedPrice);
   MACDHandle = iMACD(SymbolTraded, PeriodTraded, FastEMA, SlowEMA, SignalSMA, MACDAppliedPrice);
   ArraySetAsSeries(RSIBuffer, true);
   ArraySetAsSeries(MACDBuffer, true);
   ArraySetAsSeries(SignalBuffer, true);

   return (INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(RSIHandle);
   IndicatorRelease(MACDHandle);
   delete Trade;
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if (!NewBarPresent()) return;

   // Atualiza os dados do RSI
   CopyBuffer(RSIHandle, 0, 0, DataUsed, RSIBuffer);

   // Atualiza os dados do MACD
   if (CopyBuffer(MACDHandle, 0, 0, DataUsed, MACDBuffer) <= 0 ||
       CopyBuffer(MACDHandle, 1, 0, DataUsed, SignalBuffer) <= 0)
   {
      Print("Erro ao carregar buffers do MACD: ", GetLastError());
      return;
   }

   // Normaliza os inputs para uso na rede neural
   NormalizingInputs();
   OutPutLayerCalculation();

   double TargetOutPut = 0;

   // Definição do output alvo com base nos valores do RSI
   if (RSIBuffer[1] >= 50)
      TargetOutPut = BuyTargetOutput;
   else if (RSIBuffer[1] < 50)
      TargetOutPut = SellTargetOutput;

   // Treinamento da rede neural (BackPropagation)
   BackPropagation(NormalizedInputs, Weight, NNOutPut, TargetOutPut, LearningRate);

   // Realiza operações de compra/venda com a confluência entre RSI, MACD e NN
   if (BuySignal())
      Buy();

   if (SellSignal())
      Sell();

   if (UseCostAveraging)
   {
      GridBuy();
      GridSell();
   }

   // Fecha trades desatualizados
   CloseMatureTrades();

   // Comentário no gráfico para debug
   Comment("Peso 1: ", Weight[0], "\nPeso 2: ", Weight[1], "\nNN Output: ", NNOutPut);
  }

//+------------------------------------------------------------------+
//| Função para verificar nova barra                                 |
//+------------------------------------------------------------------+
bool NewBarPresent()
  {
   int bars = Bars(SymbolTraded, PeriodTraded);
   if (OldNumBars != bars)
   {
      OldNumBars = bars;
      return true;
   }
   return false;
  }

//+------------------------------------------------------------------+
//| Funções de sinais (BuySignal e SellSignal)                      |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   if (RSIBuffer[1] >= OSLevel && RSIBuffer[2] < OSLevel && MACDBuffer[1] > SignalBuffer[1] && NNOutPut > 0)
      return true;
   return false;
  }

bool SellSignal()
  {
   if (RSIBuffer[1] <= OBLevel && RSIBuffer[2] > OBLevel && MACDBuffer[1] < SignalBuffer[1] && NNOutPut < 0)
      return true;
   return false;
  }

//+------------------------------------------------------------------+
//| Normalização dos dados do RSI e MACD                            |
//+------------------------------------------------------------------+
void NormalizingInputs()
  {
   double LowerNormRange = -1;  // Faixa de normalização
   double UpperNormRange = 1;   // Faixa de normalização
   double MinRSI = RSIBuffer[ArrayMinimum(RSIBuffer)];
   double MaxRSI = RSIBuffer[ArrayMaximum(RSIBuffer)];
   double MinMACD = MACDBuffer[ArrayMinimum(MACDBuffer)];
   double MaxMACD = MACDBuffer[ArrayMaximum(MACDBuffer)];
   double MinSignal = SignalBuffer[ArrayMinimum(SignalBuffer)];
   double MaxSignal = SignalBuffer[ArrayMaximum(SignalBuffer)];

   // Normaliza o RSI
   for (int i = 0; i < DataUsed / 3; i++)
      NormalizedInputs[i] = (((RSIBuffer[i] - MinRSI) * (UpperNormRange - LowerNormRange)) / (MaxRSI - MinRSI)) + LowerNormRange;

   // Normaliza o MACD
   for (int i = DataUsed / 3; i < 2 * DataUsed / 3; i++)
      NormalizedInputs[i] = (((MACDBuffer[i - DataUsed / 3] - MinMACD) * (UpperNormRange - LowerNormRange)) / (MaxMACD - MinMACD)) + LowerNormRange;

   // Normaliza a linha de sinal do MACD
   for (int i = 2 * DataUsed / 3; i < DataUsed; i++)
      NormalizedInputs[i] = (((SignalBuffer[i - 2 * DataUsed / 3] - MinSignal) * (UpperNormRange - LowerNormRange)) / (MaxSignal - MinSignal)) + LowerNormRange;
  }

//+------------------------------------------------------------------+
//| Funções auxiliares para usar a rede neural                      |
//+------------------------------------------------------------------+
double HiddenLayerCalculation(double &inputs[], double &Weights[])
  {
   double TotalWeightedInputs = 0.0;
   for (int i = 0; i < ArraySize(inputs); i++)
      TotalWeightedInputs += inputs[i] * Weights[i];

   TotalWeightedInputs *= Coefficient;
   return TanHActivationFunction(TotalWeightedInputs);
  }

double TanHActivationFunction(double WeightedInputs)
  {
   return ((exp(WeightedInputs) - exp(-WeightedInputs)) / (exp(WeightedInputs) + exp(-WeightedInputs)));
  }

void OutPutLayerCalculation()
  {
   NNOutPut = HiddenLayerCalculation(NormalizedInputs, Weight);
  }

void BackPropagation(double &Inputs[], double &Weights[], double &Outputs, double TargetOutputs, double LearningRates)
  {
   double error = TargetOutputs - Outputs;
   double derivative = 1 - MathPow(Outputs, 2); // Derivada da função Tangente Hiperbólica
   for (int i = 0; i < ArraySize(Inputs); i++)
   {
      double gradient = error * derivative * Inputs[i];
      Weights[i] += LearningRates * gradient;
   }
  }

//+------------------------------------------------------------------+
//| Gestão de ordens                                                |
//+------------------------------------------------------------------+
void Buy()
  {
   if (!BuySignal())
      return;

   double LotUsed = LotSize();
   double ASK = SymbolInfoDouble(SymbolTraded, SYMBOL_ASK);
   if (!Trade.Buy(LotUsed, SymbolTraded, ASK, 0, 0, "FirstBuy"))
   {
      Print("Failed First Buy: ", GetLastError());
   }
   else
   {
      NextBuyLot = NormalizeDouble(LotUsed * LotMultiplier, 2);
      NextBuyPrice = NormalizeDouble(ASK - GridDistancePoints, MyDigits);
   }
  }

void Sell()
  {
   if (!SellSignal())
      return;

   double LotUsed = LotSize();
   double BID = SymbolInfoDouble(SymbolTraded, SYMBOL_BID);
   if (!Trade.Sell(LotUsed, SymbolTraded, BID, 0, 0, "FirstSell"))
   {
      Print("Failed First Sell: ", GetLastError());
   }
   else
   {
      NextSellLot = NormalizeDouble(LotUsed * LotMultiplier, 2);
      NextSellPrice = NormalizeDouble(BID + GridDistancePoints, MyDigits);
   }
  }

void GridBuy()
  {
   double ASK = SymbolInfoDouble(SymbolTraded, SYMBOL_ASK);
   if (NumOfBuy() > 0 && ASK < NextBuyPrice)
   {
      if (!Trade.Buy(NextBuyLot, SymbolTraded, ASK, 0, 0, "GridBuy"))
      {
         Print("Failed Grid Buy: ", GetLastError());
      }
      else
      {
         NextBuyLot = NormalizeDouble(NextBuyLot * LotMultiplier, 2);
         NextBuyPrice = NormalizeDouble(ASK - GridDistancePoints, MyDigits);
      }
   }
  }

void GridSell()
  {
   double BID = SymbolInfoDouble(SymbolTraded, SYMBOL_BID);
   if (NumOfSell() > 0 && BID > NextSellPrice)
   {
      if (!Trade.Sell(NextSellLot, SymbolTraded, BID, 0, 0, "GridSell"))
      {
         Print("Failed Grid Sell: ", GetLastError());
      }
      else
      {
         NextSellLot = NormalizeDouble(NextSellLot * LotMultiplier, 2);
         NextSellPrice = NormalizeDouble(BID + GridDistancePoints, MyDigits);
      }
   }
  }

void CloseAllBuys()
  {
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (!PositionInfo.SelectByIndex(i))
         continue;

      if (PositionInfo.Magic() != EAMagic)
         continue;

      if (PositionInfo.Symbol() != SymbolTraded)
         continue;

      if (PositionInfo.PositionType() != POSITION_TYPE_BUY)
         continue;

      if (!Trade.PositionClose(PositionGetInteger(POSITION_TICKET)))
         Print("Failed to close buy position: ", GetLastError());
   }
  }

void CloseAllSells()
  {
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (!PositionInfo.SelectByIndex(i))
         continue;

      if (PositionInfo.Magic() != EAMagic)
         continue;

      if (PositionInfo.Symbol() != SymbolTraded)
         continue;

      if (PositionInfo.PositionType() != POSITION_TYPE_SELL)
         continue;

      if (!Trade.PositionClose(PositionGetInteger(POSITION_TICKET)))
         Print("Failed to close sell position: ", GetLastError());
   }
  }

void CloseMatureTrades()
  {
   if (NumOfBuy() > 0 && RSIBuffer[1] > BuyCloseLevel && RSIBuffer[2] < BuyCloseLevel)
   {
      CloseAllBuys();
      NextBuyPrice = 0;
      NextBuyLot = 0;
   }

   if (NumOfSell() > 0 && RSIBuffer[1] < SellCloseLevel && RSIBuffer[2] > SellCloseLevel)
   {
      CloseAllSells();
      NextSellLot = 0;
      NextSellPrice = 0;
   }
  }

//+------------------------------------------------------------------+
//| Gerenciamento de lote                                           |
//+------------------------------------------------------------------+
double LotSize()
  {
   double Lot = NormalizeDouble(VolumeIncrease * AccountInfoDouble(ACCOUNT_BALANCE) / BalanceIncrease, 2);
   if (Lot > SymbolInfoDouble(SymbolTraded, SYMBOL_VOLUME_MAX))
      Lot = SymbolInfoDouble(SymbolTraded, SYMBOL_VOLUME_MAX);
   if (Lot < SymbolInfoDouble(SymbolTraded, SYMBOL_VOLUME_MIN))
      Lot = SymbolInfoDouble(SymbolTraded, SYMBOL_VOLUME_MIN);
   return Lot;
  }

//+------------------------------------------------------------------+
//| Contagem de posições                                            |
//+------------------------------------------------------------------+
int NumOfBuy()
  {
   int Num = 0;
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (!PositionInfo.SelectByIndex(i))
         continue;

      if (PositionInfo.Magic() != EAMagic)
         continue;

      if (PositionInfo.Symbol() != SymbolTraded)
         continue;

      if (PositionInfo.PositionType() != POSITION_TYPE_BUY)
         continue;

      Num++;
   }
   return Num;
  }

int NumOfSell()
  {
   int Num = 0;
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (!PositionInfo.SelectByIndex(i))
         continue;

      if (PositionInfo.Magic() != EAMagic)
         continue;

      if (PositionInfo.Symbol() != SymbolTraded)
         continue;

      if (PositionInfo.PositionType() != POSITION_TYPE_SELL)
         continue;

      Num++;
   }
   return Num;
  }


coloque um trailing stop de 10 pontos no codigo para garantir os lucros caso preço volte e um take de pelo menos 35 pontos para gold