指定
//+------------------------------------------------------------------+
//| 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
評価
プロジェクト
55
5%
仲裁
34
0%
/
94%
期限切れ
24
44%
仕事中
2
評価
プロジェクト
620
33%
仲裁
36
39%
/
53%
期限切れ
11
2%
取り込み中
3
評価
プロジェクト
2
0%
仲裁
0
期限切れ
0
暇
4
評価
プロジェクト
2
0%
仲裁
0
期限切れ
1
50%
暇
5
評価
プロジェクト
470
39%
仲裁
102
40%
/
24%
期限切れ
78
17%
多忙
パブリッシュした人: 2 codes
6
評価
プロジェクト
3
0%
仲裁
1
0%
/
100%
期限切れ
0
暇
7
評価
プロジェクト
2
0%
仲裁
1
0%
/
100%
期限切れ
0
暇
パブリッシュした人: 2 codes
8
評価
プロジェクト
34
9%
仲裁
3
33%
/
0%
期限切れ
8
24%
暇
9
評価
プロジェクト
0
0%
仲裁
0
期限切れ
0
暇
10
評価
プロジェクト
49
8%
仲裁
0
期限切れ
0
暇
11
評価
プロジェクト
0
0%
仲裁
0
期限切れ
0
暇
プロジェクト情報
予算
30+ USD