519 lines
18 KiB
MQL4
519 lines
18 KiB
MQL4
//+------------------------------------------------------------------+
|
|
//| XAU_USD_Scalper_M5.mq4 |
|
|
//| Copyright 2024, Forex Scalper Bot |
|
|
//| https://www.fbs.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Forex Scalper Bot"
|
|
#property link "https://www.fbs.com"
|
|
#property version "2.00"
|
|
#property strict
|
|
|
|
//--- Input Parameters
|
|
input double LotSize = 0.01; // Tamanho do lote
|
|
input int StopLoss = 25; // Stop Loss em pontos
|
|
input int TrailingStop = 15; // Trailing Stop em pontos
|
|
input double TakeProfitMultiplier = 2.0; // Multiplicador para Take Profit (spread + SL) * multiplicador
|
|
input int MagicNumber = 54321; // Número mágico
|
|
input int MaxSpread = 50; // Spread máximo permitido (pontos)
|
|
input int MinDistance = 30; // Distância mínima entre ordens (pontos)
|
|
input bool UseTrailingStop = true; // Usar Trailing Stop
|
|
input bool UseBreakEven = true; // Usar Break Even
|
|
input int BreakEvenPoints = 15; // Pontos para ativar Break Even
|
|
input int MaxOrders = 5; // Máximo de ordens simultâneas
|
|
input int RSI_Period = 14; // Período do RSI
|
|
input int RSI_Overbought = 70; // Nível de sobrecompra RSI
|
|
input int RSI_Oversold = 30; // Nível de sobrevenda RSI
|
|
input int MA_Fast = 8; // Média móvel rápida (ajustada para M5)
|
|
input int MA_Medium = 21; // Média móvel média
|
|
input int MA_Slow = 50; // Média móvel lenta (detecção de tendência)
|
|
input int MA_Method = MODE_EMA; // Tipo de média móvel
|
|
input double MinTrendStrength = 0.3; // Força mínima da tendência (em pontos por período)
|
|
input int TrendLookback = 20; // Períodos para calcular força da tendência
|
|
input bool UsePriceAction = true; // Usar sinais de Price Action
|
|
input double CandleBodyRatio = 0.6; // Ratio mínimo corpo/sombra para candles válidos
|
|
input bool UseMultipleOrders = true; // Permitir múltiplas ordens
|
|
|
|
//--- Global Variables
|
|
double g_point;
|
|
int g_digits;
|
|
datetime g_lastBarTime = 0;
|
|
int g_lastOrderCount = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
// Configurações básicas
|
|
g_digits = (int)MarketInfo(Symbol(), MODE_DIGITS);
|
|
g_point = MarketInfo(Symbol(), MODE_POINT);
|
|
|
|
// Ajustar para corretoras com 5 dígitos
|
|
if(g_digits == 5 || g_digits == 3)
|
|
{
|
|
g_point *= 10;
|
|
}
|
|
|
|
// Verificar se é XAU/USD
|
|
if(StringFind(Symbol(), "XAUUSD") < 0 && StringFind(Symbol(), "GOLD") < 0)
|
|
{
|
|
Print("Este EA foi projetado para XAU/USD. Símbolo atual: ", Symbol());
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
// Verificar timeframe
|
|
if(Period() != PERIOD_M5)
|
|
{
|
|
Print("Este EA foi projetado para timeframe M5. Timeframe atual: ", Period());
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
Print("XAU/USD Scalper M5 inicializado com sucesso!");
|
|
Print("Lot Size: ", LotSize);
|
|
Print("Stop Loss: ", StopLoss, " pontos");
|
|
Print("Take Profit Multiplier: ", TakeProfitMultiplier);
|
|
Print("Spread máximo: ", MaxSpread, " pontos");
|
|
Print("Magic Number: ", MagicNumber);
|
|
Print("Múltiplas ordens: ", UseMultipleOrders ? "Habilitado" : "Desabilitado");
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
Print("XAU/USD Scalper M5 finalizado. Razão: ", reason);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
// Verificar se é uma nova barra
|
|
if(g_lastBarTime == Time[0])
|
|
{
|
|
// Mesmo sem nova barra, gerenciar ordens abertas
|
|
ManageOpenOrders();
|
|
return;
|
|
}
|
|
g_lastBarTime = Time[0];
|
|
|
|
// Verificar spread
|
|
double currentSpread = MarketInfo(Symbol(), MODE_SPREAD);
|
|
if(currentSpread > MaxSpread)
|
|
{
|
|
Print("Spread muito alto: ", currentSpread, " - Aguardando melhores condições");
|
|
return;
|
|
}
|
|
|
|
// Verificar se já há muitas ordens abertas
|
|
int openOrders = CountOpenOrders();
|
|
if(!UseMultipleOrders && openOrders >= 1) return;
|
|
if(UseMultipleOrders && openOrders >= MaxOrders) return;
|
|
|
|
// Verificar condições de mercado e tendência
|
|
int marketCondition = AnalyzeMarketCondition();
|
|
if(marketCondition == 0) // Lateral - não operar
|
|
{
|
|
Print("Mercado em lateralidade - Aguardando tendência");
|
|
return;
|
|
}
|
|
|
|
// Verificar sinais de entrada
|
|
int signal = GetEntrySignal(marketCondition);
|
|
|
|
if(signal != 0)
|
|
{
|
|
double takeProfit = CalculateDynamicTakeProfit(currentSpread);
|
|
OpenOrder(signal, takeProfit);
|
|
}
|
|
|
|
// Gerenciar ordens abertas
|
|
ManageOpenOrders();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para calcular Take Profit dinâmico |
|
|
//+------------------------------------------------------------------+
|
|
double CalculateDynamicTakeProfit(double spread)
|
|
{
|
|
// TP = (Spread + Stop Loss) * Multiplicador
|
|
double tpPoints = (spread + StopLoss) * TakeProfitMultiplier;
|
|
|
|
// Garantir TP mínimo
|
|
if(tpPoints < StopLoss * 1.5)
|
|
{
|
|
tpPoints = StopLoss * 1.5;
|
|
}
|
|
|
|
Print("Take Profit calculado: ", tpPoints, " pontos (Spread: ", spread, ")");
|
|
return tpPoints;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para analisar condições do mercado |
|
|
//+------------------------------------------------------------------+
|
|
int AnalyzeMarketCondition()
|
|
{
|
|
double ma_slow = iMA(Symbol(), Period(), MA_Slow, 0, MA_Method, PRICE_CLOSE, 1);
|
|
double ma_slow_prev = iMA(Symbol(), Period(), MA_Slow, 0, MA_Method, PRICE_CLOSE, TrendLookback);
|
|
|
|
// Calcular força da tendência
|
|
double trendStrength = MathAbs(ma_slow - ma_slow_prev) / TrendLookback / g_point;
|
|
|
|
if(trendStrength < MinTrendStrength)
|
|
{
|
|
return 0; // Lateral
|
|
}
|
|
|
|
// Determinar direção da tendência
|
|
if(ma_slow > ma_slow_prev)
|
|
{
|
|
return 1; // Tendência de alta
|
|
}
|
|
else
|
|
{
|
|
return -1; // Tendência de baixa
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para obter sinal de entrada com Price Action |
|
|
//+------------------------------------------------------------------+
|
|
int GetEntrySignal(int trendDirection)
|
|
{
|
|
double rsi = iRSI(Symbol(), Period(), RSI_Period, PRICE_CLOSE, 1);
|
|
double ma_fast = iMA(Symbol(), Period(), MA_Fast, 0, MA_Method, PRICE_CLOSE, 1);
|
|
double ma_medium = iMA(Symbol(), Period(), MA_Medium, 0, MA_Method, PRICE_CLOSE, 1);
|
|
double ma_slow = iMA(Symbol(), Period(), MA_Slow, 0, MA_Method, PRICE_CLOSE, 1);
|
|
|
|
// Verificar alinhamento das médias móveis
|
|
bool bullishMA = (ma_fast > ma_medium && ma_medium > ma_slow);
|
|
bool bearishMA = (ma_fast < ma_medium && ma_medium < ma_slow);
|
|
|
|
// Price Action - analisar candles
|
|
bool bullishPA = false;
|
|
bool bearishPA = false;
|
|
|
|
if(UsePriceAction)
|
|
{
|
|
bullishPA = IsBullishPriceAction();
|
|
bearishPA = IsBearishPriceAction();
|
|
}
|
|
else
|
|
{
|
|
// Usar apenas RSI se Price Action estiver desabilitado
|
|
bullishPA = (rsi < RSI_Oversold);
|
|
bearishPA = (rsi > RSI_Overbought);
|
|
}
|
|
|
|
// Sinal de compra
|
|
if(trendDirection >= 0 && bullishMA && bullishPA && rsi < 60)
|
|
{
|
|
return 1; // Compra
|
|
}
|
|
|
|
// Sinal de venda
|
|
if(trendDirection <= 0 && bearishMA && bearishPA && rsi > 40)
|
|
{
|
|
return -1; // Venda
|
|
}
|
|
|
|
return 0; // Sem sinal
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para detectar Price Action de alta |
|
|
//+------------------------------------------------------------------+
|
|
bool IsBullishPriceAction()
|
|
{
|
|
double open1 = Open[1];
|
|
double high1 = High[1];
|
|
double low1 = Low[1];
|
|
double close1 = Close[1];
|
|
|
|
double open2 = Open[2];
|
|
double close2 = Close[2];
|
|
|
|
// Candle de alta (corpo verde)
|
|
if(close1 <= open1) return false;
|
|
|
|
// Verificar ratio do corpo
|
|
double bodySize = close1 - open1;
|
|
double totalRange = high1 - low1;
|
|
if(totalRange > 0 && (bodySize / totalRange) < CandleBodyRatio) return false;
|
|
|
|
// Padrões de Price Action
|
|
// 1. Hammer ou Doji de alta após queda
|
|
bool isHammer = (bodySize < (totalRange * 0.3) && (close1 - low1) > (high1 - close1) * 2);
|
|
|
|
// 2. Candle de engolfo de alta
|
|
bool isBullishEngulfing = (close2 < open2 && close1 > open1 && open1 < close2 && close1 > open2);
|
|
|
|
// 3. Candle de alta forte
|
|
bool isStrongBullish = (bodySize > (totalRange * 0.7) && close1 > open2);
|
|
|
|
return (isHammer || isBullishEngulfing || isStrongBullish);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para detectar Price Action de baixa |
|
|
//+------------------------------------------------------------------+
|
|
bool IsBearishPriceAction()
|
|
{
|
|
double open1 = Open[1];
|
|
double high1 = High[1];
|
|
double low1 = Low[1];
|
|
double close1 = Close[1];
|
|
|
|
double open2 = Open[2];
|
|
double close2 = Close[2];
|
|
|
|
// Candle de baixa (corpo vermelho)
|
|
if(close1 >= open1) return false;
|
|
|
|
// Verificar ratio do corpo
|
|
double bodySize = open1 - close1;
|
|
double totalRange = high1 - low1;
|
|
if(totalRange > 0 && (bodySize / totalRange) < CandleBodyRatio) return false;
|
|
|
|
// Padrões de Price Action
|
|
// 1. Shooting Star ou Doji de baixa após alta
|
|
bool isShootingStar = (bodySize < (totalRange * 0.3) && (high1 - close1) > (close1 - low1) * 2);
|
|
|
|
// 2. Candle de engolfo de baixa
|
|
bool isBearishEngulfing = (close2 > open2 && close1 < open1 && open1 > close2 && close1 < open2);
|
|
|
|
// 3. Candle de baixa forte
|
|
bool isStrongBearish = (bodySize > (totalRange * 0.7) && close1 < open2);
|
|
|
|
return (isShootingStar || isBearishEngulfing || isStrongBearish);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para abrir ordem |
|
|
//+------------------------------------------------------------------+
|
|
void OpenOrder(int signal, double tpPoints)
|
|
{
|
|
double price, sl, tp;
|
|
int cmd;
|
|
string comment;
|
|
|
|
if(signal == 1) // Compra
|
|
{
|
|
cmd = OP_BUY;
|
|
price = Ask;
|
|
sl = price - StopLoss * g_point;
|
|
tp = price + tpPoints * g_point;
|
|
comment = "XAU M5 Buy";
|
|
}
|
|
else if(signal == -1) // Venda
|
|
{
|
|
cmd = OP_SELL;
|
|
price = Bid;
|
|
sl = price + StopLoss * g_point;
|
|
tp = price - tpPoints * g_point;
|
|
comment = "XAU M5 Sell";
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Verificar distância mínima se múltiplas ordens estiverem habilitadas
|
|
if(UseMultipleOrders && !CheckMinDistance(price, cmd))
|
|
{
|
|
Print("Distância mínima não atendida para nova ordem");
|
|
return;
|
|
}
|
|
|
|
int ticket = OrderSend(Symbol(), cmd, LotSize, price, 5, sl, tp, comment, MagicNumber, 0, clrGreen);
|
|
|
|
if(ticket > 0)
|
|
{
|
|
Print("Ordem aberta: ", cmd == OP_BUY ? "Compra" : "Venda",
|
|
" Ticket: ", ticket, " Preço: ", DoubleToStr(price, g_digits),
|
|
" SL: ", DoubleToStr(sl, g_digits), " TP: ", DoubleToStr(tp, g_digits));
|
|
}
|
|
else
|
|
{
|
|
Print("Erro ao abrir ordem: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para verificar distância mínima |
|
|
//+------------------------------------------------------------------+
|
|
bool CheckMinDistance(double price, int cmd)
|
|
{
|
|
for(int i = 0; i < OrdersTotal(); i++)
|
|
{
|
|
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
|
{
|
|
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
|
|
{
|
|
double orderPrice = OrderOpenPrice();
|
|
double distance = MathAbs(price - orderPrice) / g_point;
|
|
|
|
if(distance < MinDistance)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para contar ordens abertas |
|
|
//+------------------------------------------------------------------+
|
|
int CountOpenOrders()
|
|
{
|
|
int count = 0;
|
|
|
|
for(int i = 0; i < OrdersTotal(); i++)
|
|
{
|
|
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
|
{
|
|
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() <= OP_SELL)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para gerenciar ordens abertas |
|
|
//+------------------------------------------------------------------+
|
|
void ManageOpenOrders()
|
|
{
|
|
for(int i = OrdersTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
|
|
{
|
|
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
|
|
{
|
|
// Break Even
|
|
if(UseBreakEven)
|
|
{
|
|
ManageBreakEven();
|
|
}
|
|
|
|
// Trailing Stop
|
|
if(UseTrailingStop)
|
|
{
|
|
ManageTrailingStop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para gerenciar Break Even |
|
|
//+------------------------------------------------------------------+
|
|
void ManageBreakEven()
|
|
{
|
|
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
|
|
double openPrice = OrderOpenPrice();
|
|
double currentSL = OrderStopLoss();
|
|
double profit = (OrderType() == OP_BUY) ? (currentPrice - openPrice) : (openPrice - currentPrice);
|
|
|
|
if(profit >= BreakEvenPoints * g_point)
|
|
{
|
|
double newSL = openPrice + (OrderType() == OP_BUY ? 3 * g_point : -3 * g_point);
|
|
|
|
// Verificar se o novo SL é melhor que o atual
|
|
bool shouldUpdate = false;
|
|
if(OrderType() == OP_BUY && (currentSL == 0 || newSL > currentSL))
|
|
shouldUpdate = true;
|
|
else if(OrderType() == OP_SELL && (currentSL == 0 || newSL < currentSL))
|
|
shouldUpdate = true;
|
|
|
|
if(shouldUpdate)
|
|
{
|
|
if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue))
|
|
{
|
|
Print("Break Even ativado para ticket: ", OrderTicket(), " Novo SL: ", DoubleToStr(newSL, g_digits));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para gerenciar Trailing Stop |
|
|
//+------------------------------------------------------------------+
|
|
void ManageTrailingStop()
|
|
{
|
|
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
|
|
double currentSL = OrderStopLoss();
|
|
double newSL;
|
|
|
|
if(OrderType() == OP_BUY)
|
|
{
|
|
newSL = currentPrice - TrailingStop * g_point;
|
|
if(currentSL == 0 || newSL > currentSL + g_point)
|
|
{
|
|
if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed))
|
|
{
|
|
Print("Trailing Stop atualizado para compra - Ticket: ", OrderTicket(),
|
|
" Novo SL: ", DoubleToStr(newSL, g_digits));
|
|
}
|
|
}
|
|
}
|
|
else if(OrderType() == OP_SELL)
|
|
{
|
|
newSL = currentPrice + TrailingStop * g_point;
|
|
if(currentSL == 0 || newSL < currentSL - g_point)
|
|
{
|
|
if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrRed))
|
|
{
|
|
Print("Trailing Stop atualizado para venda - Ticket: ", OrderTicket(),
|
|
" Novo SL: ", DoubleToStr(newSL, g_digits));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função para monitorar ordens executadas |
|
|
//+------------------------------------------------------------------+
|
|
void OnTrade()
|
|
{
|
|
static datetime lastCheckTime = 0;
|
|
|
|
if(TimeCurrent() != lastCheckTime)
|
|
{
|
|
lastCheckTime = TimeCurrent();
|
|
|
|
// Verificar ordens fechadas recentemente
|
|
for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
|
|
{
|
|
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
|
|
{
|
|
if(OrderCloseTime() >= TimeCurrent() - 300) // Últimos 5 minutos
|
|
{
|
|
string orderType = (OrderType() == OP_BUY) ? "Compra" : "Venda";
|
|
double profit = OrderProfit() + OrderSwap() + OrderCommission();
|
|
|
|
Print("===== ORDEM FECHADA =====");
|
|
Print("Tipo: ", orderType, " | Ticket: ", OrderTicket());
|
|
Print("Preço Abertura: ", DoubleToStr(OrderOpenPrice(), g_digits));
|
|
Print("Preço Fechamento: ", DoubleToStr(OrderClosePrice(), g_digits));
|
|
Print("Lucro: ", DoubleToStr(profit, 2), " USD");
|
|
Print("========================");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|