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