Minha automação nao compila erro mas nao abre entrada

MQL5 지표 전문가

명시

//+------------------------------------------------------------------+
//|            BEMTEVI_Confluencia_Scalper_v3.2_Corrigido_Final.mq5  |
//|       Robô scalper com confluência de múltiplos fatores          |
//|                       (Suporta Compra e Venda)                   |
//+------------------------------------------------------------------+
#property copyright "OpenAI & Google Gemini"
#property link      "https://openai.com"
#property version   "3.20" // Versão incrementada após correções finais
#property strict
#property description "Scalper EA based on confluence of 10 factors. Supports Buy and Sell."
#property description "Improvements: Sell logic, refined factors, more input parameters, Magic Number. Compilation fixes."

#include <Trade\Trade.mqh>

CTrade trade;

//--- Constantes
#define CONFLUENCE_FACTORS_COUNT 10 // Número total de fatores de confluência usados

//--- Inputs Configuráveis
input group "Gerenciamento de Risco e Trade"
input double RiskPercent         = 1.0;       // Risco por operação (% da conta)
input int    MaxTotalTrades      = 3;         // Máximo de trades totais simultâneos na conta
input double TP_Points           = 15.0;      // Take Profit em pontos
input double SL_Points           = 10.0;      // Stop Loss em pontos

input group "Trailing Stop"
input bool   EnableTrailingStop  = true;      // Habilita trailing stop
input double TrailingStartPoints = 8.0;       // Início do trailing stop (pontos de lucro)
input double TrailingStepPoints  = 3.0;       // Passo do trailing stop (pontos)

input group "Configurações Gerais do EA"
input ENUM_TIMEFRAMES Timeframe_EA = PERIOD_M1;   // Timeframe para cálculo dos sinais
input double ConfluenceThreshold = 0.80;      // % de confluência para abrir ordem (ex: 0.7 para 70%)
input long   MagicNumber         = 12345;     // Número mágico para as ordens do EA
input int    TradeStartTimeHour  = 8;         // Hora de início para operar (0-23)
input int    TradeEndTimeHour    = 18;        // Hora de fim para operar (0-23) (ex: 18 para até 18:59)

input group "Fator 1: RSI"
input int    RSI_Period          = 14;
input double RSI_OversoldLevel   = 30.0;
input double RSI_OverboughtLevel = 70.0;

input group "Fator 2: Momentum"
input int    Momentum_Period     = 5;

input group "Fator 3: MACD"
input int    MACD_FastEMA        = 12;
input int    MACD_SlowEMA        = 26;
input int    MACD_SignalSMA      = 9;

input group "Fator 4: Bandas de Bollinger"
input int    Bollinger_Period    = 20;
input double Bollinger_Deviation   = 2.0;
input double Bollinger_Proximity_Percent = 0.05; // Proximidade em % (ex: 0.05 para 0.05%)

input group "Fator 5: Padrão de Candle (Engolfo)"
// Nenhum parâmetro extra, usa OCHL das últimas velas

input group "Fator 6: Volume"
input int    Volume_AvgPeriod    = 20;

input group "Fator 7: ADX"
input int    ADX_Period          = 14;
input double ADX_MinLevel        = 25.0;      // Nível mínimo do ADX para indicar força da tendência

input group "Fator 8: Cruzamento de Médias Móveis"
input int    MA_Fast_Period      = 7;
input int    MA_Slow_Period      = 21;
input ENUM_MA_METHOD MA_Method   = MODE_SMA;

input group "Fator 9: Estocástico"
input int    Stochastic_KPeriod  = 5;
input int    Stochastic_DPeriod  = 3;
input int    Stochastic_Slowing  = 3;
input double Stochastic_OversoldLevel   = 20.0;
input double Stochastic_OverboughtLevel = 80.0;

input group "Fator 10: Suporte e Resistência (Baseado na Vela Anterior)"
input double SR_Proximity_Points = 5.0;       // Proximidade em pontos do S/R

//--- Variáveis Globais
double InitialBalance;
string ea_comment_prefix;

//+------------------------------------------------------------------+
//| Função auxiliar para calcular dígitos do volume                  |
//+------------------------------------------------------------------+
int CalculateVolumeDigits(string symbol)
{
  double volume_step = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
  if(volume_step <= 0) return 2; // Default

  string s_step = DoubleToString(volume_step, 8); // Use up to 8 decimal places for accuracy
  int dot_pos = StringFind(s_step, ".");

  if(dot_pos < 0) return 0; // No decimal part (e.g., step is 1)

  // Remove trailing zeros after the decimal point for correct length calculation
  int len = StringLen(s_step);
  while(len > dot_pos + 1 && StringGetCharacter(s_step, len - 1) == '0')
  {
    len--;
  }
  return len - dot_pos - 1;
}

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
  InitialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
  trade.SetExpertMagicNumber(MagicNumber);
  trade.SetMarginMode();

  ea_comment_prefix = "[BEMTEVI_v3.2 M:" + (string)MagicNumber + "]"; // Version updated in prefix
  Print(ea_comment_prefix, " EA scalper iniciado com confluência. Timeframe Sinais: ", EnumToString(Timeframe_EA));
  Print(ea_comment_prefix, " Limite Confluência: ", ConfluenceThreshold * 100, "%. Risk: ", RiskPercent, "%");

  if(SL_Points <= 0)
  {
    Print(ea_comment_prefix, " ERRO: SL_Points deve ser maior que zero! EA não irá operar.");
    return(INIT_FAILED);
  }

  CreateInfoPanel();
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  ObjectDelete(0, "info_panel_" + (string)MagicNumber);
  Print(ea_comment_prefix, " EA finalizado. Razão: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
  UpdateInfoPanel();

  if(PositionsTotal() >= MaxTotalTrades)
    return;

  if(!IsTradeAllowedByTime())
    return;

  if(CountEAPositionsThisSymbol() > 0)
    return;

  double buy_confluence_score = 0;
  int    buy_factors_agree = 0;
  CalculateConfluenceFactors(ORDER_TYPE_BUY, buy_confluence_score, buy_factors_agree);
  double buy_confluence_percent = (CONFLUENCE_FACTORS_COUNT > 0) ? buy_confluence_score / CONFLUENCE_FACTORS_COUNT : 0;

  double sell_confluence_score = 0;
  int    sell_factors_agree = 0;
  CalculateConfluenceFactors(ORDER_TYPE_SELL, sell_confluence_score, sell_factors_agree);
  double sell_confluence_percent = (CONFLUENCE_FACTORS_COUNT > 0) ? sell_confluence_score / CONFLUENCE_FACTORS_COUNT : 0;

  string comment_text = StringFormat("%s Buy:%.0f%%(%d/%d) | Sell:%.0f%%(%d/%d)",
                                   ea_comment_prefix,
                                   buy_confluence_percent * 100, buy_factors_agree, CONFLUENCE_FACTORS_COUNT,
                                   sell_confluence_percent * 100, sell_factors_agree, CONFLUENCE_FACTORS_COUNT);
  Comment(comment_text);

  ENUM_ORDER_TYPE trade_direction = WRONG_VALUE;

  if(buy_confluence_percent >= ConfluenceThreshold && buy_confluence_percent > sell_confluence_percent)
  {
    trade_direction = ORDER_TYPE_BUY;
  }
  else if(sell_confluence_percent >= ConfluenceThreshold && sell_confluence_percent > buy_confluence_percent)
  {
    trade_direction = ORDER_TYPE_SELL;
  }

  if(trade_direction != WRONG_VALUE)
  {
    double lot = CalculateLotSize(trade_direction);
    if(lot > 0)
    {
      ExecuteTrade(lot, trade_direction);
    }
  }

  if(EnableTrailingStop)
    ApplyTrailingStopToPositions();
}

//+------------------------------------------------------------------+
//| Calcula a confluência para uma direção específica              |
//+------------------------------------------------------------------+
void CalculateConfluenceFactors(ENUM_ORDER_TYPE direction, double &total_score, int &factors_agree_count)
{
  total_score = 0;
  factors_agree_count = 0;
  int factor_result = 0;

  factor_result = Factor_RSI(direction);              total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_Momentum(direction);         total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_MACD(direction);             total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_Bollinger(direction);        total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_CandlePattern(direction);    total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_Volume();                    total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_ADX();                       total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_MA_Cross(direction);         total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_Stochastic(direction);       total_score += factor_result; if(factor_result==1) factors_agree_count++;
  factor_result = Factor_SupportResistance(direction);total_score += factor_result; if(factor_result==1) factors_agree_count++;
}

//--- Funções de Fator Individuais (retornam 1 se sinal favorável, 0 se não)

int Factor_RSI(ENUM_ORDER_TYPE direction)
{
  double rsi_buffer[];
  long rsi_handle = iRSI(_Symbol, Timeframe_EA, RSI_Period, PRICE_CLOSE);
  if(rsi_handle == INVALID_HANDLE) return 0;
  if(CopyBuffer((int)rsi_handle, 0, 0, 1, rsi_buffer) <= 0) return 0;
  double rsi_value = rsi_buffer[0];

  if(direction == ORDER_TYPE_BUY && rsi_value < RSI_OversoldLevel) return 1;
  if(direction == ORDER_TYPE_SELL && rsi_value > RSI_OverboughtLevel) return 1;
  return 0;
}

int Factor_Momentum(ENUM_ORDER_TYPE direction)
{
  double priceNow = iClose(_Symbol, Timeframe_EA, 0);
  double pricePast = iClose(_Symbol, Timeframe_EA, Momentum_Period);
  if(pricePast == 0) return 0;

  if(direction == ORDER_TYPE_BUY && priceNow > pricePast) return 1;
  if(direction == ORDER_TYPE_SELL && priceNow < pricePast) return 1;
  return 0;
}

int Factor_MACD(ENUM_ORDER_TYPE direction)
{
  double macdMain[], macdSignal[];
  long macd_handle = iMACD(_Symbol, Timeframe_EA, MACD_FastEMA, MACD_SlowEMA, MACD_SignalSMA, PRICE_CLOSE);
  if(macd_handle == INVALID_HANDLE) return 0;

  if(CopyBuffer((int)macd_handle, 0, 0, 1, macdMain) <= 0 ||
     CopyBuffer((int)macd_handle, 1, 0, 1, macdSignal) <= 0) return 0;

  if(direction == ORDER_TYPE_BUY && macdMain[0] > macdSignal[0]) return 1;
  if(direction == ORDER_TYPE_SELL && macdMain[0] < macdSignal[0]) return 1;
  return 0;
}

int Factor_Bollinger(ENUM_ORDER_TYPE direction)
{
  double bbUpper[], bbLower[];
  long bands_handle = iBands(_Symbol, Timeframe_EA, Bollinger_Period, 0, Bollinger_Deviation, PRICE_CLOSE);
  if(bands_handle == INVALID_HANDLE) return 0;

  if(CopyBuffer((int)bands_handle, 1, 0, 1, bbUpper) <= 0 ||
     CopyBuffer((int)bands_handle, 2, 0, 1, bbLower) <= 0)
    return 0;

  double price = (direction == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
  double proximity_factor_lower = 1.0 + (Bollinger_Proximity_Percent / 100.0);
  double proximity_factor_upper = 1.0 - (Bollinger_Proximity_Percent / 100.0);


  if(direction == ORDER_TYPE_BUY && price <= bbLower[0] * proximity_factor_lower) return 1;
  if(direction == ORDER_TYPE_SELL && price >= bbUpper[0] * proximity_factor_upper) return 1;
  return 0;
}

int Factor_CandlePattern(ENUM_ORDER_TYPE direction)
{
  if(direction == ORDER_TYPE_BUY) return Factor_BullishEngulfing();
  if(direction == ORDER_TYPE_SELL) return Factor_BearishEngulfing();
  return 0;
}

int Factor_BullishEngulfing()
{
  double open1 = iOpen(_Symbol, Timeframe_EA, 1);
  double close1 = iClose(_Symbol, Timeframe_EA, 1);
  double open2 = iOpen(_Symbol, Timeframe_EA, 2);
  double close2 = iClose(_Symbol, Timeframe_EA, 2);

  if(close2 < open2 && close1 > open1 && close1 > open2 && open1 < close2)
    return 1;
  return 0;
}

int Factor_BearishEngulfing()
{
  double open1 = iOpen(_Symbol, Timeframe_EA, 1);
  double close1 = iClose(_Symbol, Timeframe_EA, 1);
  double open2 = iOpen(_Symbol, Timeframe_EA, 2);
  double close2 = iClose(_Symbol, Timeframe_EA, 2);

  if(close2 > open2 && close1 < open1 && close1 < open2 && open1 > close2)
    return 1;
  return 0;
}

int Factor_Volume()
{
  MqlRates rates_data[];
  int rates_to_copy = Volume_AvgPeriod + 1;

  if(CopyRates(_Symbol, Timeframe_EA, 0, rates_to_copy, rates_data) < rates_to_copy)
  {
    return 0;
  }

  double current_volume = (double)rates_data[0].tick_volume;
  double sum_previous_volumes = 0;

  if(Volume_AvgPeriod == 0) return (current_volume > 0) ? 1 : 0;

  for(int i = 1; i <= Volume_AvgPeriod; i++) // Sums volumes from index 1 to Volume_AvgPeriod
  {
    // Ensure we don't go out of bounds if rates_data has fewer elements than expected
    if(i < rates_to_copy) // rates_data has rates_to_copy elements (0 to rates_to_copy-1)
    {
       sum_previous_volumes += (double)rates_data[i].tick_volume;
    }
    else break; // Should not happen if CopyRates worked as expected
  }
  
  if (Volume_AvgPeriod == 0) return (current_volume > 0) ? 1 : 0; // Avoid division by zero

  double average_previous_volume = sum_previous_volumes / Volume_AvgPeriod;

  if(current_volume > average_previous_volume && average_previous_volume > 0)
  {
    return 1;
  }
  return 0;
}


int Factor_ADX()
{
  double adxBuffer[];
  long adx_handle = iADX(_Symbol, Timeframe_EA, ADX_Period);
  if(adx_handle == INVALID_HANDLE) return 0;

  if(CopyBuffer((int)adx_handle, 0, 0, 1, adxBuffer) <= 0) return 0;

  if(adxBuffer[0] > ADX_MinLevel) return 1;
  return 0;
}

int Factor_MA_Cross(ENUM_ORDER_TYPE direction)
{
  double maFastNow_arr[], maSlowNow_arr[], maFastPrev_arr[], maSlowPrev_arr[];
  ArrayResize(maFastNow_arr, 1); ArrayResize(maSlowNow_arr, 1);
  ArrayResize(maFastPrev_arr,1); ArrayResize(maSlowPrev_arr,1);

  long maFast_handle = iMA(_Symbol, Timeframe_EA, MA_Fast_Period, 0, MA_Method, PRICE_CLOSE);
  long maSlow_handle = iMA(_Symbol, Timeframe_EA, MA_Slow_Period, 0, MA_Method, PRICE_CLOSE);

  if(maFast_handle == INVALID_HANDLE || maSlow_handle == INVALID_HANDLE) return 0;

  // Get current values (shift 0)
  if(CopyBuffer((int)maFast_handle, 0, 0, 1, maFastNow_arr) <= 0 || CopyBuffer((int)maSlow_handle, 0, 0, 1, maSlowNow_arr) <= 0) return 0;
  // Get previous values (shift 1)
  if(CopyBuffer((int)maFast_handle, 0, 1, 1, maFastPrev_arr) <= 0 || CopyBuffer((int)maSlow_handle, 0, 1, 1, maSlowPrev_arr) <= 0) return 0;

  double maFastNow  = maFastNow_arr[0];
  double maSlowNow  = maSlowNow_arr[0];
  double maFastPrev = maFastPrev_arr[0];
  double maSlowPrev = maSlowPrev_arr[0];

  if(maFastNow == 0 || maSlowNow == 0 || maFastPrev == 0 || maSlowPrev == 0) return 0;

  if(direction == ORDER_TYPE_BUY && maFastNow > maSlowNow && maFastPrev <= maSlowPrev) return 1;
  if(direction == ORDER_TYPE_SELL && maFastNow < maSlowNow && maFastPrev >= maSlowPrev) return 1;
  return 0;
}

int Factor_Stochastic(ENUM_ORDER_TYPE direction)
{
  double k_buff[], d_buff[];
  long stoch_handle = iStochastic(_Symbol, Timeframe_EA, Stochastic_KPeriod, Stochastic_DPeriod, Stochastic_Slowing, MODE_SMA, STO_LOWHIGH);
  if(stoch_handle == INVALID_HANDLE) return 0;

  if(CopyBuffer((int)stoch_handle, 0, 0, 1, k_buff) <= 0 ||
     CopyBuffer((int)stoch_handle, 1, 0, 1, d_buff) <= 0)
    return 0;

  if(direction == ORDER_TYPE_BUY && k_buff[0] < Stochastic_OversoldLevel && d_buff[0] < Stochastic_OversoldLevel) return 1;
  if(direction == ORDER_TYPE_SELL && k_buff[0] > Stochastic_OverboughtLevel && d_buff[0] > Stochastic_OverboughtLevel) return 1;
  return 0;
}

int Factor_SupportResistance(ENUM_ORDER_TYPE direction)
{
  double prev_low   = iLow(_Symbol, Timeframe_EA, 1);
  double prev_high  = iHigh(_Symbol, Timeframe_EA, 1);
  double price_ask  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
  double price_bid  = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  double point_val  = _Point;

  if(prev_low == 0 || prev_high == 0) return 0;

  if(direction == ORDER_TYPE_BUY)
  {
    if(MathAbs(price_ask - prev_low) < SR_Proximity_Points * point_val) return 1;
  }
  else if(direction == ORDER_TYPE_SELL)
  {
    if(MathAbs(price_bid - prev_high) < SR_Proximity_Points * point_val) return 1;
  }
  return 0;
}

//+------------------------------------------------------------------+
//| Checa se está dentro do horário permitido para operar            |
//+------------------------------------------------------------------+
bool IsTradeAllowedByTime()
{
  MqlDateTime current_time_struct;
  TimeCurrent(current_time_struct);
  int current_hour = current_time_struct.hour;

  if(TradeStartTimeHour <= TradeEndTimeHour)
  {
    if(current_hour >= TradeStartTimeHour && current_hour <= TradeEndTimeHour)
      return true;
  }
  else // Operação que vira a noite (ex: Início 22h, Fim 05h)
  {
    if(current_hour >= TradeStartTimeHour || current_hour <= TradeEndTimeHour)
      return true;
  }
  return false;
}
//+------------------------------------------------------------------+
//| Calcula o tamanho do lote baseado no risco e SL                  |
//+------------------------------------------------------------------+
double CalculateLotSize(ENUM_ORDER_TYPE direction)
{
  if(SL_Points <= 0)
  {
    Print(ea_comment_prefix, " ERRO no cálculo do lote: SL_Points inválido (", SL_Points, ").");
    return 0.0;
  }

  double balance = AccountInfoDouble(ACCOUNT_BALANCE);
  double riskAmount = balance * (RiskPercent / 100.0);

  double tick_value = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
  double tick_size  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
  double point_val = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

  if(tick_value <= 0 || tick_size <= 0 || point_val <= 0)
  {
    Print(ea_comment_prefix, " ERRO no cálculo do lote: Informações do símbolo inválidas (TickValue, TickSize, Point).");
    return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  }

  double sl_in_money_per_lot = SL_Points * tick_value * (point_val / tick_size);
  if (sl_in_money_per_lot <= 1e-10) // Check for near zero or zero
  {
       Print(ea_comment_prefix, " ERRO no cálculo do lote: sl_in_money_per_lot é zero ou negativo: ", sl_in_money_per_lot);
       return SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  }

  double lot = riskAmount / sl_in_money_per_lot;
  
  double volMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  double volMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
  double volStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
  int    volDigits = CalculateVolumeDigits(_Symbol);

  lot = MathMax(lot, volMin);
  lot = MathMin(lot, volMax);

  if (volStep > 0) lot = MathRound(lot / volStep) * volStep;
  lot = NormalizeDouble(lot, volDigits);
  
  if (lot < volMin) lot = volMin;

  return lot;
}
//+------------------------------------------------------------------+
//| Executa a ordem (Compra ou Venda)                                |
//+------------------------------------------------------------------+
void ExecuteTrade(double lot, ENUM_ORDER_TYPE direction)
{
  double price = 0;
  double sl_price = 0;
  double tp_price = 0;
  string trade_type_str = "";
  double point_val = _Point;
  int volDigits = CalculateVolumeDigits(_Symbol);


  if(direction == ORDER_TYPE_BUY)
  {
    price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    sl_price = price - SL_Points * point_val;
    tp_price = price + TP_Points * point_val;
    trade_type_str = "COMPRA";
    if(!trade.Buy(lot, _Symbol, price, sl_price, tp_price, ea_comment_prefix + " Buy"))
    {
      Print(ea_comment_prefix, " Erro abrindo ", trade_type_str, ": ", GetLastError(), " (", trade.ResultRetcodeDescription(), ")");
    }
    else
    {
      Print(ea_comment_prefix, " ", trade_type_str, " aberta: Lote ", DoubleToString(lot, volDigits), " Preço: ", DoubleToString(price, _Digits), " SL: ", DoubleToString(sl_price, _Digits), " TP: ", DoubleToString(tp_price, _Digits));
    }
  }
  else if(direction == ORDER_TYPE_SELL)
  {
    price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    sl_price = price + SL_Points * point_val;
    tp_price = price - TP_Points * point_val;
    trade_type_str = "VENDA";
    if(!trade.Sell(lot, _Symbol, price, sl_price, tp_price, ea_comment_prefix + " Sell"))
    {
      Print(ea_comment_prefix, " Erro abrindo ", trade_type_str, ": ", GetLastError(), " (", trade.ResultRetcodeDescription(), ")");
    }
    else
    {
      Print(ea_comment_prefix, " ", trade_type_str, " aberta: Lote ", DoubleToString(lot, volDigits), " Preço: ", DoubleToString(price, _Digits), " SL: ", DoubleToString(sl_price, _Digits), " TP: ", DoubleToString(tp_price, _Digits));
    }
  }
}
//+------------------------------------------------------------------+
//| Aplica trailing stop para proteger lucros                        |
//+------------------------------------------------------------------+
void ApplyTrailingStopToPositions()
{
  for(int i = PositionsTotal() - 1; i >= 0; i--)
  {
    ulong ticket = PositionGetTicket(i);
    if(PositionSelectByTicket(ticket))
    {
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
         PositionGetString(POSITION_SYMBOL) == _Symbol)
      {
        double open_price = PositionGetDouble(POSITION_PRICE_OPEN);
        double current_sl = PositionGetDouble(POSITION_SL);
        double current_tp = PositionGetDouble(POSITION_TP);
        ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
        double point_val = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

        if(pos_type == POSITION_TYPE_BUY)
        {
          double current_bid_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
          double trail_activation_price = open_price + TrailingStartPoints * point_val;

          if(current_bid_price > trail_activation_price)
          {
            double new_sl = current_bid_price - TrailingStepPoints * point_val;
            if(new_sl > current_sl && new_sl < current_bid_price)
            {
              if(trade.PositionModify(ticket, new_sl, current_tp))
              {
                Print(ea_comment_prefix, " Trailing Stop (BUY) modificado para Posição #", ticket, ": ", DoubleToString(new_sl, _Digits));
              }
              else
              {
                Print(ea_comment_prefix, " Erro ao modificar Trailing Stop (BUY) para Posição #", ticket, ": ", GetLastError(), " (", trade.ResultRetcodeDescription(), ")");
              }
            }
          }
        }
        else if(pos_type == POSITION_TYPE_SELL)
        {
          double current_ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
          double trail_activation_price = open_price - TrailingStartPoints * point_val;

          if(current_ask_price < trail_activation_price)
          {
            double new_sl = current_ask_price + TrailingStepPoints * point_val;
            if((new_sl < current_sl || current_sl == 0) && new_sl > current_ask_price) // current_sl == 0 for positions without SL initially
            {
              if(trade.PositionModify(ticket, new_sl, current_tp))
              {
                Print(ea_comment_prefix, " Trailing Stop (SELL) modificado para Posição #", ticket, ": ", DoubleToString(new_sl, _Digits));
              }
              else
              {
                Print(ea_comment_prefix, " Erro ao modificar Trailing Stop (SELL) para Posição #", ticket, ": ", GetLastError(), " (", trade.ResultRetcodeDescription(), ")");
              }
            }
          }
        }
      }
    }
  }
}

//+------------------------------------------------------------------+
//| Conta posições abertas por este EA no símbolo atual              |
//+------------------------------------------------------------------+
int CountEAPositionsThisSymbol()
{
  int count = 0;
  for(int i = PositionsTotal() - 1; i >= 0; i--)
  {
    ulong ticket = PositionGetTicket(i);
    if(PositionSelectByTicket(ticket))
    {
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
         PositionGetString(POSITION_SYMBOL) == _Symbol)
      {
        count++;
      }
    }
  }
  return count;
}

//+------------------------------------------------------------------+
//| Cria painel com informações na tela                              |
//+------------------------------------------------------------------+
void CreateInfoPanel()
{
  string panel_name = "info_panel_" + (string)MagicNumber;
  if(ObjectFind(0, panel_name) != -1)
    ObjectDelete(0, panel_name);

  ObjectCreate(0, panel_name, OBJ_LABEL, 0, 0, 0);
  ObjectSetInteger(0, panel_name, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
  ObjectSetInteger(0, panel_name, OBJPROP_XDISTANCE, 10);
  ObjectSetInteger(0, panel_name, OBJPROP_YDISTANCE, 15);
  ObjectSetInteger(0, panel_name, OBJPROP_FONTSIZE, 10);
  ObjectSetString(0, panel_name, OBJPROP_FONT, "Arial");
  ObjectSetInteger(0, panel_name, OBJPROP_COLOR, clrWhite);
  ObjectSetInteger(0, panel_name, OBJPROP_BACK, true);
  ObjectSetInteger(0, panel_name, OBJPROP_BGCOLOR, clrDarkSlateGray);
  ObjectSetInteger(0, panel_name, OBJPROP_SELECTABLE, false);
  ObjectSetInteger(0, panel_name, OBJPROP_ZORDER, 0);
}
//+------------------------------------------------------------------+
//| Atualiza o texto do painel                                       |
//+------------------------------------------------------------------+
void UpdateInfoPanel()
{
  string panel_name = "info_panel_" + (string)MagicNumber;
  if(ObjectFind(0, panel_name) == -1 && MQL5InfoInteger(MQL5_VISUAL_MODE)) CreateInfoPanel(); // Recria se não existir e estiver em modo visual

  double balance = AccountInfoDouble(ACCOUNT_BALANCE);
  double equity  = AccountInfoDouble(ACCOUNT_EQUITY);
  double profit  = AccountInfoDouble(ACCOUNT_PROFIT);
  
  double ea_profit = 0;
  int    ea_open_positions = 0;
  for(int i = PositionsTotal() - 1; i >= 0; i--)
  {
    ulong ticket = PositionGetTicket(i);
    if(PositionSelectByTicket(ticket))
    {
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
      {
        ea_profit += PositionGetDouble(POSITION_PROFIT);
        ea_open_positions++;
      }
    }
  }

  string text = StringFormat("--- %s (%s) ---\nSaldo: %.2f\nEquity: %.2f\nLucro Total: %.2f\n" +
                             "Lucro EA: %.2f\nPosições EA: %d\n" +
                             "Posições Conta: %d",
                             ea_comment_prefix, _Symbol,
                             balance, equity, profit,
                             ea_profit,
                             ea_open_positions,
                             PositionsTotal());
  if(MQL5InfoInteger(MQL5_VISUAL_MODE)) ObjectSetString(0, panel_name, OBJPROP_TEXT, text);
}
//+------------------------------------------------------------------+

응답함

1
개발자 1
등급
(31)
프로젝트
55
5%
중재
34
0% / 94%
기한 초과
24
44%
작업중
2
개발자 2
등급
(539)
프로젝트
620
33%
중재
36
39% / 53%
기한 초과
11
2%
로드됨
3
개발자 3
등급
(2)
프로젝트
2
0%
중재
0
기한 초과
0
무료
4
개발자 4
등급
(1)
프로젝트
2
0%
중재
0
기한 초과
1
50%
무료
5
개발자 5
등급
(294)
프로젝트
470
39%
중재
102
40% / 24%
기한 초과
78
17%
바쁜
게재됨: 2 코드
6
개발자 6
등급
(3)
프로젝트
3
0%
중재
1
0% / 100%
기한 초과
0
무료
7
개발자 7
등급
(1)
프로젝트
2
0%
중재
1
0% / 100%
기한 초과
0
무료
게재됨: 2 코드
8
개발자 8
등급
(24)
프로젝트
34
9%
중재
3
33% / 0%
기한 초과
8
24%
무료
9
개발자 9
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료
10
개발자 10
등급
(48)
프로젝트
49
8%
중재
0
기한 초과
0
무료
11
개발자 11
등급
프로젝트
0
0%
중재
0
기한 초과
0
무료

프로젝트 정보

예산
30+ USD