//+------------------------------------------------------------------+ //| wing26Lib.mqh.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include #include #include #include #include #include #include #include #include #include #include #include WinFutMsgLogs msgLogs; CTrade setMagicNumber(CTrade &trade) { msgLogs.WinFutMsgLogsSetMagicNumber(); msgLogs.WinFutMsgInfoTrace(MagicNumber); trade.SetExpertMagicNumber(MagicNumber); return trade; } int setMediaMovel() { msgLogs.WinFutMsgLogsSetMediaMovel(); handleMA = iMA( Simbolo, PERIOD_M1, PeriodoMedia, 0, MODE_SMA, PRICE_CLOSE ); if(handleMA == INVALID_HANDLE) { msgLogs.WinFutMsgInfoTrace("Erro ao criar handle da média móvel"); return INIT_FAILED; } return 1; } void setLogsOnInit() { msgLogs.WinFutMsgLogsSetLogsOnInit(); msgLogs.WinFutMsgInfoTrace(Simbolo +" Scalper Clear inicializado com sucesso!"); msgLogs.WinFutMsgInfoTrace("Lote padrão: ", LotePadrao); msgLogs.WinFutMsgInfoTrace("Lote alta volatilidade: ", LoteAltaVolatilidade); } void setDeInit(int reason) { msgLogs.WinFutMsgLogsSetDeInit(); msgLogs.WinFutMsgInfoTrace("Liberar handles"); if(handleMA != INVALID_HANDLE) IndicatorRelease(handleMA); msgLogs.WinFutMsgInfoTrace(Simbolo + "Scalper Clear finalizado. Motivo: ", reason); } bool VerificarNovoDia() { msgLogs.WinFutMsgLogsSetVerificarNovoDia(); 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; } void InicializarDadosDia() { msgLogs.WinFutMsgLogsSetInicializarDadosDia(); tradesHoje = 0; tradesVencedoresHoje = 0; tradesPerdedoresConsecutivos = 0; saldoInicialDia = account.Balance(); perdaMaximaDia = saldoInicialDia * (RiscoMaximoDiario / 100.0); tradingPermitido = true; msgLogs.WinFutMsgInfoTrace("=== NOVO DIA DE TRADING ==="); msgLogs.WinFutMsgInfoTrace("Saldo inicial: R$ ", DoubleToString(saldoInicialDia, 2)); msgLogs.WinFutMsgInfoTrace("Perda máxima permitida: R$ ", DoubleToString(perdaMaximaDia, 2)); } bool TradingPermitido() { msgLogs.WinFutMsgLogsSetTradingPermitido(); msgLogs.WinFutMsgInfoTrace("Verificar se trading foi desabilitado por gestão de risco"); if(!tradingPermitido) return false; msgLogs.WinFutMsgInfoTrace("Verificar máximo de trades por dia"); if(tradesHoje >= MaxTradesPorDia) { if(tradesHoje == MaxTradesPorDia) { msgLogs.WinFutMsgInfoTrace("Máximo de trades por dia atingido: ", MaxTradesPorDia); tradingPermitido = false; } return false; } msgLogs.WinFutMsgInfoTrace("Verificar máximo de operações perdedoras consecutivas"); if(tradesPerdedoresConsecutivos >= MaxOperacoesPerdedoras) { msgLogs.WinFutMsgInfoTrace("Máximo de operações perdedoras consecutivas atingido: ", MaxOperacoesPerdedoras); tradingPermitido = false; return false; } msgLogs.WinFutMsgInfoTrace("Verificar perda máxima diária"); double perdaAtual = saldoInicialDia - account.Balance(); if(perdaAtual >= perdaMaximaDia) { msgLogs.WinFutMsgInfoTrace("Perda máxima diária atingida: R$ ", DoubleToString(perdaAtual, 2)); tradingPermitido = false; return false; } return true; } bool HorarioTradingPermitido() { msgLogs.WinFutMsgLogsSetHorarioTradingPermitido(); MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); int hora = dt.hour; int minuto = dt.min; int horaMinuto = hora * 100 + minuto; if(dt.day_of_week == 0 || dt.day_of_week == 6) { msgLogs.WinFutMsgInfoTrace("Verificar se é dia útil (Segunda a Sexta)"); return false; } if(OperarAberturaBMF && horaMinuto >= 915 && horaMinuto < 1000) { msgLogs.WinFutMsgInfoTrace("Horarios de trading (Brasília)"); msgLogs.WinFutMsgInfoTrace("09:15-10:00: Apos leilao abertura BMF"); return true; } if(OperarAberturaBovespa && horaMinuto >= 1015 && horaMinuto < 1030) { msgLogs.WinFutMsgInfoTrace("10:15-10:30: Apos leilao abertura Bovespa"); return true; } if(OperarAberturaEUA && horaMinuto >= 1030 && horaMinuto < 1200) { msgLogs.WinFutMsgInfoTrace("10:30-12:00: Abertura mercado americano"); return true; } if(OperarTarde && horaMinuto >= 1400 && horaMinuto < 1645) { msgLogs.WinFutMsgInfoTrace("14:00-16:45: Período da tarde"); return true; } if(OperarFechamento && horaMinuto >= 1700 && horaMinuto < 1800) { msgLogs.WinFutMsgInfoTrace("17:00-18:00: Após fechamento Bovespa"); return true; } msgLogs.WinFutMsgInfoTrace("fora do horario Bovespa"); return false; } bool HorarioAltaVolatilidade() { msgLogs.WinFutMsgLogsSetHorarioAltaVolatilidade(); MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); int hora = dt.hour; int minuto = dt.min; int horaMinuto = hora * 100 + minuto; if(horaMinuto >= 915 && horaMinuto < 1000) { msgLogs.WinFutMsgInfoTrace("Horários de alta volatilidade"); msgLogs.WinFutMsgInfoTrace("09:15-10:00: Após leilão BMF"); return true; } if(horaMinuto >= 1000 && horaMinuto < 1100) { msgLogs.WinFutMsgInfoTrace("10:00-11:00: Abertura Bovespa + EUA"); return true; } if(horaMinuto >= 1700 && horaMinuto < 1800) { msgLogs.WinFutMsgInfoTrace("17:00-18:00: Fechamento"); return true; } msgLogs.WinFutMsgInfoTrace("fora do horario de alta volatilidade Bovespa"); return false; } bool TemPosicaoAberta() { msgLogs.WinFutMsgLogsSetTemPosicaoAberta(); return position.SelectByMagic(Simbolo, MagicNumber); } void GerenciarPosicao() { msgLogs.WinFutMsgLogsSetGerenciarPosicao(); if(!position.SelectByMagic(Simbolo, MagicNumber)) return; //--- Aqui você pode adicionar lógica adicional de gestão //--- Por exemplo, trailing stop, breakeven, etc. } void AnalisarEntrada() { msgLogs.WinFutMsgLogsSetAnalisarEntrada(); msgLogs.WinFutMsgInfoTrace("Obter dados das velas"); MqlRates velas[]; if(CopyRates(Simbolo, PERIOD_M1, 0, VelasAnalise + 1, velas) <= 0) return; msgLogs.WinFutMsgInfoTrace("Obter dados da média móvel"); double ma[]; if(CopyBuffer(handleMA, 0, 0, VelasAnalise + 1, ma) <= 0) return; ArraySetAsSeries(velas, true); ArraySetAsSeries(ma, true); msgLogs.WinFutMsgInfoTrace("Análise de price action para entrada"); ENUM_ORDER_TYPE tipoOrdem = AnalisarPriceAction(velas, ma); if(tipoOrdem == ORDER_TYPE_BUY || tipoOrdem == ORDER_TYPE_SELL) { msgLogs.WinFutMsgInfoTrace("executando boleta de"); msgLogs.WinFutMsgInfoTrace(tipoOrdem); ExecutarOrdem(tipoOrdem); } } ENUM_ORDER_TYPE AnalisarPriceAction(const MqlRates &velas[], const double &ma[]) { msgLogs.WinFutMsgLogsSetAnalisarPriceAction(); double precoAtual = SymbolInfoDouble(Simbolo, SYMBOL_BID); msgLogs.WinFutMsgInfoTrace("Verificar movimento mínimo"); double range = velas[0].high - velas[0].low; if(range < MinimoPontosMovimento * SymbolInfoDouble(Simbolo, SYMBOL_POINT)) return -1; msgLogs.WinFutMsgInfoTrace("Análise baseada na média móvel e price action"); bool acimaDaMedia = precoAtual > ma[0]; bool tendenciaAlta = ma[0] > ma[1] && ma[1] > ma[2]; bool tendenciaBaixa = ma[0] < ma[1] && ma[1] < ma[2]; msgLogs.WinFutMsgInfoTrace("Padrão de compra: preço acima da média em tendência de alta"); if(acimaDaMedia && tendenciaAlta) { msgLogs.WinFutMsgInfoTrace("Verificar se vela anterior foi de baixa e atual é de alta"); if(velas[1].close < velas[1].open && velas[0].close > velas[0].open) { msgLogs.WinFutMsgInfoTrace("Verificar se não estamos em topo"); if(velas[0].high < velas[1].high) msgLogs.WinFutMsgInfoTrace("ordem do tipo de compra"); return ORDER_TYPE_BUY; } } msgLogs.WinFutMsgInfoTrace("Padrão de venda: preço abaixo da média em tendência de baixa"); if(!acimaDaMedia && tendenciaBaixa) { msgLogs.WinFutMsgInfoTrace("Verificar se vela anterior foi de alta e atual é de baixa"); if(velas[1].close > velas[1].open && velas[0].close < velas[0].open) { msgLogs.WinFutMsgInfoTrace("Verificar se não estamos em fundo"); if(velas[0].low > velas[1].low) msgLogs.WinFutMsgInfoTrace("ordem tipo de venda"); return ORDER_TYPE_SELL; } } msgLogs.WinFutMsgInfoTrace("Nenhum sinal"); return -1; } void ExecutarOrdem(ENUM_ORDER_TYPE tipo) { msgLogs.WinFutMsgLogsSetExecutarOrdem(); msgLogs.WinFutMsgInfoTrace("Determinar lote baseado na volatilidade"); double lote = HorarioAltaVolatilidade() ? LoteAltaVolatilidade : LotePadrao; msgLogs.WinFutMsgInfoTrace("Determinar take profit baseado na volatilidade"); int tp = HorarioAltaVolatilidade() ? TakeProfitAltaVol : TakeProfitPadrao; msgLogs.WinFutMsgInfoTrace("Calcular stop loss (50% do take profit)"); int sl = (int)(tp * (StopLossPercentual / 100.0)); double preco = (tipo == ORDER_TYPE_BUY) ? SymbolInfoDouble(Simbolo, SYMBOL_ASK) : SymbolInfoDouble(Simbolo, SYMBOL_BID); double ponto = SymbolInfoDouble(Simbolo, SYMBOL_POINT); double precoTP, precoSL; msgLogs.WinFutMsgInfoTrace("setando TP/SL para tipo de venda"); precoTP = preco - (tp * ponto); precoSL = preco + (sl * ponto); if(tipo == ORDER_TYPE_BUY) { msgLogs.WinFutMsgInfoTrace("setando TP/SL para tipo de compra"); precoTP = preco + (tp * ponto); precoSL = preco - (sl * ponto); } bool resultado = false; if(tipo == ORDER_TYPE_BUY) { msgLogs.WinFutMsgInfoTrace("executando boletada de compra" + Simbolo + "Scalper - Compra"); resultado = trade.Buy( lote, Simbolo, preco, precoSL, precoTP, Simbolo + "Scalper - Compra"); } else { msgLogs.WinFutMsgInfoTrace("executando boletada de venda" + Simbolo + "Scalper - Venda"); resultado = trade.Sell( lote, Simbolo, preco, precoSL, precoTP, Simbolo + "Scalper - Venda"); } if(resultado) { tradesHoje++; msgLogs.WinFutMsgInfoTrace("=== NOVA OPERAÇÃO ==="); msgLogs.WinFutMsgInfoTrace("Tipo: ", (tipo == ORDER_TYPE_BUY) ? "COMPRA" : "VENDA"); msgLogs.WinFutMsgInfoTrace("Lote: ", lote); msgLogs.WinFutMsgInfoTrace("Preço: ", preco); msgLogs.WinFutMsgInfoTrace("Take Profit: ", precoTP, " (", tp, " pontos)"); msgLogs.WinFutMsgInfoTrace("Stop Loss: ", precoSL, " (", sl, " pontos)"); msgLogs.WinFutMsgInfoTrace("Trade nº: ", tradesHoje); } else { msgLogs.WinFutMsgInfoTrace("Erro ao executar ordem: ", trade.ResultRetcode()); } } void setOnTickTrader() { msgLogs.WinFutMsgLogsSetOnTickTrader(); msgLogs.WinFutMsgInfoTrace("Verificar se é um novo dia"); if(VerificarNovoDia()) { InicializarDadosDia(); } msgLogs.WinFutMsgInfoTrace("Verificar se trading está permitido"); if(!TradingPermitido()) return; msgLogs.WinFutMsgInfoTrace("Verificar horário de trading"); if(!HorarioTradingPermitido()) return; msgLogs.WinFutMsgInfoTrace("Verificar se já temos posição aberta"); if(TemPosicaoAberta()) { GerenciarPosicao(); return; } msgLogs.WinFutMsgInfoTrace("Procurar oportunidades de entrada"); AnalisarEntrada(); } void setOnTrade() { msgLogs.WinFutMsgLogsSetOnTrade(); msgLogs.WinFutMsgInfoTrace("Verificar se a posição foi fechada"); if(!TemPosicaoAberta()) { msgLogs.WinFutMsgInfoTrace("Analisar resultado da última operação - Últimas 24 horas"); HistorySelect(TimeCurrent() - 86400, TimeCurrent()); 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; msgLogs.WinFutMsgInfoTrace("=== TRADE VENCEDOR ==="); msgLogs.WinFutMsgInfoTrace("Lucro: R$ ", DoubleToString(lucro, 2)); } else { tradesPerdedoresConsecutivos++; msgLogs.WinFutMsgInfoTrace("=== TRADE PERDEDOR ==="); msgLogs.WinFutMsgInfoTrace("Perda: R$ ", DoubleToString(lucro, 2)); msgLogs.WinFutMsgInfoTrace("Perdedores consecutivos: ", tradesPerdedoresConsecutivos); } msgLogs.WinFutMsgInfoTrace("Estatísticas do dia"); double winRate = (tradesHoje > 0) ? (tradesVencedoresHoje * 100.0 / tradesHoje) : 0; msgLogs.WinFutMsgInfoTrace("=== ESTATÍSTICAS DO DIA ==="); msgLogs.WinFutMsgInfoTrace("Trades realizados: ", tradesHoje); msgLogs.WinFutMsgInfoTrace("Trades vencedores: ", tradesVencedoresHoje); msgLogs.WinFutMsgInfoTrace("Win Rate: ", DoubleToString(winRate, 2), "%"); msgLogs.WinFutMsgInfoTrace("Saldo atual: R$ ", DoubleToString(account.Balance(), 2)); } } } }