Rev 767 | Rev 773 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 767 | Rev 771 | ||
|---|---|---|---|
| Line 1... | Line 1... | ||
| 1 | package br.com.kronus.core; |
1 | package br.com.kronus.core; |
| 2 | 2 | ||
| 3 | import java.math.BigDecimal; |
- | |
| 4 | import java.util.ArrayList; |
3 | import java.util.ArrayList; |
| 5 | import java.util.List; |
4 | import java.util.List; |
| 6 | 5 | ||
| 7 | import br.com.sl.domain.model.Candle; |
6 | import br.com.sl.domain.model.Candle; |
| 8 | import br.com.sl.domain.util.BigDecimalUtils; |
7 | import br.com.sl.domain.util.BigDecimalUtils; |
| 9 | 8 | ||
| 10 | /**
|
9 | /**
|
| 11 | * Detector de padrões de gatilhos (GR, G1, G2, G3, G4)
|
10 | * Detector de padrões de gatilhos (GR, G1, G2, G3, G4)
|
| 12 | * trabalhando tanto em modo backtest quanto em modo tempo real.
|
11 | * trabalhando tanto em modo backtest quanto em modo tempo real.
|
| 13 | *
|
12 | *
|
| 14 | * Regras resumidas:
|
- | |
| - | 13 | * Regras implementadas (texto alinhado):
|
|
| 15 | *
|
14 | *
|
| 16 | * GR comprador (A):
|
- | |
| 17 | * - Candle comprador.
|
- | |
| 18 | * - Último candle da tendência compradora.
|
- | |
| 19 | * - Maior topo da pernada compradora.
|
- | |
| 20 | * - Após ele, tendência muda para vendedora.
|
- | |
| 21 | * - Um vendedor subsequente rompe o fundo de A => G1 vendedor, A vira GR.
|
- | |
| - | 15 | * COMPRADOR
|
|
| - | 16 | * ---------
|
|
| - | 17 | * 1) Candle A comprador, candidato à referência.
|
|
| - | 18 | * - Após A deve haver mudança de tendência (B).
|
|
| - | 19 | * - A deve ser o último da tendência compradora:
|
|
| - | 20 | * o primeiro candle direcional após A (ignorando inside/neutros)
|
|
| - | 21 | * deve ser vendedor (B). Se for comprador, descarta A.
|
|
| 22 | *
|
22 | *
|
| 23 | * GR vendedor (B):
|
- | |
| 24 | * - Candle vendedor.
|
- | |
| 25 | * - Último candle da tendência vendedora.
|
- | |
| 26 | * - Menor fundo da pernada vendedora.
|
- | |
| 27 | * - Após ele, tendência muda para compradora.
|
- | |
| 28 | * - Um comprador subsequente rompe o topo de B => G1 comprador, B vira GR.
|
- | |
| - | 23 | * 2) Ajuste da referência com B:
|
|
| - | 24 | * - Se B (vendedor) tiver TOPO maior que o topo de A,
|
|
| - | 25 | * B passa a ser o candidato à referência.
|
|
| - | 26 | * Senão, A permanece como candidato.
|
|
| 29 | *
|
27 | *
|
| 30 | * G2 comprador (a partir de GR comprador):
|
- | |
| 31 | * - Após G1 (vendedor), surge nova tendência compradora.
|
- | |
| 32 | * - O ÚLTIMO candle dessa tendência compradora tem fechamento dentro da região do GR.
|
- | |
| 33 | * - Se nessa tendência compradora alguma barra romper o topo do GR, o padrão é descartado.
|
- | |
| 34 | * - Se a tendência terminar sem que o último comprador feche dentro da região do GR, descarta.
|
- | |
| - | 28 | * 3) G1:
|
|
| - | 29 | * - A partir do candidato à referência, o primeiro candle vendedor
|
|
| - | 30 | * subsequente que romper o FUNDO do candidato (mínima < mínima do candidato)
|
|
| - | 31 | * será o G1. O candidato torna-se o GR.
|
|
| 35 | *
|
32 | *
|
| 36 | * G3 comprador:
|
- | |
| 37 | * - Após G2, o próximo candle deve ser vendedor.
|
- | |
| 38 | * - Em uma sequência vendedora, algum vendedor:
|
- | |
| 39 | * * rompe o fundo de G2 (mínima < mínima de G2) e
|
- | |
| 40 | * * tem topo <= topo do GR
|
- | |
| 41 | * => esse candle é G3.
|
- | |
| - | 33 | * 4) G2:
|
|
| - | 34 | * - Após o G1, assim que houver nova mudança de tendência para compradora:
|
|
| - | 35 | * * encontrar o primeiro comprador após G1 (ignorando inside/neutros);
|
|
| - | 36 | * * seguir a sequência compradora até aparecer vendedor.
|
|
| - | 37 | * * durante essa sequência:
|
|
| - | 38 | * - se houver OUTSIDE (atual rompe topo e fundo do anterior) => descarta.
|
|
| - | 39 | * - se ALGUM candle romper o TOPO do GR (máxima > máxima GR) => descarta.
|
|
| - | 40 | * * o ÚLTIMO candle dessa tendência compradora deve ter o fechamento
|
|
| - | 41 | * dentro da região total do GR (mínimaGR <= fechamento <= máximaGR).
|
|
| - | 42 | * * se virar vendedor sem atingir a região do GR => descarta.
|
|
| - | 43 | * * caso válido, esse último comprador é o G2.
|
|
| 42 | *
|
44 | *
|
| 43 | * G4 comprador:
|
- | |
| 44 | * - Próximo candle após G3.
|
- | |
| 45 | * - Se romper o topo do GR (máxima > máxima do GR) => G4.
|
- | |
| 46 | * - Desarma a operação, padrão é encerrado, nova análise começa após esse candle.
|
- | |
| - | 45 | * 5) G3:
|
|
| - | 46 | * - Após o G2, o PRÓXIMO candle direcional deve ser vendedor.
|
|
| - | 47 | * se for comprador => padrão apenas até G2 (parcial).
|
|
| - | 48 | * - numa sequência vendedora:
|
|
| - | 49 | * * se houver OUTSIDE => descarta.
|
|
| - | 50 | * * se algum candle vendedor romper o fundo de G2 (mínima < mínima G2)
|
|
| - | 51 | * e tiver topo <= topo do GR => G3.
|
|
| - | 52 | * * se surgir candle que rompa o TOPO do GR (máxima > máximaGR) ANTES do G3,
|
|
| - | 53 | * o padrão é descartado.
|
|
| 47 | *
|
54 | *
|
| 48 | * G2 vendedor (a partir de GR vendedor):
|
- | |
| 49 | * - Após G1 (comprador), surge nova tendência vendedora.
|
- | |
| 50 | * - O ÚLTIMO candle dessa tendência vendedora tem fechamento dentro da região do GR.
|
- | |
| 51 | * - Se nessa tendência vendedora alguma barra romper o fundo do GR, o padrão é descartado.
|
- | |
| - | 55 | * 6) G4:
|
|
| - | 56 | * - Após o G3, se o PRÓXIMO candle romper o topo do GR (máxima > máximaGR),
|
|
| - | 57 | * será o G4. Depois disso, o padrão é encerrado e um novo padrão é buscado.
|
|
| 52 | *
|
58 | *
|
| 53 | * G3 vendedor:
|
- | |
| 54 | * - Após G2, o próximo candle deve ser comprador.
|
- | |
| 55 | * - Em uma sequência compradora, algum comprador:
|
- | |
| 56 | * * rompe o topo de G2 (máxima > máxima de G2) e
|
- | |
| 57 | * * tem fundo >= fundo do GR
|
- | |
| 58 | * => esse candle é G3.
|
- | |
| - | 59 | * VENDEDOR
|
|
| - | 60 | * --------
|
|
| - | 61 | * 1) Candle A vendedor, candidato à referência.
|
|
| - | 62 | * - Após A deve haver mudança de tendência (B).
|
|
| - | 63 | * - A deve ser o último da tendência vendedora:
|
|
| - | 64 | * o primeiro candle direcional após A (ignorando inside/neutros)
|
|
| - | 65 | * deve ser comprador (B). Se for vendedor, descarta A.
|
|
| 59 | *
|
66 | *
|
| 60 | * G4 vendedor:
|
- | |
| 61 | * - Próximo candle após G3.
|
- | |
| 62 | * - Se romper o fundo do GR (mínima < mínima do GR) => G4.
|
- | |
| - | 67 | * 2) Ajuste da referência com B:
|
|
| - | 68 | * - Se B (comprador) tiver FUNDO mais baixo (mínima menor) que o fundo de A,
|
|
| - | 69 | * B passa a ser candidato à referência.
|
|
| - | 70 | * Senão, A permanece como candidato.
|
|
| 63 | *
|
71 | *
|
| 64 | * Outside em relação ao GR:
|
- | |
| 65 | * - Qualquer candle C após o GR que:
|
- | |
| 66 | * * C.maxima > GR.maxima E
|
- | |
| 67 | * * C.minima < GR.minima
|
- | |
| 68 | * => padrão atual é descartado, nova análise começa após C.
|
- | |
| - | 72 | * 3) G1:
|
|
| - | 73 | * - A partir do candidato à referência, o primeiro candle comprador
|
|
| - | 74 | * subsequente que romper o TOPO do candidato (máxima > máxima do candidato)
|
|
| - | 75 | * será o G1. O candidato torna-se o GR.
|
|
| 69 | *
|
76 | *
|
| 70 | * Obs.: Quando um ciclo termina (padrão encontrado ou descartado),
|
- | |
| 71 | * a próxima análise SEMPRE começa após o último candle usado.
|
- | |
| - | 77 | * 4) G2:
|
|
| - | 78 | * - Após o G1, nova mudança para tendência vendedora:
|
|
| - | 79 | * * encontrar o primeiro vendedor após G1 (ignorando inside/neutros);
|
|
| - | 80 | * * seguir a sequência vendedora até aparecer comprador.
|
|
| - | 81 | * * durante essa sequência:
|
|
| - | 82 | * - se houver OUTSIDE => descarta.
|
|
| - | 83 | * - se algum candle romper o FUNDO do GR (mínima < mínimaGR) => descarta.
|
|
| - | 84 | * * o ÚLTIMO candle dessa tendência vendedora deve ter o fechamento
|
|
| - | 85 | * dentro da região total do GR (mínimaGR <= fechamento <= máximaGR).
|
|
| - | 86 | * * se virar comprador sem atingir a região do GR => descarta.
|
|
| - | 87 | * * caso válido, esse último vendedor é o G2.
|
|
| - | 88 | *
|
|
| - | 89 | * 5) G3:
|
|
| - | 90 | * - Após o G2, o PRÓXIMO candle direcional deve ser comprador.
|
|
| - | 91 | * se for vendedor => padrão apenas até G2 (parcial).
|
|
| - | 92 | * - numa sequência compradora:
|
|
| - | 93 | * * se houver OUTSIDE => descarta.
|
|
| - | 94 | * * se algum candle comprador romper o topo de G2 (máxima > máxima G2)
|
|
| - | 95 | * e tiver fundo >= fundo do GR => G3.
|
|
| - | 96 | * * se algum candle romper o FUNDO do GR (mínima < mínimaGR)
|
|
| - | 97 | * ANTES do G3 => descarta.
|
|
| - | 98 | *
|
|
| - | 99 | * 6) G4:
|
|
| - | 100 | * - Após o G3, se o PRÓXIMO candle romper o fundo do GR (mínima < mínimaGR),
|
|
| - | 101 | * será o G4. Depois disso, o padrão é encerrado e um novo padrão é buscado.
|
|
| - | 102 | *
|
|
| - | 103 | * OUTSIDE (ambos os lados):
|
|
| - | 104 | * - Candle cuja máxima > máxima do candle anterior E mínima < mínima do candle anterior.
|
|
| - | 105 | * - Se houver um outside antes de identificar o G3, o padrão é descartado.
|
|
| 72 | */
|
106 | */
|
| 73 | public class DetectorGatilhos { |
107 | public class DetectorGatilhos { |
| 74 | 108 | ||
| 75 | private final boolean logAtivo; |
109 | private final boolean logAtivo; |
| 76 | - | ||
| 77 | // Estado apenas para o modo tempo real
|
- | |
| 78 | private int idxProximaAnaliseTempoReal = 0; |
110 | private int idxProximaAnaliseTempoReal = 0; |
| 79 | 111 | ||
| 80 | public DetectorGatilhos() { |
112 | public DetectorGatilhos() { |
| 81 | this(false); |
113 | this(false); |
| 82 | }
|
114 | }
|
| Line 90... | Line 122... | ||
| 90 | System.out.println(msg); |
122 | System.out.println(msg); |
| 91 | }
|
123 | }
|
| 92 | }
|
124 | }
|
| 93 | 125 | ||
| 94 | private static class ResultadoPadrao { |
126 | private static class ResultadoPadrao { |
| 95 | PadraoGatilho padrao; // pode ser null (quando não houve padrão válido) |
- | |
| 96 | int lastIndex; // último índice de candle usado no ciclo |
- | |
| 97 | - | ||
| - | 127 | PadraoGatilho padrao;
|
|
| - | 128 | int lastIndex; |
|
| 98 | ResultadoPadrao(PadraoGatilho padrao, int lastIndex) { |
129 | ResultadoPadrao(PadraoGatilho padrao, int lastIndex) { |
| 99 | this.padrao = padrao; |
130 | this.padrao = padrao; |
| 100 | this.lastIndex = lastIndex; |
131 | this.lastIndex = lastIndex; |
| 101 | }
|
132 | }
|
| 102 | }
|
133 | }
|
| 103 | 134 | ||
| 104 | /**
|
- | |
| 105 | * Cria um resultado com padrão PARCIAL (até G2).
|
- | |
| 106 | * Usado quando GR, G1 e G2 são válidos, mas G3 não se forma.
|
- | |
| 107 | */
|
- | |
| 108 | private ResultadoPadrao criarResultadoParcialComG2(Candle ref, |
135 | private ResultadoPadrao criarResultadoParcialComG2(Candle ref, |
| 109 | Candle g1, |
136 | Candle g1, |
| 110 | Candle g2, |
137 | Candle g2, |
| 111 | int lastIndex) { |
138 | int lastIndex) { |
| 112 | PadraoGatilho padrao = new PadraoGatilho(); |
139 | PadraoGatilho padrao = new PadraoGatilho(); |
| Line 117... | Line 144... | ||
| 117 | padrao.setGatilho4(null); |
144 | padrao.setGatilho4(null); |
| 118 | return new ResultadoPadrao(padrao, lastIndex); |
145 | return new ResultadoPadrao(padrao, lastIndex); |
| 119 | }
|
146 | }
|
| 120 | 147 | ||
| 121 | // =====================================================================
|
148 | // =====================================================================
|
| 122 | // API PRINCIPAL – BACKTEST (lista completa de candles)
|
- | |
| - | 149 | // API PRINCIPAL – BACKTEST
|
|
| 123 | // =====================================================================
|
150 | // =====================================================================
|
| 124 | 151 | ||
| 125 | public List<PadraoGatilho> identificarPadroes(List<Candle> candles) { |
152 | public List<PadraoGatilho> identificarPadroes(List<Candle> candles) { |
| 126 | List<PadraoGatilho> padroes = new ArrayList<>(); |
153 | List<PadraoGatilho> padroes = new ArrayList<>(); |
| 127 | int n = candles.size(); |
154 | int n = candles.size(); |
| 128 | if (n < 4) { |
- | |
| 129 | return padroes; |
- | |
| 130 | }
|
- | |
| - | 155 | if (n < 4) return padroes; |
|
| 131 | 156 | ||
| 132 | int idxRef = 0; |
157 | int idxRef = 0; |
| 133 | - | ||
| 134 | while (idxRef < n - 3) { |
158 | while (idxRef < n - 3) { |
| 135 | ResultadoPadrao resultado = detectarPadraoAPartir(candles, idxRef); |
159 | ResultadoPadrao resultado = detectarPadraoAPartir(candles, idxRef); |
| 136 | 160 | ||
| 137 | if (resultado == null) { |
161 | if (resultado == null) { |
| 138 | idxRef++;
|
162 | idxRef++;
|
| Line 141... | Line 165... | ||
| 141 | 165 | ||
| 142 | if (resultado.padrao != null) { |
166 | if (resultado.padrao != null) { |
| 143 | padroes.add(resultado.padrao); |
167 | padroes.add(resultado.padrao); |
| 144 | }
|
168 | }
|
| 145 | 169 | ||
| 146 | // Próxima análise sempre começa após o último candle usado no ciclo
|
- | |
| 147 | idxRef = Math.max(resultado.lastIndex + 1, idxRef + 1); |
170 | idxRef = Math.max(resultado.lastIndex + 1, idxRef + 1); |
| 148 | }
|
171 | }
|
| 149 | 172 | ||
| 150 | return padroes; |
173 | return padroes; |
| 151 | }
|
174 | }
|
| 152 | 175 | ||
| 153 | private ResultadoPadrao detectarPadraoAPartir(List<Candle> candles, int idxRef) { |
176 | private ResultadoPadrao detectarPadraoAPartir(List<Candle> candles, int idxRef) { |
| 154 | Candle ref = candles.get(idxRef); |
177 | Candle ref = candles.get(idxRef); |
| 155 | - | ||
| 156 | if (ref.isCandleComprador()) { |
178 | if (ref.isCandleComprador()) { |
| 157 | return detectarPadraoComprador(candles, idxRef); |
179 | return detectarPadraoComprador(candles, idxRef); |
| 158 | } else if (ref.isCandleVendedor()) { |
180 | } else if (ref.isCandleVendedor()) { |
| 159 | return detectarPadraoVendedor(candles, idxRef); |
181 | return detectarPadraoVendedor(candles, idxRef); |
| 160 | } else { |
182 | } else { |
| 161 | // candle sem tendência não serve como GR
|
- | |
| 162 | return new ResultadoPadrao(null, idxRef); |
183 | return new ResultadoPadrao(null, idxRef); |
| 163 | }
|
184 | }
|
| 164 | }
|
185 | }
|
| 165 | 186 | ||
| 166 | // =====================================================================
|
187 | // =====================================================================
|
| 167 | // CASO 1 – GR COMPRADOR (candle A)
|
- | |
| - | 188 | // HELPERS
|
|
| 168 | // =====================================================================
|
189 | // =====================================================================
|
| 169 | 190 | ||
| 170 | private ResultadoPadrao detectarPadraoComprador(List<Candle> candles, int idxRef) { |
- | |
| 171 | int n = candles.size(); |
- | |
| 172 | Candle ref = candles.get(idxRef); // candidato a GR |
- | |
| 173 | int lastIndex = idxRef; |
- | |
| - | 191 | private boolean isInside(List<Candle> candles, int idx) { |
|
| - | 192 | if (idx <= 0) return false; |
|
| - | 193 | Candle atual = candles.get(idx); |
|
| - | 194 | Candle anterior = candles.get(idx - 1); |
|
| - | 195 | return BigDecimalUtils.ehMenorOuIgualQue(atual.getMaxima(), anterior.getMaxima()) |
|
| - | 196 | && BigDecimalUtils.ehMaiorOuIgualQue(atual.getMinima(), anterior.getMinima()); |
|
| - | 197 | }
|
|
| 174 | 198 | ||
| 175 | // 0) Validar se idxRef pode ser GR comprador (A)
|
- | |
| 176 | if (!ref.isCandleComprador()) { |
- | |
| 177 | return new ResultadoPadrao(null, idxRef); |
- | |
| 178 | }
|
- | |
| - | 199 | private boolean isOutside(List<Candle> candles, int idx) { |
|
| - | 200 | if (idx <= 0) return false; |
|
| - | 201 | Candle atual = candles.get(idx); |
|
| - | 202 | Candle anterior = candles.get(idx - 1); |
|
| - | 203 | return BigDecimalUtils.ehMaiorQue(atual.getMaxima(), anterior.getMaxima()) |
|
| - | 204 | && BigDecimalUtils.ehMenorQue(atual.getMinima(), anterior.getMinima()); |
|
| - | 205 | }
|
|
| 179 | 206 | ||
| 180 | // 0.1 – início da pernada compradora que termina em A
|
- | |
| 181 | int inicioTrendCompra = idxRef; |
- | |
| 182 | for (int i = idxRef - 1; i >= 0; i--) { |
- | |
| 183 | Candle c = candles.get(i); |
- | |
| 184 | if (!c.isCandleComprador()) { |
- | |
| 185 | break; |
- | |
| 186 | }
|
- | |
| 187 | inicioTrendCompra = i;
|
- | |
| - | 207 | // =====================================================================
|
|
| - | 208 | // CASO 1 – PADRÃO A PARTIR DE CANDLE COMPRADOR
|
|
| - | 209 | // =====================================================================
|
|
| - | 210 | ||
| - | 211 | private ResultadoPadrao detectarPadraoComprador(List<Candle> candles, int idxA) { |
|
| - | 212 | int n = candles.size(); |
|
| - | 213 | int lastIndex = idxA; |
|
| - | 214 | Candle candleA = candles.get(idxA); |
|
| - | 215 | if (!candleA.isCandleComprador()) { |
|
| - | 216 | return new ResultadoPadrao(null, idxA); |
|
| 188 | }
|
217 | }
|
| 189 | 218 | ||
| 190 | // 0.2 – primeiro candle direcional após A
|
- | |
| 191 | int idxPrimeiroDirecionalAposRef = -1; |
- | |
| 192 | for (int i = idxRef + 1; i < n; i++) { |
- | |
| - | 219 | // 1) A deve ser último da tendência compradora -> achar B vendedor
|
|
| - | 220 | int idxB = -1; |
|
| - | 221 | for (int i = idxA + 1; i < n; i++) { |
|
| 193 | Candle c = candles.get(i); |
222 | Candle c = candles.get(i); |
| 194 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| - | 223 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) { |
|
| 195 | continue; |
224 | continue; |
| 196 | }
|
225 | }
|
| 197 | - | ||
| 198 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 199 | if (isOutsideReferencia(ref, c)) { |
- | |
| 200 | lastIndex = i;
|
- | |
| 201 | log(String.format( |
- | |
| 202 | "RefC[%d]: OUTSIDE em [%d] antes da mudança de tendência. Padrão descartado.",
|
- | |
| 203 | idxRef, i)); |
- | |
| 204 | return new ResultadoPadrao(null, lastIndex); |
- | |
| - | 226 | if (c.isCandleComprador()) { |
|
| - | 227 | // A não é o último comprador
|
|
| - | 228 | return new ResultadoPadrao(null, idxA); |
|
| - | 229 | }
|
|
| - | 230 | if (c.isCandleVendedor()) { |
|
| - | 231 | idxB = i;
|
|
| - | 232 | break; |
|
| 205 | }
|
233 | }
|
| 206 | - | ||
| 207 | idxPrimeiroDirecionalAposRef = i;
|
- | |
| 208 | break; |
- | |
| 209 | }
|
234 | }
|
| - | 235 | if (idxB == -1) return new ResultadoPadrao(null, idxA); |
|
| 210 | 236 | ||
| 211 | if (idxPrimeiroDirecionalAposRef == -1) { |
- | |
| 212 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 213 | }
|
- | |
| - | 237 | Candle candleB = candles.get(idxB); |
|
| 214 | 238 | ||
| 215 | Candle primeiroDirecional = candles.get(idxPrimeiroDirecionalAposRef); |
- | |
| 216 | if (!primeiroDirecional.isCandleVendedor()) { |
- | |
| 217 | // primeiro direcional após A ainda é comprador → A não é último da pernada
|
- | |
| 218 | return new ResultadoPadrao(null, idxRef); |
- | |
| - | 239 | // 2) Candidato à referência: A ou B (conforme topo)
|
|
| - | 240 | Candle candidatoRef = candleA;
|
|
| - | 241 | int idxCandidatoRef = idxA; |
|
| - | 242 | if (BigDecimalUtils.ehMaiorQue(candleB.getMaxima(), candleA.getMaxima())) { |
|
| - | 243 | candidatoRef = candleB;
|
|
| - | 244 | idxCandidatoRef = idxB;
|
|
| 219 | }
|
245 | }
|
| 220 | 246 | ||
| 221 | // 0.3 – A tem o maior topo da pernada compradora
|
- | |
| 222 | BigDecimal topoRef = ref.getMaxima(); |
- | |
| 223 | for (int i = inicioTrendCompra; i <= idxRef; i++) { |
- | |
| 224 | Candle c = candles.get(i); |
- | |
| 225 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), topoRef)) { |
- | |
| 226 | return new ResultadoPadrao(null, idxRef); |
- | |
| 227 | }
|
- | |
| 228 | }
|
- | |
| 229 | - | ||
| 230 | int idxPrimeiroVendedor = idxPrimeiroDirecionalAposRef; |
- | |
| 231 | - | ||
| 232 | // 1) Encontrar G1 (vendedor que rompe o fundo do GR)
|
- | |
| - | 247 | // 3) G1 – primeiro vendedor que rompe fundo do candidatoRef
|
|
| - | 248 | Candle g1 = null; |
|
| 233 | int idxG1 = -1; |
249 | int idxG1 = -1; |
| 234 | Candle g1 = null; |
- | |
| 235 | - | ||
| 236 | for (int i = idxPrimeiroVendedor; i < n; i++) { |
- | |
| - | 250 | for (int i = idxCandidatoRef + 1; i < n; i++) { |
|
| 237 | Candle c = candles.get(i); |
251 | Candle c = candles.get(i); |
| 238 | - | ||
| 239 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 240 | if (isOutsideReferencia(ref, c)) { |
- | |
| 241 | lastIndex = i;
|
- | |
| 242 | log(String.format( |
- | |
| 243 | "RefC[%d]: OUTSIDE em [%d] durante busca de G1. Padrão descartado.",
|
- | |
| 244 | idxRef, i)); |
- | |
| 245 | return new ResultadoPadrao(null, lastIndex); |
- | |
| - | 252 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) { |
|
| - | 253 | continue; |
|
| 246 | }
|
254 | }
|
| 247 | 255 | ||
| 248 | if (!c.isCandleVendedor()) { |
256 | if (!c.isCandleVendedor()) { |
| 249 | // tendência vendedora terminou antes do rompimento
|
- | |
| 250 | lastIndex = i - 1; |
257 | lastIndex = i - 1; |
| 251 | return new ResultadoPadrao(null, lastIndex); |
258 | return new ResultadoPadrao(null, lastIndex); |
| 252 | }
|
259 | }
|
| 253 | 260 | ||
| 254 | lastIndex = i;
|
261 | lastIndex = i;
|
| 255 | - | ||
| 256 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), ref.getMinima())) { |
- | |
| - | 262 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), candidatoRef.getMinima())) { |
|
| - | 263 | g1 = c;
|
|
| 257 | idxG1 = i;
|
264 | idxG1 = i;
|
| 258 | g1 = c;
|
- | |
| 259 | break; |
265 | break; |
| 260 | }
|
266 | }
|
| 261 | }
|
267 | }
|
| 262 | 268 | ||
| 263 | if (idxG1 == -1) { |
- | |
| 264 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 265 | }
|
- | |
| - | 269 | if (g1 == null) return new ResultadoPadrao(null, lastIndex); |
|
| - | 270 | ||
| - | 271 | Candle gr = candidatoRef;
|
|
| - | 272 | int idxGR = idxCandidatoRef; |
|
| - | 273 | log(String.format("GR comprador em [%d], G1 (vendedor) em [%d]", idxGR, idxG1)); |
|
| 266 | 274 | ||
| 267 | log(String.format("RefC[%d] (GR) => G1 (vendedor) em [%d]", idxRef, idxG1)); |
- | |
| - | 275 | // 4) G2 – nova tendência compradora com fechamento dentro da região do GR
|
|
| - | 276 | Candle g2 = null; |
|
| - | 277 | int idxG2 = -1; |
|
| 268 | 278 | ||
| 269 | // 2) Encontrar G2 (retorno comprador à região do GR)
|
- | |
| 270 | int idxPrimeiroComprador = -1; |
279 | int idxPrimeiroComprador = -1; |
| 271 | for (int i = idxG1 + 1; i < n; i++) { |
280 | for (int i = idxG1 + 1; i < n; i++) { |
| 272 | Candle c = candles.get(i); |
281 | Candle c = candles.get(i); |
| - | 282 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 283 | continue; |
|
| 273 | 284 | ||
| 274 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 275 | if (isOutsideReferencia(ref, c)) { |
- | |
| 276 | lastIndex = i;
|
- | |
| 277 | log(String.format( |
- | |
| 278 | "RefC[%d]: OUTSIDE em [%d] antes da tendência de G2. Padrão descartado.",
|
- | |
| 279 | idxRef, i)); |
- | |
| 280 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 281 | }
|
- | |
| 282 | - | ||
| 283 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| 284 | continue; |
- | |
| 285 | }
|
- | |
| 286 | if (c.isCandleComprador()) { |
285 | if (c.isCandleComprador()) { |
| 287 | idxPrimeiroComprador = i;
|
286 | idxPrimeiroComprador = i;
|
| 288 | break; |
287 | break; |
| 289 | } else { |
288 | } else { |
| - | 289 | // ainda vendedor
|
|
| 290 | lastIndex = i;
|
290 | lastIndex = i;
|
| 291 | }
|
291 | }
|
| 292 | }
|
292 | }
|
| 293 | 293 | ||
| 294 | if (idxPrimeiroComprador == -1) { |
- | |
| 295 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 296 | }
|
- | |
| - | 294 | if (idxPrimeiroComprador == -1) return new ResultadoPadrao(null, lastIndex); |
|
| 297 | 295 | ||
| 298 | boolean rompeuTopoRef = false; |
- | |
| 299 | Candle ultimoCompradorTrend = null; |
- | |
| 300 | int idxUltimoCompradorTrend = -1; |
- | |
| - | 296 | Candle ultimoComprador = null; |
|
| - | 297 | int idxUltimoComprador = -1; |
|
| 301 | 298 | ||
| 302 | for (int i = idxPrimeiroComprador; i < n; i++) { |
299 | for (int i = idxPrimeiroComprador; i < n; i++) { |
| 303 | Candle c = candles.get(i); |
300 | Candle c = candles.get(i); |
| 304 | 301 | ||
| 305 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 306 | if (isOutsideReferencia(ref, c)) { |
- | |
| - | 302 | // outside antes de G3 descarta
|
|
| - | 303 | if (isOutside(candles, i)) { |
|
| 307 | lastIndex = i;
|
304 | lastIndex = i;
|
| 308 | log(String.format( |
- | |
| 309 | "RefC[%d]: OUTSIDE em [%d] durante formação de G2. Padrão descartado.",
|
- | |
| 310 | idxRef, i)); |
- | |
| - | 305 | log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (comprador).", idxGR, i)); |
|
| 311 | return new ResultadoPadrao(null, lastIndex); |
306 | return new ResultadoPadrao(null, lastIndex); |
| 312 | }
|
307 | }
|
| 313 | 308 | ||
| 314 | if (!c.isCandleComprador()) { |
- | |
| 315 | break; |
- | |
| 316 | }
|
- | |
| - | 309 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 310 | continue; |
|
| 317 | 311 | ||
| 318 | ultimoCompradorTrend = c;
|
- | |
| 319 | idxUltimoCompradorTrend = i;
|
- | |
| 320 | lastIndex = i;
|
- | |
| 321 | - | ||
| 322 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), ref.getMaxima())) { |
- | |
| 323 | rompeuTopoRef = true; |
- | |
| - | 312 | if (c.isCandleComprador()) { |
|
| - | 313 | // se romper topo do GR, descarta
|
|
| - | 314 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) { |
|
| - | 315 | lastIndex = i;
|
|
| - | 316 | log(String.format("GR[%d]: candle [%d] rompeu topo do GR durante G2.", idxGR, i)); |
|
| - | 317 | return new ResultadoPadrao(null, lastIndex); |
|
| - | 318 | }
|
|
| - | 319 | ultimoComprador = c;
|
|
| - | 320 | idxUltimoComprador = i;
|
|
| - | 321 | lastIndex = i;
|
|
| - | 322 | } else if (c.isCandleVendedor()) { |
|
| - | 323 | // terminou tendência compradora
|
|
| - | 324 | lastIndex = i - 1; |
|
| 324 | break; |
325 | break; |
| 325 | }
|
326 | }
|
| 326 | }
|
327 | }
|
| 327 | 328 | ||
| 328 | if (rompeuTopoRef || idxUltimoCompradorTrend == -1) { |
- | |
| 329 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 330 | }
|
- | |
| - | 329 | if (ultimoComprador == null) return new ResultadoPadrao(null, lastIndex); |
|
| 331 | 330 | ||
| 332 | boolean fechamentoDentroRegiaoRef =
|
- | |
| 333 | BigDecimalUtils.ehMaiorOuIgualQue(ultimoCompradorTrend.getFechamento(), ref.getMinima()) && |
- | |
| 334 | BigDecimalUtils.ehMenorOuIgualQue(ultimoCompradorTrend.getFechamento(), ref.getMaxima()); |
- | |
| - | 331 | boolean fechamentoDentroRegiaoGR =
|
|
| - | 332 | BigDecimalUtils.ehMaiorOuIgualQue(ultimoComprador.getFechamento(), gr.getMinima()) && |
|
| - | 333 | BigDecimalUtils.ehMenorOuIgualQue(ultimoComprador.getFechamento(), gr.getMaxima()); |
|
| 335 | 334 | ||
| 336 | if (!fechamentoDentroRegiaoRef) { |
- | |
| - | 335 | if (!fechamentoDentroRegiaoGR) { |
|
| 337 | return new ResultadoPadrao(null, lastIndex); |
336 | return new ResultadoPadrao(null, lastIndex); |
| 338 | }
|
337 | }
|
| 339 | 338 | ||
| 340 | Candle g2 = ultimoCompradorTrend;
|
- | |
| 341 | int idxG2 = idxUltimoCompradorTrend; |
- | |
| 342 | log(String.format("RefC[%d], G1[%d] => G2 (comprador) em [%d]", idxRef, idxG1, idxG2)); |
- | |
| - | 339 | g2 = ultimoComprador;
|
|
| - | 340 | idxG2 = idxUltimoComprador;
|
|
| - | 341 | log(String.format("GR[%d], G1[%d] => G2 (comprador) em [%d]", idxGR, idxG1, idxG2)); |
|
| - | 342 | ||
| - | 343 | // 5) G3 – próximo direcional vendedor; vendedor que rompe fundo de G2 com topo <= topo GR
|
|
| - | 344 | Candle g3 = null; |
|
| - | 345 | int idxG3 = -1; |
|
| 343 | 346 | ||
| 344 | // 3) Encontrar G3 (vendedor rompendo fundo de G2, topo <= topo do GR)
|
- | |
| 345 | int idxPrimeiroVendedorAposG2 = -1; |
347 | int idxPrimeiroVendedorAposG2 = -1; |
| 346 | for (int i = idxG2 + 1; i < n; i++) { |
348 | for (int i = idxG2 + 1; i < n; i++) { |
| 347 | Candle c = candles.get(i); |
349 | Candle c = candles.get(i); |
| 348 | - | ||
| 349 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 350 | if (isOutsideReferencia(ref, c)) { |
- | |
| 351 | lastIndex = i;
|
- | |
| 352 | log(String.format( |
- | |
| 353 | "RefC[%d]: OUTSIDE em [%d] antes da sequência vendedora de G3. Padrão descartado.",
|
- | |
| 354 | idxRef, i)); |
- | |
| 355 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 356 | }
|
- | |
| 357 | - | ||
| 358 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| - | 350 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| 359 | continue; |
351 | continue; |
| 360 | }
|
- | |
| 361 | 352 | ||
| 362 | if (c.isCandleVendedor()) { |
353 | if (c.isCandleVendedor()) { |
| 363 | idxPrimeiroVendedorAposG2 = i;
|
354 | idxPrimeiroVendedorAposG2 = i;
|
| 364 | break; |
355 | break; |
| 365 | } else { |
356 | } else { |
| - | 357 | // primeiro direcional não é vendedor => padrão só até G2
|
|
| 366 | lastIndex = i;
|
358 | lastIndex = i;
|
| 367 | // pela sua regra, o próximo após G2 deveria ser vendedor
|
- | |
| 368 | // => padrão chegou até G2, mas não evoluiu corretamente para G3
|
- | |
| 369 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| - | 359 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 370 | }
|
360 | }
|
| 371 | }
|
361 | }
|
| 372 | - | ||
| 373 | if (idxPrimeiroVendedorAposG2 == -1) { |
- | |
| 374 | // padrão com GR, G1, G2, mas sem sequência adequada para G3
|
- | |
| 375 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| 376 | }
|
- | |
| 377 | - | ||
| 378 | int idxG3 = -1; |
- | |
| 379 | Candle g3 = null; |
- | |
| - | 362 | if (idxPrimeiroVendedorAposG2 == -1) |
|
| - | 363 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 380 | 364 | ||
| 381 | for (int i = idxPrimeiroVendedorAposG2; i < n; i++) { |
365 | for (int i = idxPrimeiroVendedorAposG2; i < n; i++) { |
| 382 | Candle c = candles.get(i); |
366 | Candle c = candles.get(i); |
| 383 | 367 | ||
| 384 | // OUTSIDE em relação ao GR (ATÉ IDENTIFICAR G3)
|
- | |
| 385 | if (isOutsideReferencia(ref, c)) { |
- | |
| - | 368 | // outside antes de G3 descarta
|
|
| - | 369 | if (isOutside(candles, i)) { |
|
| 386 | lastIndex = i;
|
370 | lastIndex = i;
|
| 387 | log(String.format( |
- | |
| 388 | "RefC[%d]: OUTSIDE em [%d] durante formação de G3. Padrão descartado.",
|
- | |
| 389 | idxRef, i)); |
- | |
| - | 371 | log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (vendedor).", idxGR, i)); |
|
| - | 372 | return new ResultadoPadrao(null, lastIndex); |
|
| - | 373 | }
|
|
| - | 374 | ||
| - | 375 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 376 | continue; |
|
| - | 377 | ||
| - | 378 | // se romper topo do GR antes de G3 => descarta
|
|
| - | 379 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) { |
|
| - | 380 | lastIndex = i;
|
|
| - | 381 | log(String.format("GR[%d]: candle [%d] rompeu topo do GR antes de G3.", idxGR, i)); |
|
| 390 | return new ResultadoPadrao(null, lastIndex); |
382 | return new ResultadoPadrao(null, lastIndex); |
| 391 | }
|
383 | }
|
| 392 | 384 | ||
| 393 | if (!c.isCandleVendedor()) { |
385 | if (!c.isCandleVendedor()) { |
| 394 | lastIndex = i - 1; |
386 | lastIndex = i - 1; |
| 395 | break; |
387 | break; |
| 396 | }
|
388 | }
|
| 397 | 389 | ||
| 398 | lastIndex = i;
|
390 | lastIndex = i;
|
| 399 | - | ||
| 400 | boolean rompeFundoG2 = BigDecimalUtils.ehMenorQue(c.getMinima(), g2.getMinima()); |
391 | boolean rompeFundoG2 = BigDecimalUtils.ehMenorQue(c.getMinima(), g2.getMinima()); |
| 401 | boolean topoMenorOuIgualRef = BigDecimalUtils.ehMenorOuIgualQue(c.getMaxima(), ref.getMaxima()); |
- | |
| 402 | - | ||
| 403 | if (rompeFundoG2 && topoMenorOuIgualRef) { |
- | |
| - | 392 | boolean topoMenorOuIgualGR = BigDecimalUtils.ehMenorOuIgualQue(c.getMaxima(), gr.getMaxima()); |
|
| - | 393 | if (rompeFundoG2 && topoMenorOuIgualGR) { |
|
| - | 394 | g3 = c;
|
|
| 404 | idxG3 = i;
|
395 | idxG3 = i;
|
| 405 | g3 = c;
|
- | |
| 406 | break; |
396 | break; |
| 407 | }
|
397 | }
|
| 408 | }
|
398 | }
|
| 409 | 399 | ||
| 410 | if (idxG3 == -1 || g3 == null) { |
- | |
| 411 | // Chegou até G2 mas não encontrou G3
|
- | |
| 412 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| 413 | }
|
- | |
| - | 400 | if (g3 == null) |
|
| - | 401 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 414 | 402 | ||
| 415 | log(String.format("RefC[%d], G1[%d], G2[%d] => G3 (vendedor) em [%d]", |
- | |
| 416 | idxRef, idxG1, idxG2, idxG3)); |
- | |
| - | 403 | log(String.format("GR[%d], G1[%d], G2[%d] => G3 (vendedor) em [%d]", |
|
| - | 404 | idxGR, idxG1, idxG2, idxG3)); |
|
| 417 | 405 | ||
| 418 | // 4) G4 – próximo candle rompe topo do GR (aqui já não precisamos mais checar outside)
|
- | |
| - | 406 | // 6) G4 – próximo candle rompe topo do GR
|
|
| 419 | Candle g4 = null; |
407 | Candle g4 = null; |
| 420 | int proxIdx = idxG3 + 1; |
408 | int proxIdx = idxG3 + 1; |
| 421 | if (proxIdx < n) { |
409 | if (proxIdx < n) { |
| 422 | Candle c = candles.get(proxIdx); |
410 | Candle c = candles.get(proxIdx); |
| 423 | lastIndex = proxIdx;
|
411 | lastIndex = proxIdx;
|
| 424 | - | ||
| 425 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), ref.getMaxima())) { |
- | |
| - | 412 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) { |
|
| 426 | g4 = c;
|
413 | g4 = c;
|
| 427 | log(String.format("RefC[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]", |
- | |
| 428 | idxRef, idxG1, idxG2, idxG3, proxIdx)); |
- | |
| - | 414 | log(String.format("GR[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]", |
|
| - | 415 | idxGR, idxG1, idxG2, idxG3, proxIdx)); |
|
| 429 | } else { |
416 | } else { |
| 430 | log(String.format("RefC[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.", |
- | |
| 431 | idxRef, idxG1, idxG2, idxG3, proxIdx)); |
- | |
| - | 417 | log(String.format("GR[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.", |
|
| - | 418 | idxGR, idxG1, idxG2, idxG3, proxIdx)); |
|
| 432 | }
|
419 | }
|
| 433 | }
|
420 | }
|
| 434 | 421 | ||
| 435 | PadraoGatilho padrao = new PadraoGatilho(); |
422 | PadraoGatilho padrao = new PadraoGatilho(); |
| 436 | padrao.setReferencia(ref); |
- | |
| - | 423 | padrao.setReferencia(gr); |
|
| 437 | padrao.setGatilho1(g1); |
424 | padrao.setGatilho1(g1); |
| 438 | padrao.setGatilho2(g2); |
425 | padrao.setGatilho2(g2); |
| 439 | padrao.setGatilho3(g3); |
426 | padrao.setGatilho3(g3); |
| 440 | padrao.setGatilho4(g4); |
427 | padrao.setGatilho4(g4); |
| 441 | 428 | ||
| 442 | return new ResultadoPadrao(padrao, lastIndex); |
429 | return new ResultadoPadrao(padrao, lastIndex); |
| 443 | }
|
430 | }
|
| 444 | - | ||
| 445 | 431 | ||
| 446 | // =====================================================================
|
432 | // =====================================================================
|
| 447 | // CASO 2 – GR VENDEDOR (candle B)
|
- | |
| - | 433 | // CASO 2 – PADRÃO A PARTIR DE CANDLE VENDEDOR
|
|
| 448 | // =====================================================================
|
434 | // =====================================================================
|
| 449 | 435 | ||
| 450 | private ResultadoPadrao detectarPadraoVendedor(List<Candle> candles, int idxRef) { |
- | |
| - | 436 | private ResultadoPadrao detectarPadraoVendedor(List<Candle> candles, int idxA) { |
|
| 451 | int n = candles.size(); |
437 | int n = candles.size(); |
| 452 | Candle ref = candles.get(idxRef); // candidato a GR vendedor |
- | |
| 453 | int lastIndex = idxRef; |
- | |
| 454 | - | ||
| 455 | // 0) Validar se idxRef pode ser GR vendedor (B)
|
- | |
| 456 | if (!ref.isCandleVendedor()) { |
- | |
| 457 | return new ResultadoPadrao(null, idxRef); |
- | |
| - | 438 | int lastIndex = idxA; |
|
| - | 439 | Candle candleA = candles.get(idxA); |
|
| - | 440 | if (!candleA.isCandleVendedor()) { |
|
| - | 441 | return new ResultadoPadrao(null, idxA); |
|
| 458 | }
|
442 | }
|
| 459 | 443 | ||
| 460 | // 0.1 – início da pernada vendedora que termina em B
|
- | |
| 461 | int inicioTrendVenda = idxRef; |
- | |
| 462 | for (int i = idxRef - 1; i >= 0; i--) { |
- | |
| - | 444 | // 1) A deve ser último da tendência vendedora -> achar B comprador
|
|
| - | 445 | int idxB = -1; |
|
| - | 446 | for (int i = idxA + 1; i < n; i++) { |
|
| 463 | Candle c = candles.get(i); |
447 | Candle c = candles.get(i); |
| 464 | if (!c.isCandleVendedor()) { |
- | |
| 465 | break; |
- | |
| 466 | }
|
- | |
| 467 | inicioTrendVenda = i;
|
- | |
| 468 | }
|
- | |
| 469 | - | ||
| 470 | // 0.2 – primeiro candle direcional após B
|
- | |
| 471 | int idxPrimeiroDirecionalAposRef = -1; |
- | |
| 472 | for (int i = idxRef + 1; i < n; i++) { |
- | |
| 473 | Candle c = candles.get(i); |
- | |
| 474 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| - | 448 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| 475 | continue; |
449 | continue; |
| 476 | }
|
- | |
| 477 | 450 | ||
| 478 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 479 | if (isOutsideReferencia(ref, c)) { |
- | |
| 480 | lastIndex = i;
|
- | |
| 481 | log(String.format( |
- | |
| 482 | "RefV[%d]: OUTSIDE em [%d] antes da mudança de tendência. Padrão descartado.",
|
- | |
| 483 | idxRef, i)); |
- | |
| 484 | return new ResultadoPadrao(null, lastIndex); |
- | |
| - | 451 | if (c.isCandleVendedor()) { |
|
| - | 452 | return new ResultadoPadrao(null, idxA); |
|
| - | 453 | }
|
|
| - | 454 | if (c.isCandleComprador()) { |
|
| - | 455 | idxB = i;
|
|
| - | 456 | break; |
|
| 485 | }
|
457 | }
|
| 486 | - | ||
| 487 | idxPrimeiroDirecionalAposRef = i;
|
- | |
| 488 | break; |
- | |
| 489 | }
|
458 | }
|
| - | 459 | if (idxB == -1) return new ResultadoPadrao(null, idxA); |
|
| 490 | 460 | ||
| 491 | if (idxPrimeiroDirecionalAposRef == -1) { |
- | |
| 492 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 493 | }
|
- | |
| - | 461 | Candle candleB = candles.get(idxB); |
|
| 494 | 462 | ||
| 495 | Candle primeiroDirecional = candles.get(idxPrimeiroDirecionalAposRef); |
- | |
| 496 | if (!primeiroDirecional.isCandleComprador()) { |
- | |
| 497 | // primeiro direcional após B ainda é vendedor
|
- | |
| 498 | return new ResultadoPadrao(null, idxRef); |
- | |
| - | 463 | // 2) Candidato à referência: A ou B (conforme fundo)
|
|
| - | 464 | Candle candidatoRef = candleA;
|
|
| - | 465 | int idxCandidatoRef = idxA; |
|
| - | 466 | if (BigDecimalUtils.ehMenorQue(candleB.getMinima(), candleA.getMinima())) { |
|
| - | 467 | candidatoRef = candleB;
|
|
| - | 468 | idxCandidatoRef = idxB;
|
|
| 499 | }
|
469 | }
|
| 500 | 470 | ||
| 501 | // 0.3 – B tem o MENOR fundo da pernada vendedora
|
- | |
| 502 | BigDecimal fundoRef = ref.getMinima(); |
- | |
| 503 | for (int i = inicioTrendVenda; i <= idxRef; i++) { |
- | |
| 504 | Candle c = candles.get(i); |
- | |
| 505 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), fundoRef)) { |
- | |
| 506 | return new ResultadoPadrao(null, idxRef); |
- | |
| 507 | }
|
- | |
| 508 | }
|
- | |
| 509 | - | ||
| 510 | int idxPrimeiroComprador = idxPrimeiroDirecionalAposRef; |
- | |
| 511 | - | ||
| 512 | // 1) Encontrar G1 (comprador que rompe topo do GR)
|
- | |
| - | 471 | // 3) G1 – primeiro comprador que rompe topo do candidatoRef
|
|
| - | 472 | Candle g1 = null; |
|
| 513 | int idxG1 = -1; |
473 | int idxG1 = -1; |
| 514 | Candle g1 = null; |
- | |
| 515 | - | ||
| 516 | for (int i = idxPrimeiroComprador; i < n; i++) { |
- | |
| - | 474 | for (int i = idxCandidatoRef + 1; i < n; i++) { |
|
| 517 | Candle c = candles.get(i); |
475 | Candle c = candles.get(i); |
| 518 | - | ||
| 519 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 520 | if (isOutsideReferencia(ref, c)) { |
- | |
| 521 | lastIndex = i;
|
- | |
| 522 | log(String.format( |
- | |
| 523 | "RefV[%d]: OUTSIDE em [%d] durante busca de G1. Padrão descartado.",
|
- | |
| 524 | idxRef, i)); |
- | |
| 525 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 526 | }
|
- | |
| - | 476 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 477 | continue; |
|
| 527 | 478 | ||
| 528 | if (!c.isCandleComprador()) { |
479 | if (!c.isCandleComprador()) { |
| 529 | lastIndex = i - 1; |
480 | lastIndex = i - 1; |
| 530 | return new ResultadoPadrao(null, lastIndex); |
481 | return new ResultadoPadrao(null, lastIndex); |
| 531 | }
|
482 | }
|
| 532 | 483 | ||
| 533 | lastIndex = i;
|
484 | lastIndex = i;
|
| 534 | - | ||
| 535 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), ref.getMaxima())) { |
- | |
| - | 485 | if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), candidatoRef.getMaxima())) { |
|
| - | 486 | g1 = c;
|
|
| 536 | idxG1 = i;
|
487 | idxG1 = i;
|
| 537 | g1 = c;
|
- | |
| 538 | break; |
488 | break; |
| 539 | }
|
489 | }
|
| 540 | }
|
490 | }
|
| - | 491 | if (g1 == null) return new ResultadoPadrao(null, lastIndex); |
|
| 541 | 492 | ||
| 542 | if (idxG1 == -1) { |
- | |
| 543 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 544 | }
|
- | |
| - | 493 | Candle gr = candidatoRef;
|
|
| - | 494 | int idxGR = idxCandidatoRef; |
|
| - | 495 | log(String.format("GR vendedor em [%d], G1 (comprador) em [%d]", idxGR, idxG1)); |
|
| 545 | 496 | ||
| 546 | log(String.format("RefV[%d] (GR) => G1 (comprador) em [%d]", idxRef, idxG1)); |
- | |
| - | 497 | // 4) G2 – nova tendência vendedora com fechamento dentro da região do GR
|
|
| - | 498 | Candle g2 = null; |
|
| - | 499 | int idxG2 = -1; |
|
| 547 | 500 | ||
| 548 | // 2) Encontrar G2 (retorno vendedor à região do GR)
|
- | |
| 549 | int idxPrimeiroVendedor = -1; |
501 | int idxPrimeiroVendedor = -1; |
| 550 | for (int i = idxG1 + 1; i < n; i++) { |
502 | for (int i = idxG1 + 1; i < n; i++) { |
| 551 | Candle c = candles.get(i); |
503 | Candle c = candles.get(i); |
| 552 | - | ||
| 553 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 554 | if (isOutsideReferencia(ref, c)) { |
- | |
| 555 | lastIndex = i;
|
- | |
| 556 | log(String.format( |
- | |
| 557 | "RefV[%d]: OUTSIDE em [%d] antes da tendência de G2. Padrão descartado.",
|
- | |
| 558 | idxRef, i)); |
- | |
| 559 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 560 | }
|
- | |
| 561 | - | ||
| 562 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| - | 504 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| 563 | continue; |
505 | continue; |
| 564 | }
|
- | |
| 565 | 506 | ||
| 566 | if (c.isCandleVendedor()) { |
507 | if (c.isCandleVendedor()) { |
| 567 | idxPrimeiroVendedor = i;
|
508 | idxPrimeiroVendedor = i;
|
| 568 | break; |
509 | break; |
| 569 | } else { |
510 | } else { |
| 570 | lastIndex = i;
|
511 | lastIndex = i;
|
| 571 | }
|
512 | }
|
| 572 | }
|
513 | }
|
| - | 514 | if (idxPrimeiroVendedor == -1) return new ResultadoPadrao(null, lastIndex); |
|
| 573 | 515 | ||
| 574 | if (idxPrimeiroVendedor == -1) { |
- | |
| 575 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 576 | }
|
- | |
| 577 | - | ||
| 578 | boolean rompeuFundoRef = false; |
- | |
| 579 | Candle ultimoVendedorTrend = null; |
- | |
| 580 | int idxUltimoVendedorTrend = -1; |
- | |
| - | 516 | Candle ultimoVendedor = null; |
|
| - | 517 | int idxUltimoVendedor = -1; |
|
| - | 518 | boolean rompeuFundoGR = false; |
|
| 581 | 519 | ||
| 582 | for (int i = idxPrimeiroVendedor; i < n; i++) { |
520 | for (int i = idxPrimeiroVendedor; i < n; i++) { |
| 583 | Candle c = candles.get(i); |
521 | Candle c = candles.get(i); |
| 584 | 522 | ||
| 585 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 586 | if (isOutsideReferencia(ref, c)) { |
- | |
| - | 523 | if (isOutside(candles, i)) { |
|
| 587 | lastIndex = i;
|
524 | lastIndex = i;
|
| 588 | log(String.format( |
- | |
| 589 | "RefV[%d]: OUTSIDE em [%d] durante formação de G2. Padrão descartado.",
|
- | |
| 590 | idxRef, i)); |
- | |
| - | 525 | log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (vendedor).", idxGR, i)); |
|
| 591 | return new ResultadoPadrao(null, lastIndex); |
526 | return new ResultadoPadrao(null, lastIndex); |
| 592 | }
|
527 | }
|
| 593 | 528 | ||
| 594 | if (!c.isCandleVendedor()) { |
- | |
| 595 | break; |
- | |
| 596 | }
|
- | |
| - | 529 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 530 | continue; |
|
| 597 | 531 | ||
| 598 | ultimoVendedorTrend = c;
|
- | |
| 599 | idxUltimoVendedorTrend = i;
|
- | |
| 600 | lastIndex = i;
|
- | |
| 601 | - | ||
| 602 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), ref.getMinima())) { |
- | |
| 603 | rompeuFundoRef = true; |
- | |
| - | 532 | if (c.isCandleVendedor()) { |
|
| - | 533 | // se romper fundo do GR, descarta
|
|
| - | 534 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) { |
|
| - | 535 | rompeuFundoGR = true; |
|
| - | 536 | lastIndex = i;
|
|
| - | 537 | break; |
|
| - | 538 | }
|
|
| - | 539 | ultimoVendedor = c;
|
|
| - | 540 | idxUltimoVendedor = i;
|
|
| - | 541 | lastIndex = i;
|
|
| - | 542 | } else if (c.isCandleComprador()) { |
|
| - | 543 | lastIndex = i - 1; |
|
| 604 | break; |
544 | break; |
| 605 | }
|
545 | }
|
| 606 | }
|
546 | }
|
| 607 | 547 | ||
| 608 | if (rompeuFundoRef || idxUltimoVendedorTrend == -1) { |
- | |
| - | 548 | if (rompeuFundoGR || ultimoVendedor == null) |
|
| 609 | return new ResultadoPadrao(null, lastIndex); |
549 | return new ResultadoPadrao(null, lastIndex); |
| 610 | }
|
- | |
| 611 | 550 | ||
| 612 | boolean fechamentoDentroRegiaoRef =
|
- | |
| 613 | BigDecimalUtils.ehMaiorOuIgualQue(ultimoVendedorTrend.getFechamento(), ref.getMinima()) && |
- | |
| 614 | BigDecimalUtils.ehMenorOuIgualQue(ultimoVendedorTrend.getFechamento(), ref.getMaxima()); |
- | |
| - | 551 | boolean fechamentoDentroRegiaoGR =
|
|
| - | 552 | BigDecimalUtils.ehMaiorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMinima()) && |
|
| - | 553 | BigDecimalUtils.ehMenorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMaxima()); |
|
| 615 | 554 | ||
| 616 | if (!fechamentoDentroRegiaoRef) { |
- | |
| - | 555 | if (!fechamentoDentroRegiaoGR) |
|
| 617 | return new ResultadoPadrao(null, lastIndex); |
556 | return new ResultadoPadrao(null, lastIndex); |
| 618 | }
|
- | |
| 619 | 557 | ||
| 620 | Candle g2 = ultimoVendedorTrend;
|
- | |
| 621 | int idxG2 = idxUltimoVendedorTrend; |
- | |
| 622 | log(String.format("RefV[%d], G1[%d] => G2 (vendedor) em [%d]", idxRef, idxG1, idxG2)); |
- | |
| - | 558 | g2 = ultimoVendedor;
|
|
| - | 559 | idxG2 = idxUltimoVendedor;
|
|
| - | 560 | log(String.format("GR[%d], G1[%d] => G2 (vendedor) em [%d]", idxGR, idxG1, idxG2)); |
|
| - | 561 | ||
| - | 562 | // 5) G3 – próximo direcional comprador; comprador que rompe topo de G2 com fundo >= fundo GR
|
|
| - | 563 | Candle g3 = null; |
|
| - | 564 | int idxG3 = -1; |
|
| 623 | 565 | ||
| 624 | // 3) Encontrar G3 (comprador rompendo topo de G2, fundo >= fundo do GR)
|
- | |
| 625 | int idxPrimeiroCompradorAposG2 = -1; |
566 | int idxPrimeiroCompradorAposG2 = -1; |
| 626 | for (int i = idxG2 + 1; i < n; i++) { |
567 | for (int i = idxG2 + 1; i < n; i++) { |
| 627 | Candle c = candles.get(i); |
568 | Candle c = candles.get(i); |
| 628 | - | ||
| 629 | // OUTSIDE em relação ao GR (até G3)
|
- | |
| 630 | if (isOutsideReferencia(ref, c)) { |
- | |
| 631 | lastIndex = i;
|
- | |
| 632 | log(String.format( |
- | |
| 633 | "RefV[%d]: OUTSIDE em [%d] antes da sequência compradora de G3. Padrão descartado.",
|
- | |
| 634 | idxRef, i)); |
- | |
| 635 | return new ResultadoPadrao(null, lastIndex); |
- | |
| 636 | }
|
- | |
| 637 | - | ||
| 638 | if (!c.isCandleComprador() && !c.isCandleVendedor()) { |
- | |
| - | 569 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| 639 | continue; |
570 | continue; |
| 640 | }
|
- | |
| 641 | 571 | ||
| 642 | if (c.isCandleComprador()) { |
572 | if (c.isCandleComprador()) { |
| 643 | idxPrimeiroCompradorAposG2 = i;
|
573 | idxPrimeiroCompradorAposG2 = i;
|
| 644 | break; |
574 | break; |
| 645 | } else { |
575 | } else { |
| 646 | lastIndex = i;
|
576 | lastIndex = i;
|
| 647 | // esperado comprador; padrão segue apenas até G2
|
- | |
| 648 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| - | 577 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 649 | }
|
578 | }
|
| 650 | }
|
579 | }
|
| 651 | - | ||
| 652 | if (idxPrimeiroCompradorAposG2 == -1) { |
- | |
| 653 | // não teve sequência adequada após G2
|
- | |
| 654 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| 655 | }
|
- | |
| 656 | - | ||
| 657 | int idxG3 = -1; |
- | |
| 658 | Candle g3 = null; |
- | |
| - | 580 | if (idxPrimeiroCompradorAposG2 == -1) |
|
| - | 581 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 659 | 582 | ||
| 660 | for (int i = idxPrimeiroCompradorAposG2; i < n; i++) { |
583 | for (int i = idxPrimeiroCompradorAposG2; i < n; i++) { |
| 661 | Candle c = candles.get(i); |
584 | Candle c = candles.get(i); |
| 662 | 585 | ||
| 663 | // OUTSIDE em relação ao GR (ATÉ IDENTIFICAR G3)
|
- | |
| 664 | if (isOutsideReferencia(ref, c)) { |
- | |
| - | 586 | if (isOutside(candles, i)) { |
|
| 665 | lastIndex = i;
|
587 | lastIndex = i;
|
| 666 | log(String.format( |
- | |
| 667 | "RefV[%d]: OUTSIDE em [%d] durante formação de G3. Padrão descartado.",
|
- | |
| 668 | idxRef, i)); |
- | |
| - | 588 | log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (comprador).", idxGR, i)); |
|
| - | 589 | return new ResultadoPadrao(null, lastIndex); |
|
| - | 590 | }
|
|
| - | 591 | ||
| - | 592 | if (isInside(candles, i) || (!c.isCandleComprador() && !c.isCandleVendedor())) |
|
| - | 593 | continue; |
|
| - | 594 | ||
| - | 595 | // se romper fundo do GR antes de G3 => descarta
|
|
| - | 596 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) { |
|
| - | 597 | lastIndex = i;
|
|
| - | 598 | log(String.format("GR[%d]: candle [%d] rompeu fundo do GR antes de G3.", idxGR, i)); |
|
| 669 | return new ResultadoPadrao(null, lastIndex); |
599 | return new ResultadoPadrao(null, lastIndex); |
| 670 | }
|
600 | }
|
| 671 | 601 | ||
| 672 | if (!c.isCandleComprador()) { |
602 | if (!c.isCandleComprador()) { |
| 673 | lastIndex = i - 1; |
603 | lastIndex = i - 1; |
| 674 | break; |
604 | break; |
| 675 | }
|
605 | }
|
| 676 | 606 | ||
| 677 | lastIndex = i;
|
607 | lastIndex = i;
|
| 678 | - | ||
| 679 | boolean rompeTopoG2 = BigDecimalUtils.ehMaiorQue(c.getMaxima(), g2.getMaxima()); |
608 | boolean rompeTopoG2 = BigDecimalUtils.ehMaiorQue(c.getMaxima(), g2.getMaxima()); |
| 680 | boolean fundoMaiorOuIgualRef = BigDecimalUtils.ehMaiorOuIgualQue(c.getMinima(), ref.getMinima()); |
- | |
| 681 | - | ||
| 682 | if (rompeTopoG2 && fundoMaiorOuIgualRef) { |
- | |
| - | 609 | boolean fundoMaiorOuIgualGR = BigDecimalUtils.ehMaiorOuIgualQue(c.getMinima(), gr.getMinima()); |
|
| - | 610 | if (rompeTopoG2 && fundoMaiorOuIgualGR) { |
|
| - | 611 | g3 = c;
|
|
| 683 | idxG3 = i;
|
612 | idxG3 = i;
|
| 684 | g3 = c;
|
- | |
| 685 | break; |
613 | break; |
| 686 | }
|
614 | }
|
| 687 | }
|
615 | }
|
| 688 | 616 | ||
| 689 | if (idxG3 == -1 || g3 == null) { |
- | |
| 690 | // padrão só até G2
|
- | |
| 691 | return criarResultadoParcialComG2(ref, g1, g2, lastIndex); |
- | |
| 692 | }
|
- | |
| - | 617 | if (g3 == null) |
|
| - | 618 | return criarResultadoParcialComG2(gr, g1, g2, lastIndex); |
|
| 693 | 619 | ||
| 694 | log(String.format("RefV[%d], G1[%d], G2[%d] => G3 (comprador) em [%d]", |
- | |
| 695 | idxRef, idxG1, idxG2, idxG3)); |
- | |
| - | 620 | log(String.format("GR[%d], G1[%d], G2[%d] => G3 (comprador) em [%d]", |
|
| - | 621 | idxGR, idxG1, idxG2, idxG3)); |
|
| 696 | 622 | ||
| 697 | // 4) G4 – próximo candle rompe fundo do GR
|
- | |
| - | 623 | // 6) G4 – próximo candle rompe fundo do GR
|
|
| 698 | Candle g4 = null; |
624 | Candle g4 = null; |
| 699 | int proxIdx = idxG3 + 1; |
625 | int proxIdx = idxG3 + 1; |
| 700 | if (proxIdx < n) { |
626 | if (proxIdx < n) { |
| 701 | Candle c = candles.get(proxIdx); |
627 | Candle c = candles.get(proxIdx); |
| 702 | lastIndex = proxIdx;
|
628 | lastIndex = proxIdx;
|
| 703 | - | ||
| 704 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), ref.getMinima())) { |
- | |
| - | 629 | if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) { |
|
| 705 | g4 = c;
|
630 | g4 = c;
|
| 706 | log(String.format("RefV[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]", |
- | |
| 707 | idxRef, idxG1, idxG2, idxG3, proxIdx)); |
- | |
| - | 631 | log(String.format("GR[%d], G1[%d], G2[%d], G3[%d] => G4 em [%d]", |
|
| - | 632 | idxGR, idxG1, idxG2, idxG3, proxIdx)); |
|
| 708 | } else { |
633 | } else { |
| 709 | log(String.format("RefV[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.", |
- | |
| 710 | idxRef, idxG1, idxG2, idxG3, proxIdx)); |
- | |
| - | 634 | log(String.format("GR[%d], G1[%d], G2[%d], G3[%d]: próximo candle [%d] não é G4.", |
|
| - | 635 | idxGR, idxG1, idxG2, idxG3, proxIdx)); |
|
| 711 | }
|
636 | }
|
| 712 | }
|
637 | }
|
| 713 | 638 | ||
| 714 | PadraoGatilho padrao = new PadraoGatilho(); |
639 | PadraoGatilho padrao = new PadraoGatilho(); |
| 715 | padrao.setReferencia(ref); |
- | |
| - | 640 | padrao.setReferencia(gr); |
|
| 716 | padrao.setGatilho1(g1); |
641 | padrao.setGatilho1(g1); |
| 717 | padrao.setGatilho2(g2); |
642 | padrao.setGatilho2(g2); |
| 718 | padrao.setGatilho3(g3); |
643 | padrao.setGatilho3(g3); |
| 719 | padrao.setGatilho4(g4); |
644 | padrao.setGatilho4(g4); |
| 720 | 645 | ||
| 721 | return new ResultadoPadrao(padrao, lastIndex); |
646 | return new ResultadoPadrao(padrao, lastIndex); |
| 722 | }
|
- | |
| 723 | - | ||
| 724 | - | ||
| 725 | // =====================================================================
|
- | |
| 726 | // HELPER – Candle outside em relação ao GR
|
- | |
| 727 | // =====================================================================
|
- | |
| 728 | - | ||
| 729 | /**
|
- | |
| 730 | * Outside em relação ao GR:
|
- | |
| 731 | * - atual.max > GR.max e atual.min < GR.min
|
- | |
| 732 | */
|
- | |
| 733 | private boolean isOutsideReferencia(Candle referencia, Candle atual) { |
- | |
| 734 | if (referencia == null || atual == null) return false; |
- | |
| 735 | return BigDecimalUtils.ehMaiorQue(atual.getMaxima(), referencia.getMaxima()) |
- | |
| 736 | && BigDecimalUtils.ehMenorQue(atual.getMinima(), referencia.getMinima()); |
- | |
| 737 | }
|
647 | }
|
| 738 | 648 | ||
| 739 | // =====================================================================
|
649 | // =====================================================================
|
| 740 | // MODO TEMPO REAL (candle a candle)
|
- | |
| - | 650 | // MODO TEMPO REAL
|
|
| 741 | // =====================================================================
|
651 | // =====================================================================
|
| 742 | 652 | ||
| 743 | /**
|
- | |
| 744 | * Reinicia o estado do modo tempo real.
|
- | |
| 745 | */
|
- | |
| 746 | public void resetTempoReal() { |
653 | public void resetTempoReal() { |
| 747 | this.idxProximaAnaliseTempoReal = 0; |
654 | this.idxProximaAnaliseTempoReal = 0; |
| 748 | }
|
655 | }
|
| 749 | 656 | ||
| 750 | /**
|
- | |
| 751 | * Deve ser chamado SEMPRE que um novo candle for adicionado à lista.
|
- | |
| 752 | *
|
- | |
| 753 | * Exemplo:
|
- | |
| 754 | * candles.add(novoCandle);
|
- | |
| 755 | * PadraoGatilho padrao = detector.processarCandleTempoReal(candles);
|
- | |
| 756 | *
|
- | |
| 757 | * if (padrao != null) {
|
- | |
| 758 | * // padrão completo encontrado
|
- | |
| 759 | * }
|
- | |
| 760 | */
|
- | |
| 761 | public PadraoGatilho processarCandleTempoReal(List<Candle> candles) { |
657 | public PadraoGatilho processarCandleTempoReal(List<Candle> candles) { |
| 762 | int n = candles.size(); |
658 | int n = candles.size(); |
| 763 | if (n < 4) { |
- | |
| 764 | return null; |
- | |
| 765 | }
|
- | |
| - | 659 | if (n < 4) return null; |
|
| 766 | 660 | ||
| 767 | while (idxProximaAnaliseTempoReal < n - 3) { |
661 | while (idxProximaAnaliseTempoReal < n - 3) { |
| 768 | ResultadoPadrao resultado = detectarPadraoAPartir(candles, idxProximaAnaliseTempoReal); |
662 | ResultadoPadrao resultado = detectarPadraoAPartir(candles, idxProximaAnaliseTempoReal); |
| 769 | 663 | ||
| 770 | if (resultado == null) { |
664 | if (resultado == null) { |