#include <Trade\Trade.mqh> 

#define NumNodes 20
CTrade trade;
CPositionInfo pos;
COrderInfo ord;

// Trading Parameters
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";    // Trade comment
input int MaxSpread = 100;                  // Maximum spread allowed (in points)
input int Slippage = 50;                    // Slippage in points
input int MaxOrders = 2;                    // Maximum simultaneous orders

input int BarsN = 5;                        // Bars to analyze
input int ExpirationBars = 100;             // Order expiration based on bars
input int OrderDistPoints = 100;            // Distance in points from price

// Neural Network Parameters
input double Coefficient = 0.1;
input double BuyTargetOutput = 0.3;
input double SellTargetOutput = -0.3;
input double LearningRate = 0.1;

double Weight[NumNodes];
double RSIBuffer[NumNodes];
double NormalizedInputs[NumNodes];
double NNOutPut = 0;


// License Validation Parameters
string LicenseUrl = "https://raw.githubusercontent.com/seu-usuario/licencas/main/licencas.txt"; // URL do arquivo de licenças
string LicenseKey = "sua-chave-unica"; // Chave de ativação fornecida ao cliente


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   trade.SetExpertMagicNumber(InpMagic);
   ChartSetInteger(0, CHART_SHOW_GRID, false);

   // Initialize Neural Network Weights
   for (int i = 0; i < NumNodes; i++)
      Weight[i] = 0.5;

   return (INIT_SUCCEEDED);
}




//+------------------------------------------------------------------+
//| Função de validação de licença                                   |
//+------------------------------------------------------------------+
bool ValidateLicense()
{
   char result[];     // Buffer para receber os dados
   string headers;    // Cabeçalhos HTTP (não utilizados aqui)
   int timeout = 10000; // Timeout de requisição em milissegundos

   // Faz requisição WebRequest
   int response_code = 0;
   string response = "";

   if (!WebRequest("GET", LicenseUrl, headers, timeout, NULL, 0, result, response_code))
   {
      Print("Erro ao realizar WebRequest: ", GetLastError());
      return false;
   }

   // Verifica o código HTTP da resposta
   if (response_code != 200)
   {
      Print("Erro: Código HTTP = ", response_code);
      return false;
   }

   // Divide o conteúdo recebido em linhas
   string linhas[];
   int total_linhas = StringSplit(CharArrayToString(result), '\n', linhas);

   // Verifica cada linha no arquivo de licenças
   for (int i = 0; i < total_linhas; i++)
   {
      string linha = linhas[i];
      if (StringLen(linha) == 0)
         continue; // Ignora linhas vazias

      // Divide a linha para extrair as informações
      string campos[];
      int total_campos = StringSplit(linha, ',', campos);

      if (total_campos < 4)
         continue; // Linha incompleta ou inválida

      // Extrai os campos
      long account_number = StringToLong(campos[0]);
      string broker_name = campos[1];
      string activation_key = campos[2];
      datetime expiration_date = StringToTime(campos[3]);

      // Verifica se os dados batem
      if (account_number == AccountInfoInteger(ACCOUNT_LOGIN) &&
          broker_name == AccountInfoString(ACCOUNT_COMPANY) &&
          activation_key == LicenseKey &&
          TimeCurrent() <= expiration_date)
      {
         Print("Licença validada com sucesso!");
         return true;
      }
   }

   // Se nenhuma linha foi válida, licença é inválida
   Print("Licença inválida ou não encontrada.");
   return false;
}



//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Run TrailStop logic
   TrailStop();

   // Check if parameters have changed
   if (CheckForParameterUpdates())
   {
      // Recalculate points of negotiation
      AdjustPointsOfNegotiation();
   }

   // Check for new bar and exit if not
   if (!IsNewBar())
      return;

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

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

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

   // Ensure order limit
   int TotalOrders = BuyTotal + SellTotal;
   if (TotalOrders >= MaxOrders)
      return;

   // Neural network prediction
   NormalizingInputs();
   OutPutLayerCalculation();

   // Determine Buy and Sell Signals
   bool buySignal = (BuyTotal == 0 && NNOutPut > 0); // Neural Buy Signal
   bool sellSignal = (SellTotal == 0 && NNOutPut < 0); // Neural Sell Signal

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

   if (sellSignal)
   {
      double low = findLow();
      if (low > 0)
         SendSellOrder(low);
   }
}

//+------------------------------------------------------------------+
//| Order Sending Logic                                              |
//+------------------------------------------------------------------+
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;

    trade.BuyStop(LotSize, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, iTime(_Symbol, Timeframe, 0) + ExpirationBars * PeriodSeconds(Timeframe), 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;

    trade.SellStop(LotSize, entry, _Symbol, sl, tp, ORDER_TIME_SPECIFIED, iTime(_Symbol, Timeframe, 0) + ExpirationBars * PeriodSeconds(Timeframe), Slippage);
}

//+------------------------------------------------------------------+
//| Neural Network Functions                                         |
//+------------------------------------------------------------------+
void NormalizingInputs()
{
    double LowerNormRange = -1;
    double UpperNormRange = 1;

    for (int i = 0; i < NumNodes; i++)
    {
        NormalizedInputs[i] = (((RSIBuffer[i] - 0) * (UpperNormRange - LowerNormRange)) / (100 - 0)) + LowerNormRange;
    }
}

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

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

//+------------------------------------------------------------------+
//| Is New Bar Function                                              |
//+------------------------------------------------------------------+
bool IsNewBar()
{
    static datetime previousTime = 0;
    datetime currentTime = iTime(_Symbol, Timeframe, 0);
    if (previousTime != currentTime)
    {
        previousTime = currentTime;
        return true;
    }
    return false;
}

//+------------------------------------------------------------------+
//| Trailing Stop                                                    |
//+------------------------------------------------------------------+
void TrailStop()
{
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    for (int i = PositionsTotal() - 1; i >= 0; i--)
    {
        if (pos.SelectByIndex(i) && pos.Magic() == InpMagic && pos.Symbol() == _Symbol)
        {
            double sl = 0;
            double tp = pos.TakeProfit();
            if (pos.PositionType() == POSITION_TYPE_BUY)
            {
                if (bid - pos.PriceOpen() >= TslTriggerPoints * _Point)
                {
                    sl = bid - TslPoints * _Point;
                    if (sl > pos.StopLoss() || pos.StopLoss() == 0)
                        trade.PositionModify(pos.Ticket(), sl, tp);
                }
            }
            if (pos.PositionType() == POSITION_TYPE_SELL)
            {
                if (pos.PriceOpen() - ask >= TslTriggerPoints * _Point)
                {
                    sl = ask + TslPoints * _Point;
                    if (sl < pos.StopLoss() || pos.StopLoss() == 0)
                        trade.PositionModify(pos.Ticket(), sl, tp);
                }
            }
        }
    }
}

//+------------------------------------------------------------------+
//| High and Low Search                                              |
//+------------------------------------------------------------------+
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;
      }
   }
   return -1;
}

//+------------------------------------------------------------------+
//| Parameter Update Functions                                       |
//+------------------------------------------------------------------+
// Function to check if the trading parameters have been updated
bool CheckForParameterUpdates()
{
    static double prevLotSize = LotSize;
    static int prevTppoints = Tppoints;
    static int prevSlpoints = Slpoints;
    
    if (prevLotSize != LotSize || prevTppoints != Tppoints || prevSlpoints != Slpoints)
    {
        prevLotSize = LotSize;
        prevTppoints = Tppoints;
        prevSlpoints = Slpoints;
        return true;
    }
    return false;
}

// Function to adjust points of negotiation when parameters are updated
void AdjustPointsOfNegotiation()
{
    // Recalcular e reatribuir valores que dependem dos parâmetros atualizados
    // Por exemplo, ajustando trailing stop ou atualizando parâmetros de ordens

    for (int i = 0; i < NumNodes; i++)
    {
        // Recalcular pesos ou outros parâmetros, se necessário
        Weight[i] = 0.5 * Coefficient; // Exemplo de ajuste, pode ser personalizado
    }

    // Imprimir mensagem no log para indicar que os parâmetros foram ajustados
    Print("Parâmetros atualizados e pontos de negociação ajustados.");
}


erros:
'WebRequest' - no one of the overloads can be applied to the function call	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	76	9
could be one of 2 function(s)	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	76	9
   built-in: int WebRequest(const string,const string,const string,const string,int,const char&[],int,char&[],string&)	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	76	9
   built-in: int WebRequest(const string,const string,const string,int,const char&[],char&[],string&)	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	76	9
'StringToLong' - undeclared identifier	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	108	29
'[' - some operator expected	Scalping_GOLD__008_20NEURALs_Cliente001_Teste.mq5	108	48