Subversion Repositories Integrator Subversion

Rev

Rev 764 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

package br.com.sl.domain.service.impl;

import java.math.BigDecimal;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Singleton;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.itextpdf.text.log.SysoLogger;

import br.com.ec.core.generic.AbstractService;
import br.com.ec.core.generic.GenericRepository;
import br.com.ec.core.validador.Validador;
import br.com.sl.core.ExcelProfitDataProvider;
import br.com.sl.core.ExcelProfitTempoRealPorSegundoProvider;
import br.com.sl.core.ProfitDataProvider;
import br.com.sl.domain.dto.RoboDTO;
import br.com.sl.domain.dto.robo.CandleState;
import br.com.sl.domain.dto.robo.ProfitTick;
import br.com.sl.domain.service.CandleService;
import br.com.sl.domain.service.RoboColetorService;

@Singleton
@Service
public class RoboColetorServiceImpl extends AbstractService<RoboDTO> implements RoboColetorService {

        private final AtomicBoolean rodando = new AtomicBoolean(false);
       
        private RoboDTO roboDTO = new RoboDTO();
       
        private CandleService candleService;
       
        private ProfitDataProvider profitDataProvider;
       
        // estado de candle por ativo
    private final Map<String, CandleState> estados = new ConcurrentHashMap<>();

    // config básica (pode ser lido de properties)
    private static final String EXCEL_PATH = "C:/trade/temporeal.xlsx";
    private static final String EXCEL_SHEET = "Asset";
       
        @Autowired
        public RoboColetorServiceImpl(CandleService candleService, Validador validador) {
                super(validador);
                this.candleService = candleService;
        }

        @Override
        protected GenericRepository<RoboDTO> getRepository() {
                return null;
        }
       
        public RoboDTO getRoboDTO() {
                return roboDTO;
        }
        public void setRoboDTO(RoboDTO roboDTO) {
                this.roboDTO = roboDTO;
        }
       
        @Override
        public void iniciarColetor1Minuto() {
                RoboDTO roboDTO = new RoboDTO();
                roboDTO.setRodando(true);
                setRoboDTO(roboDTO);
               
                /*
                this.profitDataProvider = new ExcelProfitTempoRealPorSegundoProvider(Paths.get(EXCEL_PATH), EXCEL_SHEET);
        if (!rodando.compareAndSet(false, true)) {
            // já está rodando
            return;
        }
        */


        Thread t = new Thread(this::loopColetor, "CandleCollector-1M");
        t.setDaemon(true);
        t.start();
    }
       
        private void loopColetor() {
                System.out.println("INICIANDO COLETOR DE DADOS...");
                getRoboDTO().setObservacaoRobo("INICIANDO COLETOR DE DADOS...");
               
                /*
                try {
                        // INICIA NO PRIMEIRO SEGUNDO DO PRÓXIMO MINUTO HH:mm:01
                        LocalDateTime agora = LocalDateTime.now();
                        LocalDateTime proximoMinuto = agora
                                        .truncatedTo(ChronoUnit.MINUTES)
                                        .plusMinutes(1)
                                        .plusSeconds(1);
                       
                        long millisAteProximaExecucao = Duration.between(agora, proximoMinuto).toMillis();
                        if (millisAteProximaExecucao > 0) {
                                System.out.println("AGUARDANDO PARA INICIAR NO PRÓXIMO MINUTO");
                                getRoboDTO().setObservacaoRobo("AGUARDANDO PARA INICIAR NO PRÓXIMO MINUTO");
                                Thread.sleep(millisAteProximaExecucao);
                        }
                       
                } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                */

               
                System.out.println("INICIANDO CAPTURA!");
                getRoboDTO().setObservacaoRobo("INICIANDO CAPTURA!");
               
        while (rodando.get()) {
            try {
                /*
                // Lê ticks atuais de TODOS os ativos (snapshot)
                Map<String, ProfitTick> ticks = profitDataProvider.readCurrentTicks();

                // Atualiza estado de cada ativo
                for (Map.Entry<String, ProfitTick> entry : ticks.entrySet()) {
                    String symbol = entry.getKey();
                    ProfitTick tick = entry.getValue();
                    processarTick(symbol, tick);
                }
        */

                // Espera 1 segundo antes da próxima leitura
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        System.out.println("CAPTURA FINALIZADA!");
        getRoboDTO().setObservacaoRobo("CAPTURA FINALIZADA!");
    }

        private void processarTick(String ativo, ProfitTick tick) {
        CandleState situacaoCandle = estados.get(ativo);
        LocalDateTime tickTime = tick.getDateTime();

        // Evita processar o mesmo tick de novo (mesma data/hora)
        if (situacaoCandle != null && situacaoCandle.getLastTickTime() != null
                && tickTime.equals(situacaoCandle.getLastTickTime())) {
            return;
        }

        LocalDateTime minutoTick = tickTime.truncatedTo(ChronoUnit.MINUTES);
        BigDecimal preco = tick.getPrice();
       
        System.out.println("CAPTURANDO: " + preco + " [" + tickTime + "]");

        if (situacaoCandle == null) {
            // Primeiro tick desse ativo
                situacaoCandle = new CandleState(minutoTick, preco, tickTime);
            estados.put(ativo, situacaoCandle);
            return;
        }

        // Se o minuto mudou → fecha candle anterior e salva no banco
        if (!minutoTick.equals(situacaoCandle.getMinutoAtual())) {
            LocalDateTime inicioCandle = situacaoCandle.getMinutoAtual();
            LocalDateTime fimCandle = inicioCandle.plusMinutes(1);

            candleService.cadastrar(ativo, inicioCandle, fimCandle, situacaoCandle);

            // Inicia o próximo candle (novo minuto) com o tick atual
            situacaoCandle = new CandleState(minutoTick, preco, tickTime);
        } else {
                System.out.println("PREÇO: " + preco + " [" + tickTime + "]");
               
            // Ainda dentro do mesmo minuto → atualiza OHLC
            if (preco.compareTo(situacaoCandle.getMaxima()) > 0) {
                situacaoCandle.setMaxima(preco);
            }
            if (preco.compareTo(situacaoCandle.getMinima()) < 0) {
                situacaoCandle.setMinima(preco);
            }
            situacaoCandle.setFechamento(preco);
            situacaoCandle.setLastTickTime(tickTime);
            // volume se tiver → state.volume += ...
        }
    }

        @Override
        public void pararColetor() {
        rodando.set(false);
    }

        @Override
        public Boolean isRodando() {
                return rodando.get();
        }

        @Override
        public RoboDTO statusRobo() {
                getRoboDTO().setRodando(isRodando());
                return getRoboDTO();
        }
   
}