Subversion Repositories Integrator Subversion

Rev

Rev 773 | Rev 775 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 773 Rev 774
Line 12... Line 12...
12
 *
12
 *
13
 * IMPORTANTE:
13
 * IMPORTANTE:
14
 *  - Este detector FINALIZA o padrão assim que identifica o G3.
14
 *  - Este detector FINALIZA o padrão assim que identifica o G3.
15
 *  - O G4 será identificado apenas na camada de sinais de trade, fora desta classe.
15
 *  - O G4 será identificado apenas na camada de sinais de trade, fora desta classe.
16
 *
16
 *
17
 * REGRAS IMPLEMENTADAS (com GR DINÂMICO invertido)
-
 
18
 * ================================================
-
 
-
 
17
 * REGRAS IMPLEMENTADAS (versão alinhada)
-
 
18
 * ======================================
19
 *
19
 *
20
 * COMPRADOR
-
 
21
 * ---------
-
 
22
 * Ponto de partida: um candle COMPRADOR é candidato à referência.
-
 
-
 
20
 * 1) PADRÃO COMPRADOR
-
 
21
 * --------------------
-
 
22
 * Ponto de partida:
-
 
23
 *   - Um candle COMPRADOR é tomado como CANDIDATO À REFERÊNCIA.
23
 *
24
 *
24
 * G1:
-
 
25
 *   - Enquanto não houver G1:
-
 
26
 *       * O candidato à referência pode ser atualizado dinamicamente:
-
 
27
 *         QUALQUER candle posterior, antes do G1, que fizer uma MÁXIMA
-
 
28
 *         MAIOR que o candidato atual passa a ser o novo candidato.
-
 
29
 *       * Se algum candle VENDEDOR subsequente ROMPER o FUNDO
-
 
30
 *         do candle candidato à referência (mínima < mínima do candidato),
-
 
31
 *         esse candle será o gatilho tipo 1 [G1] e o candidato vigente
-
 
32
 *         torna-se o candle referência [GR].
-
 
-
 
25
 * GR DINÂMICO (compra):
-
 
26
 *   - Enquanto NÃO houver G1:
-
 
27
 *       * Qualquer candle DIRECIONAL posterior (comprador ou vendedor)
-
 
28
 *         que fizer uma MÁXIMA MAIOR que a do candidato atual
-
 
29
 *         passa a ser o NOVO candidato à referência.
33
 *
30
 *
34
 * G2:
-
 
35
 *   - Após o G1 (com GR definido):
-
 
36
 *       * Assim que tiver nova tendência COMPRADORA:
-
 
37
 *           - O último candle dessa sequência compradora deve ter o FECHAMENTO
-
 
38
 *             dentro da região total (mínima..máxima) do GR.
-
 
39
 *           - Se mudar para vendedor sem nenhum candle fechar dentro da região
-
 
40
 *             do GR → descarta o padrão.
-
 
41
 *       * Se qualquer candle (após o GR) romper o TOPO do GR
-
 
42
 *         (máxima > máxima GR) → descarta o padrão.
-
 
43
 *       * Se válido, esse último comprador é o gatilho tipo 2 [G2].
-
 
-
 
31
 * G1 (compra):
-
 
32
 *   - Pode ser QUALQUER candle vendedor subsequente (não precisa ser o primeiro),
-
 
33
 *     desde que ROMPA o FUNDO do candidato:
-
 
34
 *        mínima(candle vendedor) < mínima(candidatoRef).
-
 
35
 *   - No momento em que isso ocorrer:
-
 
36
 *        * Esse candle vendedor é o G1.
-
 
37
 *        * O candidato vigente passa a ser o GR (gatilho referência).
44
 *
38
 *
45
 * G3:
-
 
-
 
39
 * G2 (compra):
-
 
40
 *   - Após o G1, com GR definido:
-
 
41
 *       * Procurar uma nova tendência COMPRADORA:
-
 
42
 *           - Achar o primeiro candle COMPRADOR após o G1.
-
 
43
 *           - Seguir a sequência compradora (ignorando INSIDE e neutros)
-
 
44
 *             até aparecer candle vendedor.
-
 
45
 *       * O ÚLTIMO candle dessa tendência compradora será candidato a G2.
-
 
46
 *       * Para ser G2:
-
 
47
 *           - O FECHAMENTO deve ficar DENTRO da região [mínGR, máxGR].
-
 
48
 *       * Se mudar para vendedor sem nenhum candle fechar dentro da região do GR:
-
 
49
 *           - descarta o padrão.
-
 
50
 *   - Regra global comprador:
-
 
51
 *       * Se qualquer candle, após o GR, ROMPER o TOPO do GR
-
 
52
 *         (máxima > máximaGR) em qualquer ponto antes da conclusão:
-
 
53
 *           - descarta o padrão.
-
 
54
 *
-
 
55
 * G3 (compra) – NOVA REGRA:
46
 *   - Após o G2:
56
 *   - Após o G2:
47
 *       * O próximo direcional deve ser VENDEDOR; se for comprador,
-
 
48
 *         o padrão vai apenas até G2 (parcial).
-
 
49
 *       * Numa sequência vendedora:
-
 
50
 *           - Se algum candle VENDEDOR posterior ROMPER o FUNDO do G2
-
 
51
 *             (mínima < mínima G2) e tiver TOPO <= topo do GR
-
 
52
 *             (máxima <= máxima GR), sem mudança de tendência
-
 
53
 *             (sem compradores no meio), será o gatilho tipo 3 [G3].
-
 
-
 
57
 *       * Se ALGUM candle vendedor subsequente:
-
 
58
 *           - romper o FUNDO do G2 (mínima < mínimaG2) E
-
 
59
 *           - tiver TOPO menor ou igual ao TOPO do GR (máxima ≤ máximaGR)
-
 
60
 *         então esse candle será o G3.
-
 
61
 *   - Não precisa ser o primeiro vendedor após o G2; pode haver mudança de tendência,
-
 
62
 *     candles inside, etc., desde que a regra acima seja satisfeita e não ocorra:
-
 
63
 *       * outside antes do G3, ou
-
 
64
 *       * rompimento do topo do GR (regra global).
-
 
65
 *   - Ao identificar G3, o padrão é finalizado.
54
 *
66
 *
55
 * Regra global comprador:
-
 
56
 *   - Se algum candle posterior ao GR ROMPER o TOPO do GR
-
 
57
 *     (máxima > máxima GR), desconsiderar o padrão.
-
 
-
 
67
 * 2) PADRÃO VENDEDOR
-
 
68
 * -------------------
-
 
69
 * Ponto de partida:
-
 
70
 *   - Um candle VENDEDOR é tomado como CANDIDATO À REFERÊNCIA.
58
 *
71
 *
59
 * -----------------------------------------------------------
-
 
-
 
72
 * GR DINÂMICO (venda):
-
 
73
 *   - Enquanto NÃO houver G1:
-
 
74
 *       * Qualquer candle DIRECIONAL posterior (comprador ou vendedor)
-
 
75
 *         que fizer uma MÍNIMA MENOR que a do candidato atual
-
 
76
 *         passa a ser o NOVO candidato à referência.
60
 *
77
 *
61
 * VENDEDOR
-
 
62
 * --------
-
 
63
 * Ponto de partida: um candle VENDEDOR é candidato à referência.
-
 
64
 *
-
 
65
 * G1:
-
 
66
 *   - Enquanto não houver G1:
-
 
67
 *       * O candidato à referência pode ser atualizado dinamicamente:
-
 
68
 *         QUALQUER candle posterior, antes do G1, que fizer uma MÍNIMA
-
 
69
 *         MENOR que a do candidato atual passa a ser o novo candidato.
-
 
70
 *       * Se algum candle COMPRADOR subsequente ROMPER o TOPO
-
 
71
 *         do candidato (máxima > máxima do candidato), esse candle
-
 
72
 *         será o gatilho tipo 1 [G1] e o candidato vigente torna-se o GR.
-
 
-
 
78
 * G1 (venda):
-
 
79
 *   - Pode ser QUALQUER candle comprador subsequente (não precisa ser o primeiro),
-
 
80
 *     desde que ROMPA o TOPO do candidato:
-
 
81
 *        máxima(candle comprador) > máxima(candidatoRef).
-
 
82
 *   - No momento em que isso ocorrer:
-
 
83
 *        * Esse candle comprador é o G1.
-
 
84
 *        * O candidato vigente passa a ser o GR (gatilho referência).
73
 *
85
 *
74
 * Regra global vendedor:
86
 * Regra global vendedor:
75
 *   - Se algum candle posterior ao GR ROMPER o FUNDO do GR
-
 
76
 *     (mínima < mínima GR), desconsiderar o padrão.
-
 
-
 
87
 *   - Se qualquer candle posterior ao GR ROMPER o FUNDO do GR
-
 
88
 *     (mínima < mínimaGR) em qualquer momento antes da conclusão:
-
 
89
 *       - descarta o padrão.
77
 *
90
 *
78
 * G2:
-
 
79
 *   - Após o G1 (com GR definido):
-
 
80
 *       * Assim que tiver nova tendência VENDEDORA:
-
 
81
 *           - O último candle dessa sequência vendedora deve ter FECHAMENTO
-
 
82
 *             dentro da região total (mínima..máxima) do GR.
-
 
83
 *           - Se mudar para comprador sem nenhum candle fechar dentro
-
 
84
 *             da região do GR → descarta o padrão.
-
 
85
 *       * Se romper o FUNDO do GR em qualquer momento após o GR
-
 
86
 *         → descarta o padrão.
-
 
87
 *       * Se válido, esse último vendedor é o gatilho tipo 2 [G2].
-
 
-
 
91
 * G2 (venda):
-
 
92
 *   - Após o G1, com GR definido:
-
 
93
 *       * Procurar uma nova tendência VENDEDORA:
-
 
94
 *           - Achar o primeiro VENDEDOR após o G1.
-
 
95
 *           - Seguir a sequência vendedora (ignorando INSIDE e neutros)
-
 
96
 *             até aparecer candle comprador.
-
 
97
 *       * O ÚLTIMO candle dessa tendência vendedora será candidato a G2.
-
 
98
 *       * Para ser G2:
-
 
99
 *           - O FECHAMENTO deve ficar DENTRO da região [mínGR, máxGR].
-
 
100
 *       * Se mudar para comprador sem nenhum candle fechar dentro da região do GR:
-
 
101
 *           - descarta o padrão.
-
 
102
 *       * Se durante essa fase algum candle romper o FUNDO do GR
-
 
103
 *         (mínima < mínimaGR) → descarta o padrão (regra global).
88
 *
104
 *
89
 * G3:
-
 
-
 
105
 * G3 (venda) – NOVA REGRA:
90
 *   - Após o G2:
106
 *   - Após o G2:
91
 *       * O próximo direcional deve ser COMPRADOR; se for vendedor,
-
 
92
 *         o padrão vai até G2 (parcial).
-
 
93
 *       * Numa sequência compradora:
-
 
94
 *           - Se algum COMPRADOR posterior ROMPER o TOPO de G2
-
 
95
 *             (máxima > máxima G2) e tiver FUNDO >= fundo do GR
-
 
96
 *             (mínima >= mínima GR), sem mudança de tendência
-
 
97
 *             (sem vendedores no meio), será o gatilho tipo 3 [G3].
-
 
-
 
107
 *       * Se ALGUM candle comprador subsequente:
-
 
108
 *           - romper o TOPO do G2 (máxima > máximaG2) E
-
 
109
 *           - tiver FUNDO maior ou igual ao FUNDO do GR (mínima ≥ mínimaGR)
-
 
110
 *         então esse candle será o G3.
-
 
111
 *   - Não precisa ser o primeiro comprador após o G2; pode haver mudança de tendência,
-
 
112
 *     candles inside, etc., desde que a regra acima seja satisfeita e não ocorra:
-
 
113
 *       * outside antes do G3, ou
-
 
114
 *       * rompimento do fundo do GR (regra global).
-
 
115
 *   - Ao identificar G3, o padrão é finalizado.
98
 *
116
 *
99
 * Regra global adicional (texto original repetia):
-
 
100
 *   - Mantida a regra principal: vendedor é invalidado
-
 
101
 *     quando rompem o FUNDO do GR.
-
 
-
 
117
 * 3) OUTSIDE (ambos os lados)
-
 
118
 * ---------------------------
-
 
119
 *   - Candle cuja:
-
 
120
 *       máxima > máxima(candle anterior)
-
 
121
 *       E mínima < mínima(candle anterior).
-
 
122
 *   - Se houver OUTSIDE em qualquer estágio antes de G3:
-
 
123
 *       - o padrão atual (GR/G1/G2) é descartado.
102
 *
124
 *
103
 * -----------------------------------------------------------
-
 
104
 *
-
 
105
 * OUTSIDE (ambos os lados):
-
 
106
 *   - Candle cuja máxima > máxima do candle anterior
-
 
107
 *     E mínima < mínima do candle anterior.
-
 
108
 *   - Se houver um OUTSIDE antes de identificar o G3:
-
 
109
 *       * Desconsidera o padrão atual (GR+G1+G2) e recomeça
-
 
110
 *         a busca a partir do GR (na prática, aborta o padrão).
-
 
111
 *
-
 
112
 * OBS:
-
 
113
 *   - Os gatilhos devem seguir ORDEM cronológica:
-
 
114
 *     G1 -> G2 -> G3, sempre em candles diferentes.
-
 
-
 
125
 * 4) ORDEM CRONOLÓGICA
-
 
126
 * ---------------------
-
 
127
 *   - Sempre GR -> G1 -> G2 -> G3.
-
 
128
 *   - Todos em candles diferentes, na ordem do tempo.
115
 */
129
 */
116
public class DetectorGatilhos {
130
public class DetectorGatilhos {
117
131
118
    private final boolean logAtivo;
132
    private final boolean logAtivo;
119
    private int idxProximaAnaliseTempoReal = 0;
133
    private int idxProximaAnaliseTempoReal = 0;
Line 130... Line 144...
130
        if (logAtivo) {
144
        if (logAtivo) {
131
            System.out.println(msg);
145
            System.out.println(msg);
132
        }
146
        }
133
    }
147
    }
134
148
135
    // -----------------------------------------------------------------
-
 
-
 
149
    // -------------------------------------------------------------
136
    // Estrutura interna de retorno
150
    // Estrutura interna de retorno
137
    // -----------------------------------------------------------------
-
 
-
 
151
    // -------------------------------------------------------------
138
    private static class ResultadoPadrao {
152
    private static class ResultadoPadrao {
139
        PadraoGatilho padrao;
153
        PadraoGatilho padrao;
140
        int lastIndex;
154
        int lastIndex;
141
155
142
        ResultadoPadrao(PadraoGatilho padrao, int lastIndex) {
156
        ResultadoPadrao(PadraoGatilho padrao, int lastIndex) {
143
            this.padrao = padrao;
157
            this.padrao = padrao;
144
            this.lastIndex = lastIndex;
158
            this.lastIndex = lastIndex;
145
        }
159
        }
146
    }
160
    }
147
161
148
    private ResultadoPadrao criarResultadoParcialComG2(Candle ref,
-
 
-
 
162
    private ResultadoPadrao criarResultadoParcialComG2(Candle gr,
149
                                                       Candle g1,
163
                                                       Candle g1,
150
                                                       Candle g2,
164
                                                       Candle g2,
151
                                                       int lastIndex) {
165
                                                       int lastIndex) {
152
        PadraoGatilho padrao = new PadraoGatilho();
166
        PadraoGatilho padrao = new PadraoGatilho();
153
        padrao.setReferencia(ref);
-
 
-
 
167
        padrao.setReferencia(gr);
154
        padrao.setGatilho1(g1);
168
        padrao.setGatilho1(g1);
155
        padrao.setGatilho2(g2);
169
        padrao.setGatilho2(g2);
156
        padrao.setGatilho3(null);
170
        padrao.setGatilho3(null);
157
        padrao.setGatilho4(null); // G4 só na camada de trade
171
        padrao.setGatilho4(null); // G4 só na camada de trade
158
        return new ResultadoPadrao(padrao, lastIndex);
172
        return new ResultadoPadrao(padrao, lastIndex);
Line 235... Line 249...
235
        }
249
        }
236
250
237
        int idxCandidatoRef = idxInicio;
251
        int idxCandidatoRef = idxInicio;
238
252
239
        // --------------------
253
        // --------------------
240
        // 1) Buscar G1 (vendedor rompe fundo do candidato)
-
 
-
 
254
        // 1) Buscar G1: QUALQUER vendedor subsequente que rompa o fundo do candidatoRef
-
 
255
        //    (com GR dinâmico pela MÁXIMA antes de G1)
241
        // --------------------
256
        // --------------------
242
        Candle g1 = null;
257
        Candle g1 = null;
243
        int idxG1 = -1;
258
        int idxG1 = -1;
244
        boolean temGR = false;
-
 
245
        Candle gr = null;
259
        Candle gr = null;
246
        int idxGR = -1;
260
        int idxGR = -1;
247
261
248
        for (int i = idxInicio + 1; i < n; i++) {
262
        for (int i = idxInicio + 1; i < n; i++) {
249
            Candle c = candles.get(i);
263
            Candle c = candles.get(i);
250
            if (isInside(candles, i) || !isDirecional(c))
-
 
-
 
264
            if (isInside(candles, i) || !isDirecional(c)) {
251
                continue;
265
                continue;
-
 
266
            }
252
267
253
            // Outside antes de G3 (aqui ainda antes de G1)
-
 
-
 
268
            // OUTSIDE antes de G1 => descarta padrão
254
            if (isOutside(candles, i)) {
269
            if (isOutside(candles, i)) {
255
                lastIndex = i;
270
                lastIndex = i;
256
                log(String.format("Comprador: OUTSIDE em [%d] antes de G1. Abortando padrão.", i));
271
                log(String.format("Comprador: OUTSIDE em [%d] antes de G1. Abortando padrão.", i));
257
                return new ResultadoPadrao(null, lastIndex);
272
                return new ResultadoPadrao(null, lastIndex);
258
            }
273
            }
259
274
260
            // G1: vendedor rompe fundo do candidato
-
 
-
 
275
            // GR dinâmico (compra): atualiza candidatoRef pelo TOPO mais alto
-
 
276
            // enquanto não existir G1
-
 
277
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), candidatoRef.getMaxima())) {
-
 
278
                candidatoRef = c;
-
 
279
                idxCandidatoRef = i;
-
 
280
                lastIndex = i;
-
 
281
                continue;
-
 
282
            }
-
 
283
-
 
284
            // G1: QUALQUER vendedor subsequente que rompa o fundo do candidatoRef
261
            if (c.isCandleVendedor()
285
            if (c.isCandleVendedor()
262
                    && BigDecimalUtils.ehMenorQue(c.getMinima(), candidatoRef.getMinima())) {
286
                    && BigDecimalUtils.ehMenorQue(c.getMinima(), candidatoRef.getMinima())) {
263
                g1 = c;
287
                g1 = c;
264
                idxG1 = i;
288
                idxG1 = i;
265
                gr = candidatoRef;
289
                gr = candidatoRef;
266
                idxGR = idxCandidatoRef;
290
                idxGR = idxCandidatoRef;
267
                temGR = true;
-
 
268
                lastIndex = i;
291
                lastIndex = i;
269
                break;
292
                break;
270
            }
-
 
271
-
 
272
            // GR DINÂMICO (compra): atualiza pelo TOPO mais alto antes de G1
-
 
273
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), candidatoRef.getMaxima())) {
-
 
274
                candidatoRef = c;
-
 
275
                idxCandidatoRef = i;
-
 
276
                lastIndex = i;
-
 
277
                continue;
-
 
278
            }
293
            }
279
294
280
            lastIndex = i;
295
            lastIndex = i;
281
        }
296
        }
282
297
283
        if (g1 == null || !temGR) {
-
 
-
 
298
        if (g1 == null || gr == null) {
284
            log(String.format("Comprador: não foi possível formar G1 a partir de idx %d.", idxInicio));
299
            log(String.format("Comprador: não foi possível formar G1 a partir de idx %d.", idxInicio));
285
            return new ResultadoPadrao(null, lastIndex);
300
            return new ResultadoPadrao(null, lastIndex);
286
        }
301
        }
287
302
288
        log(String.format("GR COMPRADOR em [%d], G1 (vendedor) em [%d].", idxGR, idxG1));
303
        log(String.format("GR COMPRADOR em [%d], G1 (vendedor) em [%d].", idxGR, idxG1));
289
304
290
        // --------------------
305
        // --------------------
291
        // 2) Buscar G2 (tendência compradora com fechamento dentro do GR)
-
 
-
 
306
        // 2) Buscar G2 – tendência COMPRADORA com fechamento dentro do GR
292
        // --------------------
307
        // --------------------
293
        Candle g2 = null;
308
        Candle g2 = null;
294
        int idxG2 = -1;
309
        int idxG2 = -1;
295
310
296
        int idxPrimeiroComprador = -1;
311
        int idxPrimeiroComprador = -1;
297
        for (int i = idxG1 + 1; i < n; i++) {
312
        for (int i = idxG1 + 1; i < n; i++) {
298
            Candle c = candles.get(i);
313
            Candle c = candles.get(i);
299
            if (isInside(candles, i) || !isDirecional(c))
314
            if (isInside(candles, i) || !isDirecional(c))
300
                continue;
315
                continue;
301
316
302
            // Outside antes de G3
-
 
-
 
317
            // OUTSIDE antes de G2 => descarta padrão
303
            if (isOutside(candles, i)) {
318
            if (isOutside(candles, i)) {
304
                lastIndex = idxGR;
319
                lastIndex = idxGR;
305
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da perna compradora de G2.", idxGR, i));
-
 
-
 
320
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da tendência compradora de G2.", idxGR, i));
306
                return new ResultadoPadrao(null, lastIndex);
321
                return new ResultadoPadrao(null, lastIndex);
307
            }
322
            }
308
323
309
            // Regra global: romper topo do GR invalida
-
 
-
 
324
            // Regra global comprador: se romper topo do GR => descarta
310
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
325
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
311
                lastIndex = i;
326
                lastIndex = i;
312
                log(String.format("GR[%d]: candle[%d] rompeu topo do GR antes de G2.", idxGR, i));
-
 
-
 
327
                log(String.format("GR[%d]: candle[%d] rompeu TOPO do GR antes/na formação de G2.", idxGR, i));
313
                return new ResultadoPadrao(null, lastIndex);
328
                return new ResultadoPadrao(null, lastIndex);
314
            }
329
            }
315
330
316
            if (c.isCandleComprador()) {
331
            if (c.isCandleComprador()) {
317
                idxPrimeiroComprador = i;
332
                idxPrimeiroComprador = i;
Line 332... Line 347...
332
        for (int i = idxPrimeiroComprador; i < n; i++) {
347
        for (int i = idxPrimeiroComprador; i < n; i++) {
333
            Candle c = candles.get(i);
348
            Candle c = candles.get(i);
334
            if (isInside(candles, i) || !isDirecional(c))
349
            if (isInside(candles, i) || !isDirecional(c))
335
                continue;
350
                continue;
336
351
337
            // Outside durante G2
-
 
-
 
352
            // OUTSIDE durante G2 => descarta padrão
338
            if (isOutside(candles, i)) {
353
            if (isOutside(candles, i)) {
339
                lastIndex = idxGR;
354
                lastIndex = idxGR;
340
                log(String.format("GR[%d]: OUTSIDE em [%d] durante G2 (comprador).", idxGR, i));
-
 
-
 
355
                log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (comprador).", idxGR, i));
341
                return new ResultadoPadrao(null, lastIndex);
356
                return new ResultadoPadrao(null, lastIndex);
342
            }
357
            }
343
358
344
            // Regra global: romper topo do GR invalida
-
 
-
 
359
            // Regra global comprador: se romper topo do GR => descarta
345
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
360
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
346
                lastIndex = i;
361
                lastIndex = i;
347
                log(String.format("GR[%d]: candle[%d] rompeu topo do GR durante G2.", idxGR, i));
-
 
-
 
362
                log(String.format("GR[%d]: candle[%d] rompeu TOPO do GR durante G2.", idxGR, i));
348
                return new ResultadoPadrao(null, lastIndex);
363
                return new ResultadoPadrao(null, lastIndex);
349
            }
364
            }
350
365
351
            if (c.isCandleComprador()) {
366
            if (c.isCandleComprador()) {
352
                ultimoComprador = c;
367
                ultimoComprador = c;
Line 367... Line 382...
367
                BigDecimalUtils.ehMaiorOuIgualQue(ultimoComprador.getFechamento(), gr.getMinima()) &&
382
                BigDecimalUtils.ehMaiorOuIgualQue(ultimoComprador.getFechamento(), gr.getMinima()) &&
368
                BigDecimalUtils.ehMenorOuIgualQue(ultimoComprador.getFechamento(), gr.getMaxima());
383
                BigDecimalUtils.ehMenorOuIgualQue(ultimoComprador.getFechamento(), gr.getMaxima());
369
384
370
        if (!fechamentoDentroRegiaoGR) {
385
        if (!fechamentoDentroRegiaoGR) {
371
            log(String.format(
386
            log(String.format(
372
                    "GR[%d], G1[%d]: último comprador[%d] não fechou dentro da região do GR (fech=%s, faixa=[%s,%s]).",
-
 
373
                    idxGR, idxG1, idxUltimoComprador,
-
 
374
                    ultimoComprador.getFechamento().toPlainString(),
-
 
375
                    gr.getMinima().toPlainString(),
-
 
376
                    gr.getMaxima().toPlainString()
-
 
-
 
387
                    "GR[%d], G1[%d]: último comprador[%d] NÃO fechou dentro da região do GR.",
-
 
388
                    idxGR, idxG1, idxUltimoComprador
377
            ));
389
            ));
378
            return new ResultadoPadrao(null, lastIndex);
390
            return new ResultadoPadrao(null, lastIndex);
379
        }
391
        }
380
392
381
        g2 = ultimoComprador;
393
        g2 = ultimoComprador;
382
        idxG2 = idxUltimoComprador;
394
        idxG2 = idxUltimoComprador;
383
        log(String.format("GR[%d], G1[%d] => G2 (comprador) em [%d].", idxGR, idxG1, idxG2));
395
        log(String.format("GR[%d], G1[%d] => G2 (comprador) em [%d].", idxGR, idxG1, idxG2));
384
396
385
        // --------------------
397
        // --------------------
386
        // 3) Buscar G3 (vendedor rompe fundo de G2 com topo <= topo GR)
-
 
-
 
398
        // 3) Buscar G3 – NOVA REGRA:
-
 
399
        //    QUALQUER vendedor subsequente que rompa fundo de G2
-
 
400
        //    e tenha topo <= topo do GR.
387
        // --------------------
401
        // --------------------
388
        Candle g3 = null;
402
        Candle g3 = null;
389
        int idxG3 = -1;
403
        int idxG3 = -1;
390
404
391
        int idxPrimeiroVendedorAposG2 = -1;
-
 
392
        for (int i = idxG2 + 1; i < n; i++) {
405
        for (int i = idxG2 + 1; i < n; i++) {
393
            Candle c = candles.get(i);
406
            Candle c = candles.get(i);
394
            if (isInside(candles, i) || !isDirecional(c))
-
 
-
 
407
            if (!isDirecional(c) || isInside(candles, i)) {
395
                continue;
408
                continue;
-
 
409
            }
396
410
-
 
411
            // OUTSIDE antes/durante busca de G3 => descarta padrão
397
            if (isOutside(candles, i)) {
412
            if (isOutside(candles, i)) {
398
                lastIndex = idxGR;
413
                lastIndex = idxGR;
399
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da sequência vendedora de G3.", idxGR, i));
-
 
-
 
414
                log(String.format("GR[%d]: OUTSIDE em [%d] durante busca de G3 (vendedor).", idxGR, i));
400
                return new ResultadoPadrao(null, lastIndex);
415
                return new ResultadoPadrao(null, lastIndex);
401
            }
416
            }
402
417
403
            // Regra global: romper topo do GR invalida
-
 
-
 
418
            // Regra global comprador: romper topo do GR => descarta
404
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
419
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
405
                lastIndex = i;
420
                lastIndex = i;
406
                log(String.format("GR[%d]: candle[%d] rompeu topo do GR antes da perna vendedora de G3.", idxGR, i));
-
 
-
 
421
                log(String.format("GR[%d]: candle[%d] rompeu TOPO do GR durante busca de G3.", idxGR, i));
407
                return new ResultadoPadrao(null, lastIndex);
422
                return new ResultadoPadrao(null, lastIndex);
408
            }
423
            }
409
424
410
            if (c.isCandleVendedor()) {
425
            if (c.isCandleVendedor()) {
411
                idxPrimeiroVendedorAposG2 = i;
-
 
412
                break;
-
 
413
            } else {
-
 
414
                // primeiro direcional após G2 é comprador → padrão só até G2
-
 
415
                lastIndex = i;
-
 
416
                log(String.format("GR[%d], G1[%d], G2[%d]: primeiro direcional após G2 é comprador (idx %d).",
-
 
417
                        idxGR, idxG1, idxG2, i));
-
 
418
                return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
419
            }
-
 
420
        }
-
 
421
-
 
422
        if (idxPrimeiroVendedorAposG2 == -1) {
-
 
423
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve vendedor após G2.", idxGR, idxG1, idxG2));
-
 
424
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
425
        }
-
 
426
-
 
427
        for (int i = idxPrimeiroVendedorAposG2; i < n; i++) {
-
 
428
            Candle c = candles.get(i);
-
 
429
            if (isInside(candles, i) || !isDirecional(c))
-
 
430
                continue;
-
 
431
-
 
432
            if (isOutside(candles, i)) {
-
 
433
                lastIndex = idxGR;
-
 
434
                log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (vendedor).", idxGR, i));
-
 
435
                return new ResultadoPadrao(null, lastIndex);
-
 
436
            }
-
 
437
-
 
438
            // Regra global: romper topo do GR invalida
-
 
439
            if (BigDecimalUtils.ehMaiorQue(c.getMaxima(), gr.getMaxima())) {
-
 
440
                lastIndex = i;
-
 
441
                log(String.format("GR[%d]: candle[%d] rompeu topo do GR durante busca de G3.", idxGR, i));
-
 
442
                return new ResultadoPadrao(null, lastIndex);
-
 
443
            }
-
 
444
-
 
445
            if (!c.isCandleVendedor()) {
-
 
446
                // apareceu comprador antes de G3 → padrão só até G2
-
 
447
                lastIndex = i - 1;
-
 
448
                log(String.format("GR[%d], G1[%d], G2[%d]: comprador em [%d] antes de G3.", idxGR, idxG1, idxG2, i));
-
 
449
                return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
450
            }
-
 
451
-
 
452
            lastIndex = i;
-
 
453
            boolean rompeFundoG2 = BigDecimalUtils.ehMenorQue(c.getMinima(), g2.getMinima());
-
 
454
            boolean topoMenorOuIgualGR = BigDecimalUtils.ehMenorOuIgualQue(c.getMaxima(), gr.getMaxima());
-
 
455
            if (rompeFundoG2 && topoMenorOuIgualGR) {
-
 
456
                g3 = c;
-
 
457
                idxG3 = i;
-
 
458
                break;
-
 
-
 
426
                boolean rompeFundoG2 = BigDecimalUtils.ehMenorQue(c.getMinima(), g2.getMinima());
-
 
427
                boolean topoMenorOuIgualGR = BigDecimalUtils.ehMenorOuIgualQue(c.getMaxima(), gr.getMaxima());
-
 
428
                if (rompeFundoG2 && topoMenorOuIgualGR) {
-
 
429
                    g3 = c;
-
 
430
                    idxG3 = i;
-
 
431
                    lastIndex = i;
-
 
432
                    break;
-
 
433
                }
459
            }
434
            }
460
        }
435
        }
461
436
462
        if (g3 == null) {
437
        if (g3 == null) {
463
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve G3, padrão parcial.", idxGR, idxG1, idxG2));
-
 
-
 
438
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve G3 (comprador -> padrão parcial).",
-
 
439
                    idxGR, idxG1, idxG2));
464
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
440
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
465
        }
441
        }
466
442
467
        lastIndex = idxG3;
-
 
468
        log(String.format("GR[%d], G1[%d], G2[%d] => G3 (vendedor) em [%d].", idxGR, idxG1, idxG2, idxG3));
-
 
-
 
443
        log(String.format("GR[%d], G1[%d], G2[%d] => G3 (vendedor) em [%d].",
-
 
444
                idxGR, idxG1, idxG2, idxG3));
469
445
470
        PadraoGatilho padrao = new PadraoGatilho();
446
        PadraoGatilho padrao = new PadraoGatilho();
471
        padrao.setReferencia(gr);
447
        padrao.setReferencia(gr);
472
        padrao.setGatilho1(g1);
448
        padrao.setGatilho1(g1);
473
        padrao.setGatilho2(g2);
449
        padrao.setGatilho2(g2);
Line 491... Line 467...
491
        }
467
        }
492
468
493
        int idxCandidatoRef = idxInicio;
469
        int idxCandidatoRef = idxInicio;
494
470
495
        // --------------------
471
        // --------------------
496
        // 1) Buscar G1 (comprador rompe topo do candidato)
-
 
-
 
472
        // 1) Buscar G1: QUALQUER comprador subsequente que rompa o topo do candidatoRef
-
 
473
        //    (com GR dinâmico pela MÍNIMA antes de G1)
497
        // --------------------
474
        // --------------------
498
        Candle g1 = null;
475
        Candle g1 = null;
499
        int idxG1 = -1;
476
        int idxG1 = -1;
500
        boolean temGR = false;
-
 
501
        Candle gr = null;
477
        Candle gr = null;
502
        int idxGR = -1;
478
        int idxGR = -1;
503
479
504
        for (int i = idxInicio + 1; i < n; i++) {
480
        for (int i = idxInicio + 1; i < n; i++) {
505
            Candle c = candles.get(i);
481
            Candle c = candles.get(i);
506
            if (isInside(candles, i) || !isDirecional(c))
-
 
-
 
482
            if (isInside(candles, i) || !isDirecional(c)) {
507
                continue;
483
                continue;
-
 
484
            }
508
485
509
            // Outside antes de G1
-
 
-
 
486
            // OUTSIDE antes de G1 => descarta padrão
510
            if (isOutside(candles, i)) {
487
            if (isOutside(candles, i)) {
511
                lastIndex = i;
488
                lastIndex = i;
512
                log(String.format("Vendedor: OUTSIDE em [%d] antes de G1. Abortando padrão.", i));
489
                log(String.format("Vendedor: OUTSIDE em [%d] antes de G1. Abortando padrão.", i));
513
                return new ResultadoPadrao(null, lastIndex);
490
                return new ResultadoPadrao(null, lastIndex);
514
            }
491
            }
515
492
516
            // G1: comprador rompe topo do candidato
-
 
-
 
493
            // GR dinâmico (venda): atualiza candidatoRef pelo FUNDO mais baixo
-
 
494
            // enquanto não existir G1
-
 
495
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), candidatoRef.getMinima())) {
-
 
496
                candidatoRef = c;
-
 
497
                idxCandidatoRef = i;
-
 
498
                lastIndex = i;
-
 
499
                continue;
-
 
500
            }
-
 
501
-
 
502
            // G1: QUALQUER comprador subsequente que rompa o topo do candidatoRef
517
            if (c.isCandleComprador()
503
            if (c.isCandleComprador()
518
                    && BigDecimalUtils.ehMaiorQue(c.getMaxima(), candidatoRef.getMaxima())) {
504
                    && BigDecimalUtils.ehMaiorQue(c.getMaxima(), candidatoRef.getMaxima())) {
519
                g1 = c;
505
                g1 = c;
520
                idxG1 = i;
506
                idxG1 = i;
521
                gr = candidatoRef;
507
                gr = candidatoRef;
522
                idxGR = idxCandidatoRef;
508
                idxGR = idxCandidatoRef;
523
                temGR = true;
-
 
524
                lastIndex = i;
509
                lastIndex = i;
525
                break;
510
                break;
526
            }
-
 
527
-
 
528
            // GR DINÂMICO (venda): atualiza pelo FUNDO mais baixo antes de G1
-
 
529
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), candidatoRef.getMinima())) {
-
 
530
                candidatoRef = c;
-
 
531
                idxCandidatoRef = i;
-
 
532
                lastIndex = i;
-
 
533
                continue;
-
 
534
            }
511
            }
535
512
536
            lastIndex = i;
513
            lastIndex = i;
537
        }
514
        }
538
515
539
        if (g1 == null || !temGR) {
-
 
-
 
516
        if (g1 == null || gr == null) {
540
            log(String.format("Vendedor: não foi possível formar G1 a partir de idx %d.", idxInicio));
517
            log(String.format("Vendedor: não foi possível formar G1 a partir de idx %d.", idxInicio));
541
            return new ResultadoPadrao(null, lastIndex);
518
            return new ResultadoPadrao(null, lastIndex);
542
        }
519
        }
543
520
544
        log(String.format("GR VENDEDOR em [%d], G1 (comprador) em [%d].", idxGR, idxG1));
521
        log(String.format("GR VENDEDOR em [%d], G1 (comprador) em [%d].", idxGR, idxG1));
545
522
546
        // --------------------
523
        // --------------------
547
        // 2) Buscar G2 (tendência vendedora com fechamento dentro do GR)
-
 
-
 
524
        // 2) Buscar G2 – tendência VENDEDORA com fechamento dentro do GR
548
        // --------------------
525
        // --------------------
549
        Candle g2 = null;
526
        Candle g2 = null;
550
        int idxG2 = -1;
527
        int idxG2 = -1;
551
528
552
        int idxPrimeiroVendedor = -1;
529
        int idxPrimeiroVendedor = -1;
553
        for (int i = idxG1 + 1; i < n; i++) {
530
        for (int i = idxG1 + 1; i < n; i++) {
554
            Candle c = candles.get(i);
531
            Candle c = candles.get(i);
555
            if (isInside(candles, i) || !isDirecional(c))
-
 
556
                continue;
-
 
-
 
532
            if (isInside(candles, i) || !isDirecional(c)) continue;
557
533
558
            // Outside antes de G3
-
 
-
 
534
            // OUTSIDE antes de G2 => descarta padrão
559
            if (isOutside(candles, i)) {
535
            if (isOutside(candles, i)) {
560
                lastIndex = idxGR;
536
                lastIndex = idxGR;
561
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da perna vendedora de G2.", idxGR, i));
-
 
-
 
537
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da tendência vendedora de G2.", idxGR, i));
562
                return new ResultadoPadrao(null, lastIndex);
538
                return new ResultadoPadrao(null, lastIndex);
563
            }
539
            }
564
540
565
            // Regra global vendedor: romper fundo do GR invalida
-
 
-
 
541
            // Regra global vendedor: romper fundo do GR => descarta
566
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
542
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
567
                lastIndex = i;
543
                lastIndex = i;
568
                log(String.format("GR[%d]: candle[%d] rompeu fundo do GR antes de G2.", idxGR, i));
-
 
-
 
544
                log(String.format("GR[%d]: candle[%d] rompeu FUNDO do GR antes/na formação de G2.", idxGR, i));
569
                return new ResultadoPadrao(null, lastIndex);
545
                return new ResultadoPadrao(null, lastIndex);
570
            }
546
            }
571
547
572
            if (c.isCandleVendedor()) {
548
            if (c.isCandleVendedor()) {
573
                idxPrimeiroVendedor = i;
549
                idxPrimeiroVendedor = i;
Line 585... Line 561...
585
        Candle ultimoVendedor = null;
561
        Candle ultimoVendedor = null;
586
        int idxUltimoVendedor = -1;
562
        int idxUltimoVendedor = -1;
587
563
588
        for (int i = idxPrimeiroVendedor; i < n; i++) {
564
        for (int i = idxPrimeiroVendedor; i < n; i++) {
589
            Candle c = candles.get(i);
565
            Candle c = candles.get(i);
590
            if (isInside(candles, i) || !isDirecional(c))
-
 
591
                continue;
-
 
-
 
566
            if (isInside(candles, i) || !isDirecional(c)) continue;
592
567
593
            // Outside durante G2
-
 
-
 
568
            // OUTSIDE durante G2 => descarta padrão
594
            if (isOutside(candles, i)) {
569
            if (isOutside(candles, i)) {
595
                lastIndex = idxGR;
570
                lastIndex = idxGR;
596
                log(String.format("GR[%d]: OUTSIDE em [%d] durante G2 (vendedor).", idxGR, i));
-
 
-
 
571
                log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G2 (vendedor).", idxGR, i));
597
                return new ResultadoPadrao(null, lastIndex);
572
                return new ResultadoPadrao(null, lastIndex);
598
            }
573
            }
599
574
600
            // Regra global vendedor: romper fundo do GR invalida
-
 
-
 
575
            // Regra global vendedor: romper fundo do GR => descarta
601
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
576
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
602
                lastIndex = i;
577
                lastIndex = i;
603
                log(String.format("GR[%d]: candle[%d] rompeu fundo do GR durante G2.", idxGR, i));
-
 
-
 
578
                log(String.format("GR[%d]: candle[%d] rompeu FUNDO do GR durante G2.", idxGR, i));
604
                return new ResultadoPadrao(null, lastIndex);
579
                return new ResultadoPadrao(null, lastIndex);
605
            }
580
            }
606
581
607
            if (c.isCandleVendedor()) {
582
            if (c.isCandleVendedor()) {
608
                ultimoVendedor = c;
583
                ultimoVendedor = c;
Line 623... Line 598...
623
                BigDecimalUtils.ehMaiorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMinima()) &&
598
                BigDecimalUtils.ehMaiorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMinima()) &&
624
                BigDecimalUtils.ehMenorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMaxima());
599
                BigDecimalUtils.ehMenorOuIgualQue(ultimoVendedor.getFechamento(), gr.getMaxima());
625
600
626
        if (!fechamentoDentroRegiaoGR) {
601
        if (!fechamentoDentroRegiaoGR) {
627
            log(String.format(
602
            log(String.format(
628
                    "GR[%d], G1[%d]: último vendedor[%d] não fechou dentro da região do GR (fech=%s, faixa=[%s,%s]).",
-
 
629
                    idxGR, idxG1, idxUltimoVendedor,
-
 
630
                    ultimoVendedor.getFechamento().toPlainString(),
-
 
631
                    gr.getMinima().toPlainString(),
-
 
632
                    gr.getMaxima().toPlainString()
-
 
-
 
603
                    "GR[%d], G1[%d]: último vendedor[%d] NÃO fechou dentro da região do GR.",
-
 
604
                    idxGR, idxG1, idxUltimoVendedor
633
            ));
605
            ));
634
            return new ResultadoPadrao(null, lastIndex);
606
            return new ResultadoPadrao(null, lastIndex);
635
        }
607
        }
636
608
637
        g2 = ultimoVendedor;
609
        g2 = ultimoVendedor;
638
        idxG2 = idxUltimoVendedor;
610
        idxG2 = idxUltimoVendedor;
639
        log(String.format("GR[%d], G1[%d] => G2 (vendedor) em [%d].", idxGR, idxG1, idxG2));
611
        log(String.format("GR[%d], G1[%d] => G2 (vendedor) em [%d].", idxGR, idxG1, idxG2));
640
612
641
        // --------------------
613
        // --------------------
642
        // 3) Buscar G3 (comprador rompe topo de G2 com fundo >= fundo GR)
-
 
-
 
614
        // 3) Buscar G3 – NOVA REGRA:
-
 
615
        //    QUALQUER comprador subsequente que rompa topo de G2
-
 
616
        //    e tenha fundo >= fundo do GR.
643
        // --------------------
617
        // --------------------
644
        Candle g3 = null;
618
        Candle g3 = null;
645
        int idxG3 = -1;
619
        int idxG3 = -1;
646
620
647
        int idxPrimeiroCompradorAposG2 = -1;
-
 
648
        for (int i = idxG2 + 1; i < n; i++) {
621
        for (int i = idxG2 + 1; i < n; i++) {
649
            Candle c = candles.get(i);
622
            Candle c = candles.get(i);
650
            if (isInside(candles, i) || !isDirecional(c))
-
 
-
 
623
            if (!isDirecional(c) || isInside(candles, i)) {
651
                continue;
624
                continue;
-
 
625
            }
652
626
-
 
627
            // OUTSIDE antes/durante busca de G3 => descarta padrão
653
            if (isOutside(candles, i)) {
628
            if (isOutside(candles, i)) {
654
                lastIndex = idxGR;
629
                lastIndex = idxGR;
655
                log(String.format("GR[%d]: OUTSIDE em [%d] antes da sequência compradora de G3.", idxGR, i));
-
 
-
 
630
                log(String.format("GR[%d]: OUTSIDE em [%d] durante busca de G3 (comprador).", idxGR, i));
656
                return new ResultadoPadrao(null, lastIndex);
631
                return new ResultadoPadrao(null, lastIndex);
657
            }
632
            }
658
633
659
            // Regra global vendedor: romper fundo do GR antes de G3 invalida
-
 
-
 
634
            // Regra global vendedor: romper fundo do GR => descarta
660
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
635
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
661
                lastIndex = i;
636
                lastIndex = i;
662
                log(String.format("GR[%d]: candle[%d] rompeu fundo do GR antes de G3.", idxGR, i));
-
 
-
 
637
                log(String.format("GR[%d]: candle[%d] rompeu FUNDO do GR durante busca de G3.", idxGR, i));
663
                return new ResultadoPadrao(null, lastIndex);
638
                return new ResultadoPadrao(null, lastIndex);
664
            }
639
            }
665
640
666
            if (c.isCandleComprador()) {
641
            if (c.isCandleComprador()) {
667
                idxPrimeiroCompradorAposG2 = i;
-
 
668
                break;
-
 
669
            } else {
-
 
670
                // primeiro direcional não é comprador → padrão até G2
-
 
671
                lastIndex = i;
-
 
672
                log(String.format("GR[%d], G1[%d], G2[%d]: primeiro direcional após G2 não é comprador (idx %d).",
-
 
673
                        idxGR, idxG1, idxG2, i));
-
 
674
                return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
675
            }
-
 
676
        }
-
 
677
-
 
678
        if (idxPrimeiroCompradorAposG2 == -1) {
-
 
679
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve comprador após G2.", idxGR, idxG1, idxG2));
-
 
680
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
681
        }
-
 
682
-
 
683
        for (int i = idxPrimeiroCompradorAposG2; i < n; i++) {
-
 
684
            Candle c = candles.get(i);
-
 
685
            if (isInside(candles, i) || !isDirecional(c))
-
 
686
                continue;
-
 
687
-
 
688
            if (isOutside(candles, i)) {
-
 
689
                lastIndex = idxGR;
-
 
690
                log(String.format("GR[%d]: OUTSIDE em [%d] durante formação de G3 (comprador).", idxGR, i));
-
 
691
                return new ResultadoPadrao(null, lastIndex);
-
 
692
            }
-
 
693
-
 
694
            // Regra global vendedor: romper fundo do GR invalida
-
 
695
            if (BigDecimalUtils.ehMenorQue(c.getMinima(), gr.getMinima())) {
-
 
696
                lastIndex = i;
-
 
697
                log(String.format("GR[%d]: candle[%d] rompeu fundo do GR durante busca de G3.", idxGR, i));
-
 
698
                return new ResultadoPadrao(null, lastIndex);
-
 
699
            }
-
 
700
-
 
701
            if (!c.isCandleComprador()) {
-
 
702
                // apareceu vendedor antes de G3 → padrão só até G2
-
 
703
                lastIndex = i - 1;
-
 
704
                log(String.format("GR[%d], G1[%d], G2[%d]: vendedor em [%d] antes de G3.", idxGR, idxG1, idxG2, i));
-
 
705
                return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
-
 
706
            }
-
 
707
-
 
708
            lastIndex = i;
-
 
709
            boolean rompeTopoG2 = BigDecimalUtils.ehMaiorQue(c.getMaxima(), g2.getMaxima());
-
 
710
            boolean fundoMaiorOuIgualGR = BigDecimalUtils.ehMaiorOuIgualQue(c.getMinima(), gr.getMinima());
-
 
711
            if (rompeTopoG2 && fundoMaiorOuIgualGR) {
-
 
712
                g3 = c;
-
 
713
                idxG3 = i;
-
 
714
                break;
-
 
-
 
642
                boolean rompeTopoG2 = BigDecimalUtils.ehMaiorQue(c.getMaxima(), g2.getMaxima());
-
 
643
                boolean fundoMaiorOuIgualGR = BigDecimalUtils.ehMaiorOuIgualQue(c.getMinima(), gr.getMinima());
-
 
644
                if (rompeTopoG2 && fundoMaiorOuIgualGR) {
-
 
645
                    g3 = c;
-
 
646
                    idxG3 = i;
-
 
647
                    lastIndex = i;
-
 
648
                    break;
-
 
649
                }
715
            }
650
            }
716
        }
651
        }
717
652
718
        if (g3 == null) {
653
        if (g3 == null) {
719
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve G3, padrão parcial.", idxGR, idxG1, idxG2));
-
 
-
 
654
            log(String.format("GR[%d], G1[%d], G2[%d]: não houve G3 (vendedor -> padrão parcial).",
-
 
655
                    idxGR, idxG1, idxG2));
720
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
656
            return criarResultadoParcialComG2(gr, g1, g2, lastIndex);
721
        }
657
        }
722
658
723
        lastIndex = idxG3;
-
 
724
        log(String.format("GR[%d], G1[%d], G2[%d] => G3 (comprador) em [%d].", idxGR, idxG1, idxG2, idxG3));
-
 
-
 
659
        log(String.format("GR[%d], G1[%d], G2[%d] => G3 (comprador) em [%d].",
-
 
660
                idxGR, idxG1, idxG2, idxG3));
725
661
726
        PadraoGatilho padrao = new PadraoGatilho();
662
        PadraoGatilho padrao = new PadraoGatilho();
727
        padrao.setReferencia(gr);
663
        padrao.setReferencia(gr);
728
        padrao.setGatilho1(g1);
664
        padrao.setGatilho1(g1);
729
        padrao.setGatilho2(g2);
665
        padrao.setGatilho2(g2);
Line 739... Line 675...
739
675
740
    public void resetTempoReal() {
676
    public void resetTempoReal() {
741
        this.idxProximaAnaliseTempoReal = 0;
677
        this.idxProximaAnaliseTempoReal = 0;
742
    }
678
    }
743
679
-
 
680
    /**
-
 
681
     * Deve ser chamado SEMPRE que um novo candle for adicionado à lista.
-
 
682
     *
-
 
683
     * Exemplo:
-
 
684
     *   candles.add(novoCandle);
-
 
685
     *   PadraoGatilho padrao = detector.processarCandleTempoReal(candles);
-
 
686
     *
-
 
687
     *   if (padrao != null) {
-
 
688
     *       // padrão completo (até G3) encontrado
-
 
689
     *   }
-
 
690
     */
744
    public PadraoGatilho processarCandleTempoReal(List<Candle> candles) {
691
    public PadraoGatilho processarCandleTempoReal(List<Candle> candles) {
745
        int n = candles.size();
692
        int n = candles.size();
746
        if (n < 4) return null;
693
        if (n < 4) return null;
747
694
748
        while (idxProximaAnaliseTempoReal < n - 3) {
695
        while (idxProximaAnaliseTempoReal < n - 3) {