//+------------------------------------------------------------------+ //| WinQ25_Indicadores.mqh | //| Copyright 2024, Scalper Trading Bot | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Scalper Trading Bot" #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Classe para análise avançada de Price Action | //+------------------------------------------------------------------+ class PriceActionAnalyzer { private: string simbolo; ENUM_TIMEFRAMES timeframe; public: PriceActionAnalyzer(string _simbolo = "", ENUM_TIMEFRAMES _timeframe = PERIOD_M1) { simbolo = (_simbolo == "") ? Symbol() : _simbolo; timeframe = _timeframe; } //--- Detectar padrão de martelo/doji bool IsMartelo(const MqlRates &vela) { double corpo = MathAbs(vela.close - vela.open); double sombraInferior = (vela.close > vela.open) ? (vela.open - vela.low) : (vela.close - vela.low); double sombraSuperior = (vela.close > vela.open) ? (vela.high - vela.close) : (vela.high - vela.open); double range = vela.high - vela.low; // Martelo: sombra inferior > 2x corpo e sombra superior pequena return (sombraInferior > 2 * corpo && sombraSuperior < corpo * 0.3 && range > 0); } //--- Detectar padrão de estrela cadente bool IsEstrelaCadente(const MqlRates &vela) { double corpo = MathAbs(vela.close - vela.open); double sombraInferior = (vela.close > vela.open) ? (vela.open - vela.low) : (vela.close - vela.low); double sombraSuperior = (vela.close > vela.open) ? (vela.high - vela.close) : (vela.high - vela.open); // Estrela cadente: sombra superior > 2x corpo e sombra inferior pequena return (sombraSuperior > 2 * corpo && sombraInferior < corpo * 0.3); } //--- Detectar engolfo de alta bool IsEngolfoAlta(const MqlRates &vela1, const MqlRates &vela2) { // Vela 1 (anterior) deve ser baixista bool vela1Baixista = vela1.close < vela1.open; // Vela 2 (atual) deve ser altista bool vela2Altista = vela2.close > vela2.open; // Vela 2 deve engolfar vela 1 bool engolfa = vela2.open < vela1.close && vela2.close > vela1.open; return vela1Baixista && vela2Altista && engolfa; } //--- Detectar engolfo de baixa bool IsEngolfoBaixa(const MqlRates &vela1, const MqlRates &vela2) { // Vela 1 (anterior) deve ser altista bool vela1Altista = vela1.close > vela1.open; // Vela 2 (atual) deve ser baixista bool vela2Baixista = vela2.close < vela2.open; // Vela 2 deve engolfar vela 1 bool engolfa = vela2.open > vela1.close && vela2.close < vela1.open; return vela1Altista && vela2Baixista && engolfa; } //--- Calcular força da tendência (baseado em sequência de velas) double CalcularForcaTendencia(const MqlRates &velas[], int periodos = 5) { int contadorAlta = 0; int contadorBaixa = 0; for(int i = 0; i < periodos && i < ArraySize(velas); i++) { if(velas[i].close > velas[i].open) contadorAlta++; else if(velas[i].close < velas[i].open) contadorBaixa++; } // Retorna valor entre -1 (forte baixa) e +1 (forte alta) return (double)(contadorAlta - contadorBaixa) / periodos; } //--- Detectar rompimento de suporte/resistência bool IsRompimentoSuporteResistencia(const MqlRates &velas[], double nivel, bool isResistencia) { if(ArraySize(velas) < 2) return false; double precoAtual = velas[0].close; double precoAnterior = velas[1].close; if(isResistencia) { // Rompimento de resistência (preço cruza acima) return (precoAnterior <= nivel && precoAtual > nivel); } else { // Rompimento de suporte (preço cruza abaixo) return (precoAnterior >= nivel && precoAtual < nivel); } } }; //+------------------------------------------------------------------+ //| Classe para análise de volume (quando disponível) | //+------------------------------------------------------------------+ class VolumeAnalyzer { public: //--- Detectar divergência de volume static bool IsDivergenciaVolume(const MqlRates &velas[], int periodos = 3) { if(ArraySize(velas) < periodos) return false; // Verificar se preço subiu mas volume diminuiu (divergência bearish) bool precoSubiu = velas[0].close > velas[periodos-1].close; bool volumeDiminuiu = velas[0].tick_volume < velas[periodos-1].tick_volume; return precoSubiu && volumeDiminuiu; } //--- Calcular volume médio static double CalcularVolumeMedia(const MqlRates &velas[], int periodos = 20) { if(ArraySize(velas) < periodos) return 0; long somaVolume = 0; for(int i = 0; i < periodos; i++) { somaVolume += velas[i].tick_volume; } return (double)somaVolume / periodos; } //--- Verificar se volume está acima da média static bool IsVolumeAcimaDaMedia(const MqlRates &velaAtual, double volumeMedia, double multiplicador = 1.5) { return velaAtual.tick_volume > (volumeMedia * multiplicador); } }; //+------------------------------------------------------------------+ //| Classe para cálculos de suporte e resistência | //+------------------------------------------------------------------+ class SuporteResistencia { public: //--- Calcular suporte e resistência baseado em pivôs struct NiveisSR { double suporte1; double suporte2; double resistencia1; double resistencia2; double pontosPivo; }; static NiveisSR CalcularNiveisDiarios(string simbolo) { NiveisSR niveis = {0}; // Obter dados do dia anterior MqlRates day[]; if(CopyRates(simbolo, PERIOD_D1, 1, 1, day) > 0) { double high = day[0].high; double low = day[0].low; double close = day[0].close; // Calcular ponto pivô niveis.pontosPivo = (high + low + close) / 3.0; // Calcular suportes e resistências niveis.resistencia1 = (2 * niveis.pontosPivo) - low; niveis.suporte1 = (2 * niveis.pontosPivo) - high; niveis.resistencia2 = niveis.pontosPivo + (high - low); niveis.suporte2 = niveis.pontosPivo - (high - low); } return niveis; } //--- Encontrar máximas e mínimas locais static double EncontrarMaximaLocal(const MqlRates &velas[], int periodos = 10) { if(ArraySize(velas) < periodos) return 0; double maxima = velas[0].high; for(int i = 1; i < periodos; i++) { if(velas[i].high > maxima) maxima = velas[i].high; } return maxima; } static double EncontrarMinimaLocal(const MqlRates &velas[], int periodos = 10) { if(ArraySize(velas) < periodos) return 0; double minima = velas[0].low; for(int i = 1; i < periodos; i++) { if(velas[i].low < minima) minima = velas[i].low; } return minima; } }; //+------------------------------------------------------------------+ //| Classe para detecção de padrões de velas | //+------------------------------------------------------------------+ class PadroesVelas { public: //--- Detectar inside bar (vela interior) static bool IsInsideBar(const MqlRates &vela1, const MqlRates &vela2) { return (vela2.high < vela1.high && vela2.low > vela1.low); } //--- Detectar outside bar (vela exterior) static bool IsOutsideBar(const MqlRates &vela1, const MqlRates &vela2) { return (vela2.high > vela1.high && vela2.low < vela1.low); } //--- Detectar pin bar static bool IsPinBar(const MqlRates &vela, bool isPinBarAlta = true) { double corpo = MathAbs(vela.close - vela.open); double range = vela.high - vela.low; double sombra = isPinBarAlta ? (vela.low - MathMin(vela.open, vela.close)) : (MathMax(vela.open, vela.close) - vela.high); // Pin bar deve ter sombra > 60% do range e corpo < 30% do range return (sombra > range * 0.6 && corpo < range * 0.3); } //--- Detectar doji static bool IsDoji(const MqlRates &vela) { double corpo = MathAbs(vela.close - vela.open); double range = vela.high - vela.low; // Doji: corpo muito pequeno comparado ao range return (corpo < range * 0.1 && range > 0); } //--- Detectar vela de indecisão static bool IsVelaIndecisao(const MqlRates &vela) { double corpo = MathAbs(vela.close - vela.open); double sombraInferior = MathMin(vela.open, vela.close) - vela.low; double sombraSuperior = vela.high - MathMax(vela.open, vela.close); // Vela de indecisão: sombras longas e corpo pequeno return (sombraInferior > corpo && sombraSuperior > corpo); } }; //+------------------------------------------------------------------+ //| Classe para análise de momentum | //+------------------------------------------------------------------+ class MomentumAnalyzer { public: //--- Calcular momentum baseado em preços static double CalcularMomentum(const MqlRates &velas[], int periodo = 10) { if(ArraySize(velas) < periodo) return 0; double precoAtual = velas[0].close; double precoAnterior = velas[periodo-1].close; return precoAtual - precoAnterior; } //--- Calcular taxa de mudança (ROC) static double CalcularROC(const MqlRates &velas[], int periodo = 10) { if(ArraySize(velas) < periodo) return 0; double precoAtual = velas[0].close; double precoAnterior = velas[periodo-1].close; if(precoAnterior == 0) return 0; return ((precoAtual - precoAnterior) / precoAnterior) * 100; } //--- Detectar divergência de momentum static bool IsDivergenciaMomentum(const MqlRates &velas[], int periodo = 5) { if(ArraySize(velas) < periodo * 2) return false; // Calcular momentum para dois períodos double momentum1 = CalcularMomentum(velas, periodo); double momentum2 = CalcularMomentum(velas, periodo * 2); // Verificar divergência bool precoSubindo = velas[0].close > velas[periodo].close; bool momentumDiminuindo = momentum1 < momentum2; return precoSubindo && momentumDiminuindo; } }; //+------------------------------------------------------------------+ //| Classe para filtros de entrada | //+------------------------------------------------------------------+ class FiltrosEntrada { public: //--- Filtro de spread static bool IsFiltroSpread(string simbolo, double maxSpreadPontos = 3.0) { double ask = SymbolInfoDouble(simbolo, SYMBOL_ASK); double bid = SymbolInfoDouble(simbolo, SYMBOL_BID); double point = SymbolInfoDouble(simbolo, SYMBOL_POINT); double spreadAtual = (ask - bid) / point; return spreadAtual <= maxSpreadPontos; } //--- Filtro de volatilidade mínima static bool IsFiltroVolatilidadeMinima(const MqlRates &velas[], double minRange = 30.0) { if(ArraySize(velas) < 5) return false; double rangeMedia = 0; for(int i = 0; i < 5; i++) { rangeMedia += (velas[i].high - velas[i].low); } rangeMedia /= 5.0; double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT); double rangePontos = rangeMedia / point; return rangePontos >= minRange; } //--- Filtro de horário de trading static bool IsFiltroHorario() { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); // Evitar primeiros e últimos minutos da sessão int horaMinuto = dt.hour * 100 + dt.min; // Evitar 09:15-09:20 e 17:55-18:00 if((horaMinuto >= 915 && horaMinuto < 920) || (horaMinuto >= 1755)) return false; return true; } //--- Filtro combinado static bool TodosFiltrosOK(string simbolo, const MqlRates &velas[]) { return IsFiltroSpread(simbolo) && IsFiltroVolatilidadeMinima(velas) && IsFiltroHorario(); } };