481 lines
No EOL
18 KiB
MQL5
481 lines
No EOL
18 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |