//+------------------------------------------------------------------+ //| XAU_USD_HFT_Scalper.mq5 | //| Copyright 2024, Scalper HFT Systems Ltd. | //| https://www.mql5.com/pt/users | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Scalper HFT Systems Ltd." #property link "https://www.mql5.com/pt/users" #property version "2.00" #property description "Expert Advisor HFT para Scalping XAU/USD - Timeframe M1" #property description "Sistema otimizado para operações de alta frequência" #property description "Estratégia: Price Action + EMAs + RSI" //--- Inputs dos parâmetros input group "=== CONFIGURAÇÕES BÁSICAS ===" input double LotSize = 0.01; // Tamanho do lote input int StopLoss = 10; // Stop Loss em pips input int TakeProfit = 15; // Take Profit em pips (1.5x SL) input int Magic = 12345; // Magic Number input group "=== INDICADORES TÉCNICOS ===" input int MA_Fast = 5; // EMA Rápida (períodos) input int MA_Slow = 10; // EMA Lenta (períodos) input int RSI_Period = 7; // RSI Período input int RSI_Overbought = 75; // RSI Sobrecompra input int RSI_Oversold = 25; // RSI Sobrevenda input group "=== GESTÃO DE RISCO ===" input double MaxSpread = 5.0; // Spread máximo (pips) input int MaxOrders = 3; // Máximo de ordens simultâneas input int MinBarsAfterTrade = 3; // Barras mínimas entre trades input bool UseTrailingStop = true; // Usar Trailing Stop input int TrailingStop = 5; // Trailing Stop (pips) input group "=== FILTROS HFT ===" input bool UseSpeedFilter = true; // Usar filtro de velocidade input double MinPriceSpeed = 0.0003; // Velocidade mínima do preço input bool UseTimeFilter = true; // Usar filtro de horário input int StartHour = 8; // Hora início (GMT) input int EndHour = 17; // Hora fim (GMT) input group "=== CONFIGURAÇÕES AVANÇADAS ===" input int Slippage = 3; // Slippage máximo input bool UseProfitLock = true; // Travar lucro em 5 pips input int ProfitLockPips = 5; // Pips para travar lucro input bool ReduceLotAfterLoss = true; // Reduzir lote após perdas input int MaxConsecutiveLosses = 3; // Perdas consecutivas máximas //--- Variáveis globais int ema_fast_handle; int ema_slow_handle; int rsi_handle; double ema_fast[]; double ema_slow[]; double rsi[]; datetime last_trade_time = 0; int consecutive_losses = 0; bool profit_locked = false; double current_lot_size; //--- Estrutura para controle de velocidade struct PriceSpeed { double last_price; datetime last_time; double speed; }; PriceSpeed price_speed; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Verificar se o símbolo é XAU/USD if(Symbol() != "XAUUSD" && Symbol() != "GOLD" && Symbol() != "XAU/USD") { Alert("ERRO: Este EA funciona apenas com XAU/USD (GOLD)!"); return(INIT_FAILED); } // Verificar timeframe if(_Period != PERIOD_M1) { Alert("AVISO: EA otimizado para timeframe M1. Timeframe atual: ", EnumToString(_Period)); } // Inicializar handles dos indicadores ema_fast_handle = iMA(Symbol(), PERIOD_M1, MA_Fast, 0, MODE_EMA, PRICE_CLOSE); ema_slow_handle = iMA(Symbol(), PERIOD_M1, MA_Slow, 0, MODE_EMA, PRICE_CLOSE); rsi_handle = iRSI(Symbol(), PERIOD_M1, RSI_Period, PRICE_CLOSE); if(ema_fast_handle == INVALID_HANDLE || ema_slow_handle == INVALID_HANDLE || rsi_handle == INVALID_HANDLE) { Alert("ERRO: Falha ao criar handles dos indicadores!"); return(INIT_FAILED); } // Configurar arrays ArraySetAsSeries(ema_fast, true); ArraySetAsSeries(ema_slow, true); ArraySetAsSeries(rsi, true); // Inicializar variáveis current_lot_size = LotSize; price_speed.last_price = SymbolInfoDouble(Symbol(), SYMBOL_BID); price_speed.last_time = TimeCurrent(); Print("XAU/USD HFT Scalper v2.0 inicializado com sucesso!"); Print("Símbolo: ", Symbol(), " | Timeframe: M1"); Print("Lote: ", current_lot_size, " | SL: ", StopLoss, " | TP: ", TakeProfit); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("EA finalizado. Motivo: ", reason); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Atualizar velocidade do preço UpdatePriceSpeed(); // Verificar filtros básicos if(!CheckBasicFilters()) return; // Atualizar indicadores if(!UpdateIndicators()) return; // Gerenciar posições abertas ManageOpenPositions(); // Verificar novas oportunidades de entrada CheckEntrySignals(); } //+------------------------------------------------------------------+ //| Atualizar velocidade do preço | //+------------------------------------------------------------------+ void UpdatePriceSpeed() { double current_price = SymbolInfoDouble(Symbol(), SYMBOL_BID); datetime current_time = TimeCurrent(); if(price_speed.last_time > 0) { double price_change = MathAbs(current_price - price_speed.last_price); double time_diff = (double)(current_time - price_speed.last_time); if(time_diff > 0) price_speed.speed = price_change / time_diff; } price_speed.last_price = current_price; price_speed.last_time = current_time; } //+------------------------------------------------------------------+ //| Verificar filtros básicos | //+------------------------------------------------------------------+ bool CheckBasicFilters() { // Filtro de spread double spread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD) * SymbolInfoDouble(Symbol(), SYMBOL_POINT); if(spread > MaxSpread * GetPipSize()) return false; // Filtro de horário if(UseTimeFilter) { MqlDateTime time_struct; TimeToStruct(TimeCurrent(), time_struct); if(time_struct.hour < StartHour || time_struct.hour >= EndHour) return false; } // Filtro de velocidade do preço if(UseSpeedFilter && price_speed.speed < MinPriceSpeed) return false; // Verificar máximo de ordens if(CountOpenPositions() >= MaxOrders) return false; // Verificar intervalo entre trades if(TimeCurrent() - last_trade_time < MinBarsAfterTrade * 60) return false; return true; } //+------------------------------------------------------------------+ //| Atualizar indicadores | //+------------------------------------------------------------------+ bool UpdateIndicators() { if(CopyBuffer(ema_fast_handle, 0, 0, 3, ema_fast) < 0) return false; if(CopyBuffer(ema_slow_handle, 0, 0, 3, ema_slow) < 0) return false; if(CopyBuffer(rsi_handle, 0, 0, 3, rsi) < 0) return false; return true; } //+------------------------------------------------------------------+ //| Verificar sinais de entrada | //+------------------------------------------------------------------+ void CheckEntrySignals() { double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK); // Sinal de compra if(CheckBuySignal()) { double sl = bid - StopLoss * GetPipSize(); double tp = bid + TakeProfit * GetPipSize(); if(OpenPosition(ORDER_TYPE_BUY, current_lot_size, ask, sl, tp)) { last_trade_time = TimeCurrent(); profit_locked = false; } } // Sinal de venda else if(CheckSellSignal()) { double sl = ask + StopLoss * GetPipSize(); double tp = ask - TakeProfit * GetPipSize(); if(OpenPosition(ORDER_TYPE_SELL, current_lot_size, bid, sl, tp)) { last_trade_time = TimeCurrent(); profit_locked = false; } } } //+------------------------------------------------------------------+ //| Verificar sinal de compra | //+------------------------------------------------------------------+ bool CheckBuySignal() { double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); // Condições de compra bool ema_bullish = (ema_fast[0] > ema_slow[0]) || (ema_fast[1] <= ema_slow[1] && ema_fast[0] > ema_slow[0]); // Cruzamento bullish bool price_above_ema = bid > ema_fast[0]; bool rsi_ok = rsi[0] > RSI_Oversold && rsi[0] < RSI_Overbought; bool momentum = ema_fast[0] > ema_fast[1]; // Momentum ascendente return ema_bullish && price_above_ema && rsi_ok && momentum; } //+------------------------------------------------------------------+ //| Verificar sinal de venda | //+------------------------------------------------------------------+ bool CheckSellSignal() { double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID); // Condições de venda bool ema_bearish = (ema_fast[0] < ema_slow[0]) || (ema_fast[1] >= ema_slow[1] && ema_fast[0] < ema_slow[0]); // Cruzamento bearish bool price_below_ema = bid < ema_fast[0]; bool rsi_ok = rsi[0] > RSI_Oversold && rsi[0] < RSI_Overbought; bool momentum = ema_fast[0] < ema_fast[1]; // Momentum descendente return ema_bearish && price_below_ema && rsi_ok && momentum; } //+------------------------------------------------------------------+ //| Abrir posição | //+------------------------------------------------------------------+ bool OpenPosition(ENUM_ORDER_TYPE type, double volume, double price, double sl, double tp) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = volume; request.type = type; request.price = price; request.sl = sl; request.tp = tp; request.deviation = Slippage; request.magic = Magic; request.comment = "HFT Scalper v2.0"; bool success = OrderSend(request, result); if(success) { Print("Posição aberta: ", EnumToString(type), " | Volume: ", volume, " | Preço: ", price, " | SL: ", sl, " | TP: ", tp); } else { Print("ERRO ao abrir posição: ", result.retcode, " - ", result.comment); // Ajustar lote após falhas consecutivas if(ReduceLotAfterLoss) { consecutive_losses++; if(consecutive_losses >= MaxConsecutiveLosses) { current_lot_size = MathMax(current_lot_size * 0.5, SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN)); consecutive_losses = 0; Print("Lote reduzido para: ", current_lot_size); } } } return success; } //+------------------------------------------------------------------+ //| Gerenciar posições abertas | //+------------------------------------------------------------------+ void ManageOpenPositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == Symbol() && PositionGetInteger(POSITION_MAGIC) == Magic) { ulong ticket = PositionGetInteger(POSITION_TICKET); ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double open_price = PositionGetDouble(POSITION_PRICE_OPEN); double current_price = (type == POSITION_TYPE_BUY) ? SymbolInfoDouble(Symbol(), SYMBOL_BID) : SymbolInfoDouble(Symbol(), SYMBOL_ASK); double profit_pips = GetProfitInPips(type, open_price, current_price); // Trailing Stop if(UseTrailingStop && profit_pips > TrailingStop) { ApplyTrailingStop(ticket, type, current_price); } // Travamento de lucro if(UseProfitLock && !profit_locked && profit_pips >= ProfitLockPips) { LockProfit(ticket, type, open_price); profit_locked = true; } } } } //+------------------------------------------------------------------+ //| Aplicar trailing stop | //+------------------------------------------------------------------+ void ApplyTrailingStop(ulong ticket, ENUM_POSITION_TYPE type, double current_price) { double new_sl; double current_sl = PositionGetDouble(POSITION_SL); if(type == POSITION_TYPE_BUY) { new_sl = current_price - TrailingStop * GetPipSize(); if(new_sl > current_sl + GetPipSize()) { ModifyPosition(ticket, new_sl, PositionGetDouble(POSITION_TP)); } } else { new_sl = current_price + TrailingStop * GetPipSize(); if(new_sl < current_sl - GetPipSize() || current_sl == 0) { ModifyPosition(ticket, new_sl, PositionGetDouble(POSITION_TP)); } } } //+------------------------------------------------------------------+ //| Travar lucro | //+------------------------------------------------------------------+ void LockProfit(ulong ticket, ENUM_POSITION_TYPE type, double open_price) { double lock_sl; if(type == POSITION_TYPE_BUY) lock_sl = open_price + (ProfitLockPips / 2) * GetPipSize(); else lock_sl = open_price - (ProfitLockPips / 2) * GetPipSize(); ModifyPosition(ticket, lock_sl, PositionGetDouble(POSITION_TP)); Print("Lucro travado para posição: ", ticket); } //+------------------------------------------------------------------+ //| Modificar posição | //+------------------------------------------------------------------+ void ModifyPosition(ulong ticket, double sl, double tp) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = ticket; request.sl = sl; request.tp = tp; OrderSend(request, result); } //+------------------------------------------------------------------+ //| Contar posições abertas | //+------------------------------------------------------------------+ int CountOpenPositions() { int count = 0; for(int i = 0; i < PositionsTotal(); i++) { if(PositionGetSymbol(i) == Symbol() && PositionGetInteger(POSITION_MAGIC) == Magic) count++; } return count; } //+------------------------------------------------------------------+ //| Obter tamanho do pip | //+------------------------------------------------------------------+ double GetPipSize() { double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); int digits = (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS); if(digits == 5 || digits == 3) return point * 10; else return point; } //+------------------------------------------------------------------+ //| Calcular lucro em pips | //+------------------------------------------------------------------+ double GetProfitInPips(ENUM_POSITION_TYPE type, double open_price, double current_price) { double diff = (type == POSITION_TYPE_BUY) ? current_price - open_price : open_price - current_price; return diff / GetPipSize(); } //+------------------------------------------------------------------+ //| Função de evento OnTradeTransaction | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { if(trans.symbol == Symbol() && request.magic == Magic) { if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { if(trans.deal_type == DEAL_TYPE_BUY || trans.deal_type == DEAL_TYPE_SELL) { Print("Deal executado: Ticket=", trans.deal, " | Tipo=", EnumToString(trans.deal_type), " | Volume=", trans.volume, " | Preço=", trans.price); // Resetar contador de perdas em caso de sucesso if(trans.deal_type == DEAL_TYPE_BUY || trans.deal_type == DEAL_TYPE_SELL) { consecutive_losses = 0; current_lot_size = LotSize; // Resetar lote } } } } }