Subversion Repositories Integrator Subversion

Rev

Blame | Last modification | View Log | Download | RSS feed

package br.com.robo.model;

import br.com.robo.model.Candle;

import java.util.*;
import java.util.stream.Collectors;

public class SwingLevelDetector {

    public enum LevelType {
        HIGH, LOW
    }

    public static class Level {
        private final int index;
        private final double price;
        private final LevelType type;
        // flag interno
        private boolean mitigated;

        public Level(int index, double price, LevelType type) {
            this.index = index;
            this.price = price;
            this.type = type;
            this.mitigated = false;
        }

        public int getIndex() {
            return index;
        }

        public double getPrice() {
            return price;
        }

        public LevelType getType() {
            return type;
        }

        boolean isMitigated() {
            return mitigated;
        }

        void setMitigated(boolean mitigated) {
            this.mitigated = mitigated;
        }

        @Override
        public String toString() {
            return "Level{" +
                    "index=" + index +
                    ", price=" + price +
                    ", type=" + type +
                    '}';
        }
    }

    /**
     * Detecta fundos e topos predominantes:
     * - encontra pivôs (high > vizinhos = topo, low < vizinhos = fundo)
     * - forma pares adjacentes (topo-fundo ou fundo-topo)
     * - para cada par, calcula a linha média (50%)
     * - se depois do par houver:
     *      * rompimento da linha média (50%), OU
     *      * rompimento do topo, OU
     *      * rompimento do fundo,
     *   o par é considerado mitigado e seus níveis são descartados
     * - retorna apenas níveis NÃO mitigados (predominantes)
     */

    public List<Level> detectPredominantLevels(List<Candle> candles) {
        List<Level> pivots = detectSwings(candles);
        if (pivots.size() < 2) {
            return Collections.emptyList();
        }

        for (int i = 0; i < pivots.size() - 1; i++) {
            Level a = pivots.get(i);
            Level b = pivots.get(i + 1);

            double topPrice;
            double bottomPrice;

            if (a.getType() == LevelType.HIGH && b.getType() == LevelType.LOW) {
                topPrice = a.getPrice();
                bottomPrice = b.getPrice();
            } else if (a.getType() == LevelType.LOW && b.getType() == LevelType.HIGH) {
                topPrice = b.getPrice();
                bottomPrice = a.getPrice();
            } else {
                // dois topos seguidos ou dois fundos seguidos → não formam um par topo–fundo ou fundo–topo
                continue;
            }

            double mid = (topPrice + bottomPrice) / 2.0;
            int lastIdx = Math.max(a.getIndex(), b.getIndex());

            boolean mitigatedPair = false;
            for (int j = lastIdx + 1; j < candles.size(); j++) {
                Candle c = candles.get(j);

                boolean rompeMid = (c.getHigh() >= mid && c.getLow() <= mid);
                boolean rompeTopo = c.getHigh() > topPrice;
                boolean rompeFundo = c.getLow() < bottomPrice;

                if (rompeMid || rompeTopo || rompeFundo) {
                    mitigatedPair = true;
                    break;
                }
            }

            if (mitigatedPair) {
                a.setMitigated(true);
                b.setMitigated(true);
            }
        }

        // ✅ Só devolve os níveis que nunca foram mitigados em nenhum par
        return pivots.stream()
                .filter(l -> !l.isMitigated())
                .collect(Collectors.toList());
    }

    /**
     * Detecta pivôs simples:
     * - topo: high[i] > high[i-1] e high[i] > high[i+1]
     * - fundo: low[i] < low[i-1] e low[i] < low[i+1]
     */

    private List<Level> detectSwings(List<Candle> candles) {
        List<Level> levels = new ArrayList<>();
        for (int i = 1; i < candles.size() - 1; i++) {
            Candle prev = candles.get(i - 1);
            Candle curr = candles.get(i);
            Candle next = candles.get(i + 1);

            if (curr.getHigh() > prev.getHigh() && curr.getHigh() > next.getHigh()) {
                levels.add(new Level(i, curr.getHigh(), LevelType.HIGH));
            } else if (curr.getLow() < prev.getLow() && curr.getLow() < next.getLow()) {
                levels.add(new Level(i, curr.getLow(), LevelType.LOW));
            }
        }
        return levels;
    }
   
}