//+------------------------------------------------------------------+ //| 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; WinFutHorarioBovespaLibs hBovespaLibs; class WinFutLib { public: WinFutLib(void); ~WinFutLib(void); CTrade setMagicNumber(CTrade &trade); int setMediaMovel(void); void setDeInit(int reason); void InicializarDadosDia(void); bool TradingPermitido(void); bool TemPosicaoAberta(void); void GerenciarPosicao(void); void AnalisarEntrada(void); ENUM_ORDER_TYPE AnalisarPriceAction(const MqlRates &velas[], const double &ma[]); void ExecutarOrdem(ENUM_ORDER_TYPE tipo); void setOnTickTrader(void); void setOnTrade(void); }; void WinFutLib::WinFutLib(void) { } void WinFutLib::~WinFutLib(void) { } CTrade WinFutLib::setMagicNumber(CTrade &trade) { msgLogs.WinFutMsgLogsSetMagicNumber(); msgLogs.WinFutMsgInfoTrace(MagicNumber); trade.SetExpertMagicNumber(MagicNumber); return trade; } int WinFutLib::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 WinFutLib::setDeInit(int reason) { msgLogs.WinFutMsgLogsSetDeInit(); msgLogs.WinFutMsgInfoTrace("Liberar handles"); if(handleMA != INVALID_HANDLE) IndicatorRelease(handleMA); msgLogs.WinFutMsgInfoTrace(Simbolo + "Scalper Clear finalizado. Motivo: " + reason); } void WinFutLib::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 WinFutLib::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 WinFutLib::TemPosicaoAberta() { msgLogs.WinFutMsgLogsSetTemPosicaoAberta(); return position.SelectByMagic(Simbolo, MagicNumber); } void WinFutLib::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 WinFutLib::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 WinFutLib::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 WinFutLib::ExecutarOrdem(ENUM_ORDER_TYPE tipo) { msgLogs.WinFutMsgLogsSetExecutarOrdem(); msgLogs.WinFutMsgInfoTrace("Determinar lote baseado na volatilidade"); double lote = hBovespaLibs.HorarioAltaVolatilidade() ? LoteAltaVolatilidade : LotePadrao; msgLogs.WinFutMsgInfoTrace("Determinar take profit baseado na volatilidade"); int tp = hBovespaLibs.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; string scalper = ""; if(tipo == ORDER_TYPE_BUY) { scalper = Simbolo + "Scalper - Compra"; msgLogs.WinFutMsgInfoTrace("executando boletada de compra" + scalper); resultado = trade.Buy( lote, Simbolo, preco, precoSL, precoTP, scalper ); } else { scalper = Simbolo + "Scalper - Venda"; msgLogs.WinFutMsgInfoTrace("executando boletada de venda" + scalper); resultado = trade.Sell( lote, Simbolo, preco, precoSL, precoTP, scalper ); } if(resultado) { tradesHoje++; msgLogs.WinFutMsgInfoTrace("=== NOVA OPERAÇÃO ==="); msgLogs.WinFutMsgInfoTrace("Tipo: " + scalper); 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 WinFutLib::setOnTickTrader() { msgLogs.WinFutMsgLogsSetOnTickTrader(); msgLogs.WinFutMsgInfoTrace("Verificar se é um novo dia"); if(hBovespaLibs.VerificarNovoDia()) { InicializarDadosDia(); } msgLogs.WinFutMsgInfoTrace("Verificar se trading está permitido"); if(!TradingPermitido()) return; msgLogs.WinFutMsgInfoTrace("Verificar horário de trading"); if(!hBovespaLibs.HorarioTradingPermitido()) return; msgLogs.WinFutMsgInfoTrace("Verificar se já temos posição aberta"); if(TemPosicaoAberta()) { GerenciarPosicao(); return; } msgLogs.WinFutMsgInfoTrace("Procurar oportunidades de entrada"); AnalisarEntrada(); } void WinFutLib::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)); } } } }