package br.com.kronus.core;
import java.util.ArrayList;
import java.util.List;
import br.com.sl.domain.model.Candle;
import br.com.sl.domain.util.BigDecimalUtils;
/**
* Detector de padrões de gatilhos (GR, G1, G2, G3, G4)
* trabalhando tanto em modo backtest quanto em modo tempo real.
*
* Regras implementadas (texto alinhado):
*
* COMPRADOR
* ---------
* 1) Candle A comprador, candidato à referência.
* - Após A deve haver mudança de tendência (B).
* - A deve ser o último da tendência compradora:
* o primeiro candle direcional após A (ignorando inside/neutros)
* deve ser vendedor (B). Se for comprador, descarta A.
*
* 2) Ajuste da referência com B:
* - Se B (vendedor) tiver TOPO maior que o topo de A,
* B passa a ser o candidato à referência.
* Senão, A permanece como candidato.
*
* 3) G1:
* - A partir do candidato à referência, o primeiro candle vendedor
* subsequente que romper o FUNDO do candidato (mínima < mínima do candidato)
* será o G1. O candidato torna-se o GR.
*
* 4) G2:
* - Após o G1, assim que houver nova mudança de tendência para compradora:
* * encontrar o primeiro comprador após G1 (ignorando inside/neutros);
* * seguir a sequência compradora até aparecer vendedor.
* * durante essa sequência:
* - se houver OUTSIDE (atual rompe topo e fundo do anterior) => descarta.
* - se ALGUM candle romper o TOPO do GR (máxima > máxima GR) => descarta.
* * o ÚLTIMO candle dessa tendência compradora deve ter o fechamento
* dentro da região total do GR (mínimaGR <= fechamento <= máximaGR).
* * se virar vendedor sem atingir a região do GR => descarta.
* * caso válido, esse último comprador é o G2.
*
* 5) G3:
* - Após o G2, o PRÓXIMO candle direcional deve ser vendedor.
* se for comprador => padrão apenas até G2 (parcial).
* - numa sequência vendedora:
* * se houver OUTSIDE => descarta.
* * se algum candle vendedor romper o fundo de G2 (mínima < mínima G2)
* e tiver topo <= topo do GR => G3.
* * se surgir candle que rompa o TOPO do GR (máxima > máximaGR) ANTES do G3,
* o padrão é descartado.
*
* 6) G4:
* - Após o G3, se o PRÓXIMO candle romper o topo do GR (máxima > máximaGR),
* será o G4. Depois disso, o padrão é encerrado e um novo padrão é buscado.
*
* VENDEDOR
* --------
* 1) Candle A vendedor, candidato à referência.
* - Após A deve haver mudança de tendência (B).
* - A deve ser o último da tendência vendedora:
* o primeiro candle direcional após A (ignorando inside/neutros)
* deve ser comprador (B). Se for vendedor, descarta A.
*
* 2) Ajuste da referência com B:
* - Se B (comprador) tiver FUNDO mais baixo (mínima menor) que o fundo de A,
* B passa a ser candidato à referência.
* Senão, A permanece como candidato.
*
* 3) G1:
* - A partir do candidato à referência, o primeiro candle comprador
* subsequente que romper o TOPO do candidato (máxima > máxima do candidato)
* será o G1. O candidato torna-se o GR.
*
* 4) G2:
* - Após o G1, nova mudança para tendência vendedora:
* * encontrar o primeiro vendedor após G1 (ignorando inside/neutros);
* * seguir a sequência vendedora até aparecer comprador.
* * durante essa sequência:
* - se houver OUTSIDE => descarta.
* - se algum candle romper o FUNDO do GR (mínima < mínimaGR) => descarta.
* * o ÚLTIMO candle dessa tendência vendedora deve ter o fechamento
* dentro da região total do GR (mínimaGR <= fechamento <= máximaGR).
* * se virar comprador sem atingir a região do GR => descarta.
* * caso válido, esse último vendedor é o G2.
*
* 5) G3:
* - Após o G2, o PRÓXIMO candle direcional deve ser comprador.
* se for vendedor => padrão apenas até G2 (parcial).
* - numa sequência compradora:
* * se houver OUTSIDE => descarta.
* * se algum candle comprador romper o topo de G2 (máxima > máxima G2)
* e tiver fundo >= fundo do GR => G3.
* * se algum candle romper o FUNDO do GR (mínima < mínimaGR)
* ANTES do G3 => descarta.
*
* 6) G4:
* - Após o G3, se o PRÓXIMO candle romper o fundo do GR (mínima < mínimaGR),
* será o G4. Depois disso, o padrão é encerrado e um novo padrão é buscado.
*
* OUTSIDE (ambos os lados):
* - Candle cuja máxima > máxima do candle anterior E mínima < mínima do candle anterior.
* - Se houver um outside antes de identificar o G3, o padrão é descartado.
*/
public class DetectorGatilhos
{
private final boolean logAtivo
;
private int idxProximaAnaliseTempoReal =
0;
public DetectorGatilhos
() {
this(false);
}
public DetectorGatilhos
(boolean logAtivo
) {
this.
logAtivo = logAtivo
;
}
private void log
(String msg
) {
if (logAtivo
) {
System.
out.
println(msg
);
}
}
private static class ResultadoPadrao
{
PadraoGatilho padrao
;
int lastIndex
;
ResultadoPadrao
(PadraoGatilho padrao,
int lastIndex
) {
this.
padrao = padrao
;
this.
lastIndex = lastIndex
;
}
}
private ResultadoPadrao criarResultadoParcialComG2
(Candle ref,
Candle g1,
Candle g2,
int lastIndex
) {
PadraoGatilho padrao =
new PadraoGatilho
();
padrao.
setReferencia(ref
);
padrao.
setGatilho1(g1
);
padrao.
setGatilho2(g2
);
padrao.
setGatilho3(null);
padrao.
setGatilho4(null);
return new ResultadoPadrao
(padrao, lastIndex
);
}
// =====================================================================
// API PRINCIPAL – BACKTEST
// =====================================================================
public List<PadraoGatilho
> identificarPadroes
(List<Candle
> candles
) {
List<PadraoGatilho
> padroes =
new ArrayList<>();
int n = candles.
size();
if (n
< 4) return padroes
;
int idxRef =
0;
while (idxRef
< n -
3) {
ResultadoPadrao resultado = detectarPadraoAPartir
(candles, idxRef
);
if (resultado ==
null) {
idxRef++
;
continue;
}
if (resultado.
padrao !=
null) {
padroes.
add(resultado.
padrao);
}
idxRef =
Math.
max(resultado.
lastIndex +
1, idxRef +
1);
}
return padroes
;
}
private ResultadoPadrao detectarPadraoAPartir
(List<Candle
> candles,
int idxRef
) {
Candle ref = candles.
get(idxRef
);
if (ref.
isCandleComprador()) {
return detectarPadraoComprador
(candles, idxRef
);
} else if (ref.
isCandleVendedor()) {
return detectarPadraoVendedor
(candles, idxRef
);
} else {
return new ResultadoPadrao
(null, idxRef
);
}
}
// =====================================================================
// HELPERS
// =====================================================================
private boolean isInside
(List<Candle
> candles,
int idx
) {
if (idx
<=
0) return false;
Candle atual = candles.
get(idx
);
Candle anterior = candles.
get(idx -
1);
return BigDecimalUtils.
ehMenorOuIgualQue(atual.
getMaxima(), anterior.
getMaxima())
&& BigDecimalUtils.
ehMaiorOuIgualQue(atual.
getMinima(), anterior.
getMinima());
}
private boolean isOutside
(List<Candle
> candles,
int idx
) {
if (idx
<=
0) return false;
Candle atual = candles.
get(idx
);
Candle anterior = candles.
get(idx -
1);
return BigDecimalUtils.
ehMaiorQue(atual.
getMaxima(), anterior.
getMaxima())
&& BigDecimalUtils.
ehMenorQue(atual.
getMinima(), anterior.
getMinima());
}
// =====================================================================
// CASO 1 – PADRÃO A PARTIR DE CANDLE COMPRADOR
// =====================================================================
private ResultadoPadrao detectarPadraoComprador
(List<Candle
> candles,
int idxA
) {
int n = candles.
size();
int lastIndex = idxA
;
Candle candleA = candles.
get(idxA
);
if (!candleA.
isCandleComprador()) {
return new ResultadoPadrao
(null, idxA
);
}
// 1) A deve ser último da tendência compradora -> achar B vendedor
int idxB = -
1;
for (int i = idxA +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor())) {
continue;
}
if (c.
isCandleComprador()) {
// A não é o último comprador
return new ResultadoPadrao
(null, idxA
);
}
if (c.
isCandleVendedor()) {
idxB = i
;
break;
}
}
if (idxB == -
1) return new ResultadoPadrao
(null, idxA
);
Candle candleB = candles.
get(idxB
);
// 2) Candidato à referência: A ou B (conforme topo)
Candle candidatoRef = candleA
;
int idxCandidatoRef = idxA
;
if (BigDecimalUtils.
ehMaiorQue(candleB.
getMaxima(), candleA.
getMaxima())) {
candidatoRef = candleB
;
idxCandidatoRef = idxB
;
}
// 3) G1 – primeiro vendedor que rompe fundo do candidatoRef
Candle g1 =
null;
int idxG1 = -
1;
for (int i = idxCandidatoRef +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor())) {
continue;
}
if (!c.
isCandleVendedor()) {
lastIndex = i -
1;
return new ResultadoPadrao
(null, lastIndex
);
}
lastIndex = i
;
if (BigDecimalUtils.
ehMenorQue(c.
getMinima(), candidatoRef.
getMinima())) {
g1 = c
;
idxG1 = i
;
break;
}
}
if (g1 ==
null) return new ResultadoPadrao
(null, lastIndex
);
Candle gr = candidatoRef
;
int idxGR = idxCandidatoRef
;
log
(String.
format("GR comprador em [%d], G1 (vendedor) em [%d]", idxGR, idxG1
));
// 4) G2 – nova tendência compradora com fechamento dentro da região do GR
Candle g2 =
null;
int idxG2 = -
1;
int idxPrimeiroComprador = -
1;
for (int i = idxG1 +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleComprador()) {
idxPrimeiroComprador = i
;
break;
} else {
// ainda vendedor
lastIndex = i
;
}
}
if (idxPrimeiroComprador == -
1) return new ResultadoPadrao
(null, lastIndex
);
Candle ultimoComprador =
null;
int idxUltimoComprador = -
1;
for (int i = idxPrimeiroComprador
; i
< n
; i++
) {
Candle c = candles.
get(i
);
// outside antes de G3 descarta
if (isOutside
(candles, i
)) {
lastIndex = i
;
log
(String.
format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (comprador).", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleComprador()) {
// se romper topo do GR, descarta
if (BigDecimalUtils.
ehMaiorQue(c.
getMaxima(), gr.
getMaxima())) {
lastIndex = i
;
log
(String.
format("GR[%d]: candle [%d] rompeu topo do GR durante G2.", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
ultimoComprador = c
;
idxUltimoComprador = i
;
lastIndex = i
;
} else if (c.
isCandleVendedor()) {
// terminou tendência compradora
lastIndex = i -
1;
break;
}
}
if (ultimoComprador ==
null) return new ResultadoPadrao
(null, lastIndex
);
boolean fechamentoDentroRegiaoGR =
BigDecimalUtils.
ehMaiorOuIgualQue(ultimoComprador.
getFechamento(), gr.
getMinima()) &&
BigDecimalUtils.
ehMenorOuIgualQue(ultimoComprador.
getFechamento(), gr.
getMaxima());
if (!fechamentoDentroRegiaoGR
) {
return new ResultadoPadrao
(null, lastIndex
);
}
g2 = ultimoComprador
;
idxG2 = idxUltimoComprador
;
log
(String.
format("GR[%d], G1[%d] => G2 (comprador) em [%d]", idxGR, idxG1, idxG2
));
// 5) G3 – próximo direcional vendedor; vendedor que rompe fundo de G2 com topo <= topo GR
Candle g3 =
null;
int idxG3 = -
1;
int idxPrimeiroVendedorAposG2 = -
1;
for (int i = idxG2 +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleVendedor()) {
idxPrimeiroVendedorAposG2 = i
;
break;
} else {
// primeiro direcional não é vendedor => padrão só até G2
lastIndex = i
;
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
}
}
if (idxPrimeiroVendedorAposG2 == -
1)
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
for (int i = idxPrimeiroVendedorAposG2
; i
< n
; i++
) {
Candle c = candles.
get(i
);
// outside antes de G3 descarta
if (isOutside
(candles, i
)) {
lastIndex = i
;
log
(String.
format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (vendedor).", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
// se romper topo do GR antes de G3 => descarta
if (BigDecimalUtils.
ehMaiorQue(c.
getMaxima(), gr.
getMaxima())) {
lastIndex = i
;
log
(String.
format("GR[%d]: candle [%d] rompeu topo do GR antes de G3.", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (!c.
isCandleVendedor()) {
lastIndex = i -
1;
break;
}
lastIndex = i
;
boolean rompeFundoG2 = BigDecimalUtils.
ehMenorQue(c.
getMinima(), g2.
getMinima());
boolean topoMenorOuIgualGR = BigDecimalUtils.
ehMenorOuIgualQue(c.
getMaxima(), gr.
getMaxima());
if (rompeFundoG2
&& topoMenorOuIgualGR
) {
g3 = c
;
idxG3 = i
;
break;
}
}
if (g3 ==
null)
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
log
(String.
format("GR[%d], G1[%d], G2[%d] => G3 (vendedor) em [%d]",
idxGR, idxG1, idxG2, idxG3
));
// 6) G4 – próximo candle rompe topo do GR
Candle g4 =
null;
int proxIdx = idxG3 +
1;
if (proxIdx
< n
) {
Candle c = candles.
get(proxIdx
);
lastIndex = proxIdx
;
if (BigDecimalUtils.
ehMaiorQue(c.
getMaxima(), gr.
getMaxima())) {
g4 = c
;
log
(String.
format("GR[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]",
idxGR, idxG1, idxG2, idxG3, proxIdx
));
} else {
log
(String.
format("GR[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.",
idxGR, idxG1, idxG2, idxG3, proxIdx
));
}
}
PadraoGatilho padrao =
new PadraoGatilho
();
padrao.
setReferencia(gr
);
padrao.
setGatilho1(g1
);
padrao.
setGatilho2(g2
);
padrao.
setGatilho3(g3
);
padrao.
setGatilho4(g4
);
return new ResultadoPadrao
(padrao, lastIndex
);
}
// =====================================================================
// CASO 2 – PADRÃO A PARTIR DE CANDLE VENDEDOR
// =====================================================================
private ResultadoPadrao detectarPadraoVendedor
(List<Candle
> candles,
int idxA
) {
int n = candles.
size();
int lastIndex = idxA
;
Candle candleA = candles.
get(idxA
);
if (!candleA.
isCandleVendedor()) {
return new ResultadoPadrao
(null, idxA
);
}
// 1) A deve ser último da tendência vendedora -> achar B comprador
int idxB = -
1;
for (int i = idxA +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleVendedor()) {
return new ResultadoPadrao
(null, idxA
);
}
if (c.
isCandleComprador()) {
idxB = i
;
break;
}
}
if (idxB == -
1) return new ResultadoPadrao
(null, idxA
);
Candle candleB = candles.
get(idxB
);
// 2) Candidato à referência: A ou B (conforme fundo)
Candle candidatoRef = candleA
;
int idxCandidatoRef = idxA
;
if (BigDecimalUtils.
ehMenorQue(candleB.
getMinima(), candleA.
getMinima())) {
candidatoRef = candleB
;
idxCandidatoRef = idxB
;
}
// 3) G1 – primeiro comprador que rompe topo do candidatoRef
Candle g1 =
null;
int idxG1 = -
1;
for (int i = idxCandidatoRef +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (!c.
isCandleComprador()) {
lastIndex = i -
1;
return new ResultadoPadrao
(null, lastIndex
);
}
lastIndex = i
;
if (BigDecimalUtils.
ehMaiorQue(c.
getMaxima(), candidatoRef.
getMaxima())) {
g1 = c
;
idxG1 = i
;
break;
}
}
if (g1 ==
null) return new ResultadoPadrao
(null, lastIndex
);
Candle gr = candidatoRef
;
int idxGR = idxCandidatoRef
;
log
(String.
format("GR vendedor em [%d], G1 (comprador) em [%d]", idxGR, idxG1
));
// 4) G2 – nova tendência vendedora com fechamento dentro da região do GR
Candle g2 =
null;
int idxG2 = -
1;
int idxPrimeiroVendedor = -
1;
for (int i = idxG1 +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleVendedor()) {
idxPrimeiroVendedor = i
;
break;
} else {
lastIndex = i
;
}
}
if (idxPrimeiroVendedor == -
1) return new ResultadoPadrao
(null, lastIndex
);
Candle ultimoVendedor =
null;
int idxUltimoVendedor = -
1;
boolean rompeuFundoGR =
false;
for (int i = idxPrimeiroVendedor
; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isOutside
(candles, i
)) {
lastIndex = i
;
log
(String.
format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (vendedor).", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleVendedor()) {
// se romper fundo do GR, descarta
if (BigDecimalUtils.
ehMenorQue(c.
getMinima(), gr.
getMinima())) {
rompeuFundoGR =
true;
lastIndex = i
;
break;
}
ultimoVendedor = c
;
idxUltimoVendedor = i
;
lastIndex = i
;
} else if (c.
isCandleComprador()) {
lastIndex = i -
1;
break;
}
}
if (rompeuFundoGR || ultimoVendedor ==
null)
return new ResultadoPadrao
(null, lastIndex
);
boolean fechamentoDentroRegiaoGR =
BigDecimalUtils.
ehMaiorOuIgualQue(ultimoVendedor.
getFechamento(), gr.
getMinima()) &&
BigDecimalUtils.
ehMenorOuIgualQue(ultimoVendedor.
getFechamento(), gr.
getMaxima());
if (!fechamentoDentroRegiaoGR
)
return new ResultadoPadrao
(null, lastIndex
);
g2 = ultimoVendedor
;
idxG2 = idxUltimoVendedor
;
log
(String.
format("GR[%d], G1[%d] => G2 (vendedor) em [%d]", idxGR, idxG1, idxG2
));
// 5) G3 – próximo direcional comprador; comprador que rompe topo de G2 com fundo >= fundo GR
Candle g3 =
null;
int idxG3 = -
1;
int idxPrimeiroCompradorAposG2 = -
1;
for (int i = idxG2 +
1; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
if (c.
isCandleComprador()) {
idxPrimeiroCompradorAposG2 = i
;
break;
} else {
lastIndex = i
;
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
}
}
if (idxPrimeiroCompradorAposG2 == -
1)
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
for (int i = idxPrimeiroCompradorAposG2
; i
< n
; i++
) {
Candle c = candles.
get(i
);
if (isOutside
(candles, i
)) {
lastIndex = i
;
log
(String.
format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (comprador).", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (isInside
(candles, i
) ||
(!c.
isCandleComprador() && !c.
isCandleVendedor()))
continue;
// se romper fundo do GR antes de G3 => descarta
if (BigDecimalUtils.
ehMenorQue(c.
getMinima(), gr.
getMinima())) {
lastIndex = i
;
log
(String.
format("GR[%d]: candle [%d] rompeu fundo do GR antes de G3.", idxGR, i
));
return new ResultadoPadrao
(null, lastIndex
);
}
if (!c.
isCandleComprador()) {
lastIndex = i -
1;
break;
}
lastIndex = i
;
boolean rompeTopoG2 = BigDecimalUtils.
ehMaiorQue(c.
getMaxima(), g2.
getMaxima());
boolean fundoMaiorOuIgualGR = BigDecimalUtils.
ehMaiorOuIgualQue(c.
getMinima(), gr.
getMinima());
if (rompeTopoG2
&& fundoMaiorOuIgualGR
) {
g3 = c
;
idxG3 = i
;
break;
}
}
if (g3 ==
null)
return criarResultadoParcialComG2
(gr, g1, g2, lastIndex
);
log
(String.
format("GR[%d], G1[%d], G2[%d] => G3 (comprador) em [%d]",
idxGR, idxG1, idxG2, idxG3
));
// 6) G4 – próximo candle rompe fundo do GR
Candle g4 =
null;
int proxIdx = idxG3 +
1;
if (proxIdx
< n
) {
Candle c = candles.
get(proxIdx
);
lastIndex = proxIdx
;
if (BigDecimalUtils.
ehMenorQue(c.
getMinima(), gr.
getMinima())) {
g4 = c
;
log
(String.
format("GR[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]",
idxGR, idxG1, idxG2, idxG3, proxIdx
));
} else {
log
(String.
format("GR[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.",
idxGR, idxG1, idxG2, idxG3, proxIdx
));
}
}
PadraoGatilho padrao =
new PadraoGatilho
();
padrao.
setReferencia(gr
);
padrao.
setGatilho1(g1
);
padrao.
setGatilho2(g2
);
padrao.
setGatilho3(g3
);
padrao.
setGatilho4(g4
);
return new ResultadoPadrao
(padrao, lastIndex
);
}
// =====================================================================
// MODO TEMPO REAL
// =====================================================================
public void resetTempoReal
() {
this.
idxProximaAnaliseTempoReal =
0;
}
public PadraoGatilho processarCandleTempoReal
(List<Candle
> candles
) {
int n = candles.
size();
if (n
< 4) return null;
while (idxProximaAnaliseTempoReal
< n -
3) {
ResultadoPadrao resultado = detectarPadraoAPartir
(candles, idxProximaAnaliseTempoReal
);
if (resultado ==
null) {
idxProximaAnaliseTempoReal++
;
continue;
}
int proximoInicio = resultado.
lastIndex +
1;
if (proximoInicio
<= idxProximaAnaliseTempoReal
) {
proximoInicio = idxProximaAnaliseTempoReal +
1;
}
idxProximaAnaliseTempoReal = proximoInicio
;
if (resultado.
padrao !=
null) {
return resultado.
padrao;
}
}
return null;
}
}