Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
760 blopes 1
package br.com.robo.model;
2
 
3
import java.util.ArrayList;
4
import java.util.List;
5
 
6
 
7
/**
8
 * Identifica sequências de 3 gatilhos em tendência de alta,
9
 * conforme regras fornecidas.
10
 */
11
public class TriggerFinder {
12
 
13
    /**
14
     * Representa um padrão completo de gatilhos:
15
     * - refIndex: candle de referência (topo da perna de alta)
16
     * - g1Index: índice do Gatilho tipo 1
17
     * - g2Index: índice do Gatilho tipo 2
18
     * - g3Index: índice do Gatilho tipo 3
19
     */
20
    public static class TriggerPattern {
21
        private final int refIndex;
22
        private final int g1Index;
23
        private final int g2Index;
24
        private final int g3Index;
25
 
26
        public TriggerPattern(int refIndex, int g1Index, int g2Index, int g3Index) {
27
            this.refIndex = refIndex;
28
            this.g1Index = g1Index;
29
            this.g2Index = g2Index;
30
            this.g3Index = g3Index;
31
        }
32
 
33
        public int getRefIndex() {
34
            return refIndex;
35
        }
36
 
37
        public int getG1Index() {
38
            return g1Index;
39
        }
40
 
41
        public int getG2Index() {
42
            return g2Index;
43
        }
44
 
45
        public int getG3Index() {
46
            return g3Index;
47
        }
48
 
49
        @Override
50
        public String toString() {
51
            return "TriggerPattern{" +
52
                    "refIndex=" + refIndex +
53
                    ", g1Index=" + g1Index +
54
                    ", g2Index=" + g2Index +
55
                    ", g3Index=" + g3Index +
56
                    '}';
57
        }
58
    }
59
 
60
    /**
61
     * Encontra todos os padrões de 3 gatilhos em tendência de alta
62
     * na lista de candles.
63
     */
64
    public List<TriggerPattern> findTriggers(List<Candle> candles) {
65
        List<TriggerPattern> patterns = new ArrayList<>();
66
        if (candles == null || candles.size() < 5) {
67
            return patterns;
68
        }
69
 
70
        int i = 2; // começa em 2 por causa da checagem de tendência
71
        while (i < candles.size() - 3) {
72
 
73
            int refIndex = i - 1;
74
            Candle ref = candles.get(refIndex);
75
            Candle possibleG1 = candles.get(i);
76
 
77
            // 1) Tendência de alta antes do refIndex
78
            if (!isUptrend(candles, refIndex)) {
79
                i++;
80
                continue;
81
            }
82
 
83
            // 2) Candle de referência deve ser comprador
84
            if (!isBullish(ref)) {
85
                i++;
86
                continue;
87
            }
88
 
89
            // 3) Gatilho tipo 1: candle vendedor contrário ao ref
90
            if (!isBearish(possibleG1)) {
91
                i++;
92
                continue;
93
            }
94
 
95
            int g1Index = i;
96
            Candle g1 = possibleG1;
97
 
98
            int g2Index = -1;
99
            int g3Index = -1;
100
 
101
            // -------------------------------
102
            // 4) Procurar G2
103
            //
104
            // Gatilho tipo 2:
105
            // - Candle comprador dentro da região da referência (ref)
106
            //      => high(G2) <= high(ref) e low(G2) >= low(ref)
107
            //   OU
108
            // - Candle vendedor rompendo com pavio o topo do G1
109
            //      => candle vendedor e high(G2) > high(G1)
110
            //
111
            // IMPORTANTE: aqui AINDA NÃO vale a regra especial
112
            // do rompimento do topo da referência; ela só entra
113
            // na etapa de busca do G3.
114
            // -------------------------------
115
            int j = g1Index + 1;
116
            while (j < candles.size() - 1) { // deixa pelo menos 1 candle depois pra ser o G3
117
                Candle c = candles.get(j);
118
 
119
                boolean isG2 = false;
120
 
121
                // Caso 1: comprador dentro da região da referência
122
                boolean compradorDentroRef =
123
                        isBullish(c)
124
                        && c.getHigh() <= ref.getHigh()
125
                        && c.getLow() >= ref.getLow();
126
 
127
                // Caso 2: vendedor rompendo com pavio o topo do G1
128
                // (pavio rompe topo do G1)
129
                boolean vendedorRompeTopoG1 =
130
                        isBearish(c)
131
                        && c.getHigh() > g1.getHigh();
132
 
133
                if (compradorDentroRef || vendedorRompeTopoG1) {
134
                    isG2 = true;
135
                }
136
 
137
                if (isG2) {
138
                    g2Index = j;
139
                    break;
140
                }
141
 
142
                j++;
143
            }
144
 
145
            // Se não achou G2, avança e segue a busca
146
            if (g2Index == -1) {
147
                i++;
148
                continue;
149
            }
150
 
151
            Candle g2 = candles.get(g2Index);
152
 
153
            // -------------------------------
154
            // 5) Procurar G3
155
            //
156
            // Gatilho tipo 3:
157
            // - Candle vendedor
158
            // - topo < topo do candle de referência
159
            // - rompe o fundo do G2 (low(G3) < low(G2))
160
            //
161
            // REGRA ESPECIAL:
162
            // "Se houver o rompimento do topo do referência,
163
            //  não considerar mais os gatilhos definidos anteriormente."
164
            //
165
            // Ou seja: durante a busca do G3, se QUALQUER candle tiver
166
            // high > high(ref), invalida essa sequência.
167
            // -------------------------------
168
            boolean invalidSequence = false;
169
            int k = g2Index + 1;
170
            while (k < candles.size()) {
171
                Candle c = candles.get(k);
172
 
173
                // Regra especial: rompimento do topo da referência
174
                if (c.getHigh() > ref.getHigh()) {
175
                    invalidSequence = true;
176
                    break;
177
                }
178
 
179
                if (isBearish(c)
180
                        && c.getHigh() < ref.getHigh()
181
                        && c.getLow() < g2.getLow()) {
182
                    g3Index = k;
183
                    break;
184
                }
185
 
186
                k++;
187
            }
188
 
189
            if (invalidSequence) {
190
                // sequência descartada, segue a partir do candle
191
                // que rompeu o topo da referência
192
                i = k + 1;
193
                continue;
194
            }
195
 
196
            if (g3Index != -1) {
197
                patterns.add(new TriggerPattern(refIndex, g1Index, g2Index, g3Index));
198
                // pula pra depois do G3 pra evitar muitos padrões sobrepostos
199
                i = g3Index + 1;
200
            } else {
201
                // não houve G3, segue a partir do próximo candle após G1
202
                i = g1Index + 1;
203
            }
204
        }
205
 
206
        return patterns;
207
    }
208
 
209
    // ---------- Funções auxiliares ----------
210
 
211
    private boolean isBullish(Candle c) {
212
        return c.getClose() > c.getOpen();
213
    }
214
 
215
    private boolean isBearish(Candle c) {
216
        return c.getClose() < c.getOpen();
217
    }
218
 
219
    /**
220
     * Tendência de alta simples:
221
     * close[ref] > close[ref-1] > close[ref-2]
222
     */
223
    private boolean isUptrend(List<Candle> candles, int refIndex) {
224
        if (refIndex < 2) {
225
            return false;
226
        }
227
        double c0 = candles.get(refIndex).getClose();
228
        double c1 = candles.get(refIndex - 1).getClose();
229
        double c2 = candles.get(refIndex - 2).getClose();
230
        return c0 > c1 && c1 > c2;
231
    }
232
 
233
}