//+------------------------------------------------------------------+ //| 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("========================"); } } } } } }