mt5-clear-winq25-scalper/WinQ25_Indicadores.mqh
Marcos Paulo 6ce3e66f7f WINQ25
2025-07-31 08:08:19 -03:00

385 lines
No EOL
13 KiB
MQL5

//+------------------------------------------------------------------+
//| 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();
}
};