Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
762 blopes 1
package br.com.sl.domain.util;
2
 
3
import java.math.BigDecimal;
4
import java.math.RoundingMode;
5
 
6
public final class CandleMathUtils {
7
 
8
    private static final BigDecimal ZERO = BigDecimal.ZERO;
9
    private static final BigDecimal CEM  = BigDecimal.valueOf(100);
10
 
11
    private CandleMathUtils() {}
12
 
13
    /* ============================================================
14
       HELPERS
15
       ============================================================ */
16
 
17
    private static BigDecimal n(BigDecimal v) {
18
        return v == null ? ZERO : v;
19
    }
20
 
21
    private static BigDecimal max(BigDecimal a, BigDecimal b) {
22
        return n(a).compareTo(n(b)) >= 0 ? n(a) : n(b);
23
    }
24
 
25
    private static BigDecimal min(BigDecimal a, BigDecimal b) {
26
        return n(a).compareTo(n(b)) <= 0 ? n(a) : n(b);
27
    }
28
 
29
    /* ============================================================
30
       OPERAÇÕES BÁSICAS DO CANDLE
31
       ============================================================ */
32
 
33
    /**
34
     * Corpo do candle (fechamento - abertura).
35
     * Pode ser positivo (comprador), negativo (vendedor) ou zero (doji).
36
     */
37
    public static BigDecimal corpo(BigDecimal abertura, BigDecimal fechamento) {
38
        return n(fechamento).subtract(n(abertura));
39
    }
40
 
41
    /**
42
     * Módulo do corpo (tamanho absoluto).
43
     */
44
    public static BigDecimal corpoAbs(BigDecimal abertura, BigDecimal fechamento) {
45
        return corpo(abertura, fechamento).abs();
46
    }
47
 
48
    /**
49
     * Amplitude total do candle: máxima - mínima.
50
     */
51
    public static BigDecimal amplitude(BigDecimal maxima, BigDecimal minima) {
52
        return n(maxima).subtract(n(minima)).abs();
53
    }
54
 
55
    /**
56
     * Pavio superior: máxima - max(abertura, fechamento).
57
     */
58
    public static BigDecimal pavioSuperior(BigDecimal abertura, BigDecimal fechamento, BigDecimal maxima) {
59
        BigDecimal topoCorpo = max(abertura, fechamento);
60
        return n(maxima).subtract(topoCorpo).max(ZERO);
61
    }
62
 
63
    /**
64
     * Pavio inferior: min(abertura, fechamento) - mínima.
65
     */
66
    public static BigDecimal pavioInferior(BigDecimal abertura, BigDecimal fechamento, BigDecimal minima) {
67
        BigDecimal baseCorpo = min(abertura, fechamento);
68
        return baseCorpo.subtract(n(minima)).max(ZERO);
69
    }
70
 
71
    /* ============================================================
72
       CLASSIFICAÇÃO DO CANDLE
73
       ============================================================ */
74
 
75
    /**
76
     * Candle comprador (fechamento > abertura).
77
     */
78
    public static boolean isComprador(BigDecimal abertura, BigDecimal fechamento) {
79
        return n(fechamento).compareTo(n(abertura)) > 0;
80
    }
81
 
82
    /**
83
     * Candle vendedor (fechamento < abertura).
84
     */
85
    public static boolean isVendedor(BigDecimal abertura, BigDecimal fechamento) {
86
        return n(fechamento).compareTo(n(abertura)) < 0;
87
    }
88
 
89
    /**
90
     * Candle neutro (fechamento == abertura).
91
     */
92
    public static boolean isNeutro(BigDecimal abertura, BigDecimal fechamento) {
93
        return n(fechamento).compareTo(n(abertura)) == 0;
94
    }
95
 
96
    /**
97
     * Doji: corpo muito pequeno em relação à amplitude.
98
     * limiarPercentual é o máximo de % do corpo em relação à amplitude (ex: 10 → 10%).
99
     */
100
    public static boolean isDoji(BigDecimal abertura,
101
                                 BigDecimal fechamento,
102
                                 BigDecimal maxima,
103
                                 BigDecimal minima,
104
                                 BigDecimal limiarPercentual) {
105
 
106
        BigDecimal amp = amplitude(maxima, minima);
107
        if (amp.compareTo(ZERO) == 0) {
108
            // Candle "travado" (sem range)
109
            return true;
110
        }
111
 
112
        BigDecimal corpoAbs = corpoAbs(abertura, fechamento);
113
        // (corpo / amplitude) * 100
114
        BigDecimal perc = corpoAbs
115
                .multiply(CEM)
116
                .divide(amp, 6, RoundingMode.HALF_UP);
117
 
118
        return perc.compareTo(n(limiarPercentual)) <= 0;
119
    }
120
 
121
    /* ============================================================
122
       POSIÇÃO DO FECHAMENTO DENTRO DO CANDLE
123
       ============================================================ */
124
 
125
    /**
126
     * Retorna o percentual do fechamento dentro da amplitude do candle.
127
     * 0% = na mínima, 100% = na máxima.
128
     */
129
    public static BigDecimal percentualFechamentoNaAmplitude(BigDecimal abertura,
130
                                                             BigDecimal fechamento,
131
                                                             BigDecimal maxima,
132
                                                             BigDecimal minima) {
133
        BigDecimal amp = amplitude(maxima, minima);
134
        if (amp.compareTo(ZERO) == 0) {
135
            return ZERO;
136
        }
137
 
138
        // (fechamento - minima) / amplitude * 100
139
        BigDecimal num = n(fechamento).subtract(n(minima));
140
        return num
141
                .multiply(CEM)
142
                .divide(amp, 6, RoundingMode.HALF_UP);
143
    }
144
 
145
    /**
146
     * Retorna o percentual de retração do fechamento a partir da máxima até a mínima.
147
     * 0% = na máxima, 100% = na mínima.
148
     */
149
    public static BigDecimal percentualRetraidoDaMaxima(BigDecimal fechamento,
150
                                                        BigDecimal maxima,
151
                                                        BigDecimal minima) {
152
        BigDecimal amp = amplitude(maxima, minima);
153
        if (amp.compareTo(ZERO) == 0) {
154
            return ZERO;
155
        }
156
 
157
        // (maxima - fechamento) / amplitude * 100
158
        BigDecimal num = n(maxima).subtract(n(fechamento));
159
        return num
160
                .multiply(CEM)
161
                .divide(amp, 6, RoundingMode.HALF_UP);
162
    }
163
 
164
    /* ============================================================
165
       VERSÕES EM double (para gráficos, logs, etc.)
166
       ============================================================ */
167
 
168
    public static double corpoDouble(BigDecimal abertura, BigDecimal fechamento) {
169
        return corpo(abertura, fechamento).doubleValue();
170
    }
171
 
172
    public static double amplitudeDouble(BigDecimal maxima, BigDecimal minima) {
173
        return amplitude(maxima, minima).doubleValue();
174
    }
175
 
176
    public static double pavioSuperiorDouble(BigDecimal abertura, BigDecimal fechamento, BigDecimal maxima) {
177
        return pavioSuperior(abertura, fechamento, maxima).doubleValue();
178
    }
179
 
180
    public static double pavioInferiorDouble(BigDecimal abertura, BigDecimal fechamento, BigDecimal minima) {
181
        return pavioInferior(abertura, fechamento, minima).doubleValue();
182
    }
183
 
184
    public static double percentualFechamentoNaAmplitudeDouble(BigDecimal abertura,
185
                                                               BigDecimal fechamento,
186
                                                               BigDecimal maxima,
187
                                                               BigDecimal minima) {
188
        return percentualFechamentoNaAmplitude(abertura, fechamento, maxima, minima).doubleValue();
189
    }
190
 
191
    public static double percentualRetraidoDaMaximaDouble(BigDecimal fechamento,
192
                                                          BigDecimal maxima,
193
                                                          BigDecimal minima) {
194
        return percentualRetraidoDaMaxima(fechamento, maxima, minima).doubleValue();
195
    }
196
 
197
}