Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
778 blopes 1
package br.com.robo.model;
2
 
3
import br.com.robo.model.Candle;
4
 
5
import java.util.*;
6
import java.util.stream.Collectors;
7
 
8
public class SwingLevelDetector {
9
 
10
    public enum LevelType {
11
        HIGH, LOW
12
    }
13
 
14
    public static class Level {
15
        private final int index;
16
        private final double price;
17
        private final LevelType type;
18
        // flag interno
19
        private boolean mitigated;
20
 
21
        public Level(int index, double price, LevelType type) {
22
            this.index = index;
23
            this.price = price;
24
            this.type = type;
25
            this.mitigated = false;
26
        }
27
 
28
        public int getIndex() {
29
            return index;
30
        }
31
 
32
        public double getPrice() {
33
            return price;
34
        }
35
 
36
        public LevelType getType() {
37
            return type;
38
        }
39
 
40
        boolean isMitigated() {
41
            return mitigated;
42
        }
43
 
44
        void setMitigated(boolean mitigated) {
45
            this.mitigated = mitigated;
46
        }
47
 
48
        @Override
49
        public String toString() {
50
            return "Level{" +
51
                    "index=" + index +
52
                    ", price=" + price +
53
                    ", type=" + type +
54
                    '}';
55
        }
56
    }
57
 
58
    /**
59
     * Detecta fundos e topos predominantes:
60
     * - encontra pivôs (high > vizinhos = topo, low < vizinhos = fundo)
61
     * - forma pares adjacentes (topo-fundo ou fundo-topo)
62
     * - para cada par, calcula a linha média (50%)
63
     * - se depois do par houver:
64
     *      * rompimento da linha média (50%), OU
65
     *      * rompimento do topo, OU
66
     *      * rompimento do fundo,
67
     *   o par é considerado mitigado e seus níveis são descartados
68
     * - retorna apenas níveis NÃO mitigados (predominantes)
69
     */
70
    public List<Level> detectPredominantLevels(List<Candle> candles) {
71
        List<Level> pivots = detectSwings(candles);
72
        if (pivots.size() < 2) {
73
            return Collections.emptyList();
74
        }
75
 
76
        for (int i = 0; i < pivots.size() - 1; i++) {
77
            Level a = pivots.get(i);
78
            Level b = pivots.get(i + 1);
79
 
80
            double topPrice;
81
            double bottomPrice;
82
 
83
            if (a.getType() == LevelType.HIGH && b.getType() == LevelType.LOW) {
84
                topPrice = a.getPrice();
85
                bottomPrice = b.getPrice();
86
            } else if (a.getType() == LevelType.LOW && b.getType() == LevelType.HIGH) {
87
                topPrice = b.getPrice();
88
                bottomPrice = a.getPrice();
89
            } else {
90
                // dois topos seguidos ou dois fundos seguidos → não formam um par topo–fundo ou fundo–topo
91
                continue;
92
            }
93
 
94
            double mid = (topPrice + bottomPrice) / 2.0;
95
            int lastIdx = Math.max(a.getIndex(), b.getIndex());
96
 
97
            boolean mitigatedPair = false;
98
            for (int j = lastIdx + 1; j < candles.size(); j++) {
99
                Candle c = candles.get(j);
100
 
101
                boolean rompeMid = (c.getHigh() >= mid && c.getLow() <= mid);
102
                boolean rompeTopo = c.getHigh() > topPrice;
103
                boolean rompeFundo = c.getLow() < bottomPrice;
104
 
105
                if (rompeMid || rompeTopo || rompeFundo) {
106
                    mitigatedPair = true;
107
                    break;
108
                }
109
            }
110
 
111
            if (mitigatedPair) {
112
                a.setMitigated(true);
113
                b.setMitigated(true);
114
            }
115
        }
116
 
117
        // ✅ Só devolve os níveis que nunca foram mitigados em nenhum par
118
        return pivots.stream()
119
                .filter(l -> !l.isMitigated())
120
                .collect(Collectors.toList());
121
    }
122
 
123
    /**
124
     * Detecta pivôs simples:
125
     * - topo: high[i] > high[i-1] e high[i] > high[i+1]
126
     * - fundo: low[i] < low[i-1] e low[i] < low[i+1]
127
     */
128
    private List<Level> detectSwings(List<Candle> candles) {
129
        List<Level> levels = new ArrayList<>();
130
        for (int i = 1; i < candles.size() - 1; i++) {
131
            Candle prev = candles.get(i - 1);
132
            Candle curr = candles.get(i);
133
            Candle next = candles.get(i + 1);
134
 
135
            if (curr.getHigh() > prev.getHigh() && curr.getHigh() > next.getHigh()) {
136
                levels.add(new Level(i, curr.getHigh(), LevelType.HIGH));
137
            } else if (curr.getLow() < prev.getLow() && curr.getLow() < next.getLow()) {
138
                levels.add(new Level(i, curr.getLow(), LevelType.LOW));
139
            }
140
        }
141
        return levels;
142
    }
143
 
144
}