500 lines
No EOL
19 KiB
MQL5
500 lines
No EOL
19 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| WinQ25_Scalper_Conservador.mq5 |
|
|
//| Copyright 2024, Scalper Trading Bot |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2024, Scalper Trading Bot"
|
|
#property link "https://www.mql5.com"
|
|
#property version "1.00"
|
|
#property description "Robô Scalper WinQ25 - Perfil CONSERVADOR - Mercado Brasileiro BMF"
|
|
|
|
//--- Includes
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
#include <Trade\AccountInfo.mqh>
|
|
|
|
//--- Objetos globais
|
|
CTrade trade;
|
|
CPositionInfo position;
|
|
CAccountInfo account;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Parâmetros CONSERVADORES pré-configurados |
|
|
//+------------------------------------------------------------------+
|
|
input group "=== PERFIL CONSERVADOR ==="
|
|
input string InfoPerfil = "Baixo risco, operações menores";
|
|
|
|
input group "=== CONFIGURAÇÕES BÁSICAS ==="
|
|
input double LotePadrao = 1.0; // Lote padrão para baixa volatilidade
|
|
input double LoteAltaVolatilidade = 2.0; // Lote para alta volatilidade
|
|
input int TakeProfitPadrao = 30; // Take Profit padrão (pontos)
|
|
input int TakeProfitAltaVol = 80; // Take Profit alta volatilidade (pontos)
|
|
input int MagicNumber = 111111; // Número mágico (conservador)
|
|
input string Simbolo = "WINQ25"; // Símbolo a ser operado
|
|
|
|
input group "=== GESTÃO DE RISCO CONSERVADORA ==="
|
|
input double RiscoMaximoDiario = 1.0; // Risco máximo diário (% do saldo)
|
|
input int MaxOperacoesPerdedoras = 2; // Máximo de operações perdedoras consecutivas
|
|
input int MaxTradesPorDia = 10; // Máximo de trades por dia
|
|
input double StopLossPercentual = 50.0; // Stop Loss como % do Take Profit
|
|
|
|
input group "=== PRICE ACTION CONSERVADOR ==="
|
|
input int PeriodoMedia = 20; // Período da média móvel
|
|
input double MinimoPontosMovimento = 40.0; // Mínimo de pontos para considerar movimento
|
|
input int VelasAnalise = 5; // Número de velas para análise (mais confirmação)
|
|
|
|
input group "=== HORÁRIOS DE TRADING ==="
|
|
input bool OperarAberturaBMF = true; // Operar abertura BMF (09:15-10:00)
|
|
input bool OperarAberturaBovespa = false; // NÃO operar abertura Bovespa (muito volátil)
|
|
input bool OperarAberturaEUA = false; // NÃO operar abertura EUA (muito volátil)
|
|
input bool OperarTarde = true; // Operar período tarde (14:00-16:45)
|
|
input bool OperarFechamento = false; // NÃO operar fechamento (muito volátil)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Variáveis globais |
|
|
//+------------------------------------------------------------------+
|
|
datetime ultimoDia = 0;
|
|
int tradesHoje = 0;
|
|
int tradesVencedoresHoje = 0;
|
|
int tradesPerdedoresConsecutivos = 0;
|
|
double saldoInicialDia = 0;
|
|
double perdaMaximaDia = 0;
|
|
bool tradingPermitido = true;
|
|
|
|
//--- Handles dos indicadores
|
|
int handleMA;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função de inicialização |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Configurar Magic Number
|
|
trade.SetExpertMagicNumber(MagicNumber);
|
|
|
|
//--- Criar handle da média móvel
|
|
handleMA = iMA(Simbolo, PERIOD_M1, PeriodoMedia, 0, MODE_SMA, PRICE_CLOSE);
|
|
if(handleMA == INVALID_HANDLE)
|
|
{
|
|
Print("Erro ao criar handle da média móvel");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
//--- Inicializar dados do dia
|
|
InicializarDadosDia();
|
|
|
|
Print("=== WinQ25 Scalper CONSERVADOR ===");
|
|
Print("✅ Robô inicializado com sucesso!");
|
|
Print("📊 Perfil: CONSERVADOR (Baixo Risco)");
|
|
Print("💰 Lote padrão: ", LotePadrao);
|
|
Print("🎯 Take Profit padrão: ", TakeProfitPadrao, " pontos");
|
|
Print("🛡️ Risco máximo diário: ", RiscoMaximoDiario, "%");
|
|
Print("⏰ Horários ativos: BMF + Tarde (horários menos voláteis)");
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função de desinicialização |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//--- Liberar handles
|
|
if(handleMA != INVALID_HANDLE)
|
|
IndicatorRelease(handleMA);
|
|
|
|
Print("WinQ25 Scalper CONSERVADOR finalizado. Motivo: ", reason);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função principal - executada a cada tick |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//--- Verificar se é um novo dia
|
|
if(VerificarNovoDia())
|
|
{
|
|
InicializarDadosDia();
|
|
}
|
|
|
|
//--- Verificar se trading está permitido
|
|
if(!TradingPermitido())
|
|
return;
|
|
|
|
//--- Verificar horário de trading
|
|
if(!HorarioTradingPermitido())
|
|
return;
|
|
|
|
//--- Verificar se já temos posição aberta
|
|
if(TemPosicaoAberta())
|
|
{
|
|
GerenciarPosicao();
|
|
return;
|
|
}
|
|
|
|
//--- Procurar oportunidades de entrada (mais conservadora)
|
|
AnalisarEntradaConservadora();
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Verificar se é um novo dia |
|
|
//+------------------------------------------------------------------+
|
|
bool VerificarNovoDia()
|
|
{
|
|
datetime agora = TimeCurrent();
|
|
MqlDateTime dt;
|
|
TimeToStruct(agora, dt);
|
|
|
|
datetime diaAtual = StringToTime(StringFormat("%04d.%02d.%02d 00:00", dt.year, dt.mon, dt.day));
|
|
|
|
if(ultimoDia != diaAtual)
|
|
{
|
|
ultimoDia = diaAtual;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Inicializar dados do dia |
|
|
//+------------------------------------------------------------------+
|
|
void InicializarDadosDia()
|
|
{
|
|
tradesHoje = 0;
|
|
tradesVencedoresHoje = 0;
|
|
tradesPerdedoresConsecutivos = 0;
|
|
saldoInicialDia = account.Balance();
|
|
perdaMaximaDia = saldoInicialDia * (RiscoMaximoDiario / 100.0);
|
|
tradingPermitido = true;
|
|
|
|
Print("=== NOVO DIA DE TRADING CONSERVADOR ===");
|
|
Print("💰 Saldo inicial: R$ ", DoubleToString(saldoInicialDia, 2));
|
|
Print("🛡️ Perda máxima permitida: R$ ", DoubleToString(perdaMaximaDia, 2));
|
|
Print("📈 Estratégia: Conservadora (foco em segurança)");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Verificar se trading está permitido |
|
|
//+------------------------------------------------------------------+
|
|
bool TradingPermitido()
|
|
{
|
|
//--- Verificar se trading foi desabilitado por gestão de risco
|
|
if(!tradingPermitido)
|
|
return false;
|
|
|
|
//--- Verificar máximo de trades por dia
|
|
if(tradesHoje >= MaxTradesPorDia)
|
|
{
|
|
if(tradesHoje == MaxTradesPorDia)
|
|
{
|
|
Print("🛑 Máximo de trades CONSERVADOR por dia atingido: ", MaxTradesPorDia);
|
|
tradingPermitido = false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//--- Verificar máximo de operações perdedoras consecutivas (mais restritivo)
|
|
if(tradesPerdedoresConsecutivos >= MaxOperacoesPerdedoras)
|
|
{
|
|
Print("⚠️ Máximo de operações perdedoras CONSERVADOR atingido: ", MaxOperacoesPerdedoras);
|
|
Print("🛡️ Parando trading por segurança até amanhã");
|
|
tradingPermitido = false;
|
|
return false;
|
|
}
|
|
|
|
//--- Verificar perda máxima diária
|
|
double perdaAtual = saldoInicialDia - account.Balance();
|
|
if(perdaAtual >= perdaMaximaDia)
|
|
{
|
|
Print("🚨 ATENÇÃO: Perda máxima CONSERVADORA atingida: R$ ", DoubleToString(perdaAtual, 2));
|
|
Print("🛑 Trading interrompido por segurança!");
|
|
tradingPermitido = false;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Verificar horário de trading permitido (CONSERVADOR) |
|
|
//+------------------------------------------------------------------+
|
|
bool HorarioTradingPermitido()
|
|
{
|
|
MqlDateTime dt;
|
|
TimeToStruct(TimeCurrent(), dt);
|
|
|
|
//--- Verificar se é dia útil (Segunda a Sexta)
|
|
if(dt.day_of_week == 0 || dt.day_of_week == 6)
|
|
return false;
|
|
|
|
int hora = dt.hour;
|
|
int minuto = dt.min;
|
|
int horaMinuto = hora * 100 + minuto;
|
|
|
|
//--- Horários CONSERVADORES (evita alta volatilidade)
|
|
// 09:30-09:45: Apenas 15 min após abertura BMF (mais seguro)
|
|
if(OperarAberturaBMF && horaMinuto >= 930 && horaMinuto < 945)
|
|
return true;
|
|
|
|
// 14:30-16:30: Período da tarde (menos volátil)
|
|
if(OperarTarde && horaMinuto >= 1430 && horaMinuto < 1630)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Verificar se tem posição aberta |
|
|
//+------------------------------------------------------------------+
|
|
bool TemPosicaoAberta()
|
|
{
|
|
return position.SelectByMagic(Simbolo, MagicNumber);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Gerenciar posição aberta |
|
|
//+------------------------------------------------------------------+
|
|
void GerenciarPosicao()
|
|
{
|
|
if(!position.SelectByMagic(Simbolo, MagicNumber))
|
|
return;
|
|
|
|
//--- Gestão conservadora: breakeven mais rápido
|
|
double precoEntrada = position.PriceOpen();
|
|
double precoAtual = (position.PositionType() == POSITION_TYPE_BUY) ?
|
|
SymbolInfoDouble(Simbolo, SYMBOL_BID) :
|
|
SymbolInfoDouble(Simbolo, SYMBOL_ASK);
|
|
|
|
double ponto = SymbolInfoDouble(Simbolo, SYMBOL_POINT);
|
|
double breakeven = 15 * ponto; // Breakeven com apenas 15 pontos de lucro
|
|
|
|
if(position.PositionType() == POSITION_TYPE_BUY)
|
|
{
|
|
if(precoAtual >= precoEntrada + breakeven && position.StopLoss() < precoEntrada)
|
|
{
|
|
trade.PositionModify(position.Ticket(), precoEntrada + (5 * ponto), position.TakeProfit());
|
|
Print("🔒 Breakeven CONSERVADOR ativado na compra");
|
|
}
|
|
}
|
|
else if(position.PositionType() == POSITION_TYPE_SELL)
|
|
{
|
|
if(precoAtual <= precoEntrada - breakeven && position.StopLoss() > precoEntrada)
|
|
{
|
|
trade.PositionModify(position.Ticket(), precoEntrada - (5 * ponto), position.TakeProfit());
|
|
Print("🔒 Breakeven CONSERVADOR ativado na venda");
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Analisar entrada CONSERVADORA |
|
|
//+------------------------------------------------------------------+
|
|
void AnalisarEntradaConservadora()
|
|
{
|
|
//--- Obter mais velas para análise conservadora
|
|
MqlRates velas[];
|
|
if(CopyRates(Simbolo, PERIOD_M1, 0, VelasAnalise + 3, velas) <= 0)
|
|
return;
|
|
|
|
//--- Obter dados da média móvel
|
|
double ma[];
|
|
if(CopyBuffer(handleMA, 0, 0, VelasAnalise + 3, ma) <= 0)
|
|
return;
|
|
|
|
ArraySetAsSeries(velas, true);
|
|
ArraySetAsSeries(ma, true);
|
|
|
|
//--- Análise CONSERVADORA (mais filtros)
|
|
ENUM_ORDER_TYPE tipoOrdem = AnalisarPriceActionConservador(velas, ma);
|
|
|
|
if(tipoOrdem == ORDER_TYPE_BUY || tipoOrdem == ORDER_TYPE_SELL)
|
|
{
|
|
ExecutarOrdemConservadora(tipoOrdem);
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Análise Price Action CONSERVADORA |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_ORDER_TYPE AnalisarPriceActionConservador(const MqlRates &velas[], const double &ma[])
|
|
{
|
|
double precoAtual = SymbolInfoDouble(Simbolo, SYMBOL_BID);
|
|
|
|
//--- Verificar movimento mínimo (mais restritivo)
|
|
double range = velas[0].high - velas[0].low;
|
|
if(range < MinimoPontosMovimento * SymbolInfoDouble(Simbolo, SYMBOL_POINT))
|
|
return -1;
|
|
|
|
//--- Verificar spread (conservador)
|
|
double ask = SymbolInfoDouble(Simbolo, SYMBOL_ASK);
|
|
double bid = SymbolInfoDouble(Simbolo, SYMBOL_BID);
|
|
double spread = (ask - bid) / SymbolInfoDouble(Simbolo, SYMBOL_POINT);
|
|
if(spread > 2.0) return -1; // Spread máximo de 2 pontos
|
|
|
|
//--- Análise mais conservadora baseada na média móvel
|
|
bool acimaDaMedia = precoAtual > ma[0];
|
|
bool tendenciaAlta = ma[0] > ma[1] && ma[1] > ma[2] && ma[2] > ma[3]; // Tendência mais confirmada
|
|
bool tendenciaBaixa = ma[0] < ma[1] && ma[1] < ma[2] && ma[2] < ma[3];
|
|
|
|
//--- Verificar volatilidade não excessiva
|
|
double volatilidade = 0;
|
|
for(int i = 0; i < 5; i++)
|
|
volatilidade += (velas[i].high - velas[i].low);
|
|
volatilidade /= 5.0;
|
|
|
|
double pontoValor = SymbolInfoDouble(Simbolo, SYMBOL_POINT);
|
|
double volatilidadePontos = volatilidade / pontoValor;
|
|
|
|
// Evitar mercado muito volátil (>100 pontos média) ou muito parado (<20 pontos)
|
|
if(volatilidadePontos > 100.0 || volatilidadePontos < 20.0)
|
|
return -1;
|
|
|
|
//--- Padrão CONSERVADOR de compra
|
|
if(acimaDaMedia && tendenciaAlta)
|
|
{
|
|
// Precisar de 2 velas consecutivas na direção
|
|
bool sequenciaAlta = velas[1].close > velas[1].open && velas[0].close > velas[0].open;
|
|
// E preço não muito longe da média
|
|
double distanciaMedia = MathAbs(precoAtual - ma[0]) / pontoValor;
|
|
|
|
if(sequenciaAlta && distanciaMedia < 50.0)
|
|
return ORDER_TYPE_BUY;
|
|
}
|
|
|
|
//--- Padrão CONSERVADOR de venda
|
|
if(!acimaDaMedia && tendenciaBaixa)
|
|
{
|
|
// Precisar de 2 velas consecutivas na direção
|
|
bool sequenciaBaixa = velas[1].close < velas[1].open && velas[0].close < velas[0].open;
|
|
// E preço não muito longe da média
|
|
double distanciaMedia = MathAbs(precoAtual - ma[0]) / pontoValor;
|
|
|
|
if(sequenciaBaixa && distanciaMedia < 50.0)
|
|
return ORDER_TYPE_SELL;
|
|
}
|
|
|
|
return -1; // Nenhum sinal conservador
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Executar ordem CONSERVADORA |
|
|
//+------------------------------------------------------------------+
|
|
void ExecutarOrdemConservadora(ENUM_ORDER_TYPE tipo)
|
|
{
|
|
//--- Sempre usar lote conservador (nunca usar lote alto em perfil conservador)
|
|
double lote = LotePadrao;
|
|
|
|
//--- Take profit conservador
|
|
int tp = TakeProfitPadrao;
|
|
|
|
//--- Stop loss conservador (mais apertado - 40% do TP para ser mais seguro)
|
|
int sl = (int)(tp * 0.4);
|
|
|
|
double preco = (tipo == ORDER_TYPE_BUY) ?
|
|
SymbolInfoDouble(Simbolo, SYMBOL_ASK) :
|
|
SymbolInfoDouble(Simbolo, SYMBOL_BID);
|
|
|
|
double ponto = SymbolInfoDouble(Simbolo, SYMBOL_POINT);
|
|
|
|
double precoTP, precoSL;
|
|
|
|
if(tipo == ORDER_TYPE_BUY)
|
|
{
|
|
precoTP = preco + (tp * ponto);
|
|
precoSL = preco - (sl * ponto);
|
|
}
|
|
else
|
|
{
|
|
precoTP = preco - (tp * ponto);
|
|
precoSL = preco + (sl * ponto);
|
|
}
|
|
|
|
//--- Executar ordem
|
|
bool resultado = false;
|
|
if(tipo == ORDER_TYPE_BUY)
|
|
{
|
|
resultado = trade.Buy(lote, Simbolo, preco, precoSL, precoTP,
|
|
"WinQ25 Scalper CONSERVADOR - Compra");
|
|
}
|
|
else
|
|
{
|
|
resultado = trade.Sell(lote, Simbolo, preco, precoSL, precoTP,
|
|
"WinQ25 Scalper CONSERVADOR - Venda");
|
|
}
|
|
|
|
if(resultado)
|
|
{
|
|
tradesHoje++;
|
|
Print("=== NOVA OPERAÇÃO CONSERVADORA ===");
|
|
Print("🔵 Tipo: ", (tipo == ORDER_TYPE_BUY) ? "COMPRA" : "VENDA");
|
|
Print("💎 Lote: ", lote, " (sempre conservador)");
|
|
Print("💰 Preço: ", preco);
|
|
Print("🎯 Take Profit: ", precoTP, " (", tp, " pontos)");
|
|
Print("🛡️ Stop Loss: ", precoSL, " (", sl, " pontos - conservador)");
|
|
Print("📊 Trade nº: ", tradesHoje, "/", MaxTradesPorDia);
|
|
Print("⚡ Perfil: CONSERVADOR (baixo risco)");
|
|
}
|
|
else
|
|
{
|
|
Print("❌ Erro ao executar ordem conservadora: ", trade.ResultRetcode());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Função chamada quando há negociação |
|
|
//+------------------------------------------------------------------+
|
|
void OnTrade()
|
|
{
|
|
//--- Verificar se a posição foi fechada
|
|
if(!TemPosicaoAberta())
|
|
{
|
|
//--- Analisar resultado da última operação
|
|
HistorySelect(TimeCurrent() - 86400, TimeCurrent()); // Últimas 24 horas
|
|
|
|
int totalDeals = HistoryDealsTotal();
|
|
if(totalDeals > 0)
|
|
{
|
|
ulong ticket = HistoryDealGetTicket(totalDeals - 1);
|
|
if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber)
|
|
{
|
|
double lucro = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
|
|
|
if(lucro > 0)
|
|
{
|
|
tradesVencedoresHoje++;
|
|
tradesPerdedoresConsecutivos = 0;
|
|
Print("=== TRADE VENCEDOR CONSERVADOR ===");
|
|
Print("💚 Lucro: R$ ", DoubleToString(lucro, 2));
|
|
Print("✅ Estratégia conservadora funcionando!");
|
|
}
|
|
else
|
|
{
|
|
tradesPerdedoresConsecutivos++;
|
|
Print("=== TRADE PERDEDOR CONSERVADOR ===");
|
|
Print("🔴 Perda: R$ ", DoubleToString(lucro, 2));
|
|
Print("⚠️ Perdedores consecutivos: ", tradesPerdedoresConsecutivos, "/", MaxOperacoesPerdedoras);
|
|
|
|
if(tradesPerdedoresConsecutivos >= MaxOperacoesPerdedoras)
|
|
{
|
|
Print("🛑 ATENÇÃO: Limite conservador de perdas atingido!");
|
|
Print("🛡️ Trading suspenso até amanhã por segurança");
|
|
}
|
|
}
|
|
|
|
//--- Estatísticas do dia
|
|
double winRate = (tradesHoje > 0) ? (tradesVencedoresHoje * 100.0 / tradesHoje) : 0;
|
|
double perdaAtual = saldoInicialDia - account.Balance();
|
|
double perdaPercentual = (saldoInicialDia > 0) ? (perdaAtual * 100.0 / saldoInicialDia) : 0;
|
|
|
|
Print("=== ESTATÍSTICAS CONSERVADOR ===");
|
|
Print("📊 Trades realizados: ", tradesHoje, "/", MaxTradesPorDia);
|
|
Print("✅ Trades vencedores: ", tradesVencedoresHoje);
|
|
Print("📈 Win Rate: ", DoubleToString(winRate, 2), "%");
|
|
Print("💰 Saldo atual: R$ ", DoubleToString(account.Balance(), 2));
|
|
Print("📉 Perda atual: ", DoubleToString(perdaPercentual, 2), "%/", RiscoMaximoDiario, "%");
|
|
Print("🔵 Perfil: CONSERVADOR - Prioriza segurança");
|
|
}
|
|
}
|
|
}
|
|
} |