Subversion Repositories Integrator Subversion

Rev

Rev 762 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
761 blopes 1
package br.com.sl.domain.service.impl;
2
 
3
import java.math.BigDecimal;
4
import java.nio.file.Paths;
764 blopes 5
import java.time.Duration;
761 blopes 6
import java.time.LocalDateTime;
7
import java.time.temporal.ChronoUnit;
8
import java.util.Map;
9
import java.util.concurrent.ConcurrentHashMap;
10
import java.util.concurrent.TimeUnit;
11
import java.util.concurrent.atomic.AtomicBoolean;
12
 
13
import javax.inject.Singleton;
14
 
15
import org.springframework.beans.factory.annotation.Autowired;
16
import org.springframework.stereotype.Service;
17
 
764 blopes 18
import com.itextpdf.text.log.SysoLogger;
19
 
761 blopes 20
import br.com.ec.core.generic.AbstractService;
21
import br.com.ec.core.generic.GenericRepository;
22
import br.com.ec.core.validador.Validador;
23
import br.com.sl.core.ExcelProfitDataProvider;
764 blopes 24
import br.com.sl.core.ExcelProfitTempoRealPorSegundoProvider;
761 blopes 25
import br.com.sl.core.ProfitDataProvider;
26
import br.com.sl.domain.dto.RoboDTO;
27
import br.com.sl.domain.dto.robo.CandleState;
28
import br.com.sl.domain.dto.robo.ProfitTick;
29
import br.com.sl.domain.service.CandleService;
30
import br.com.sl.domain.service.RoboColetorService;
31
 
32
@Singleton
33
@Service
34
public class RoboColetorServiceImpl extends AbstractService<RoboDTO> implements RoboColetorService {
35
 
36
        private final AtomicBoolean rodando = new AtomicBoolean(false);
37
 
762 blopes 38
        private RoboDTO roboDTO = new RoboDTO();
761 blopes 39
 
40
        private CandleService candleService;
41
 
42
        private ProfitDataProvider profitDataProvider;
43
 
44
        // estado de candle por ativo
45
    private final Map<String, CandleState> estados = new ConcurrentHashMap<>();
46
 
47
    // config básica (pode ser lido de properties)
48
    private static final String EXCEL_PATH = "C:/trade/temporeal.xlsx";
49
    private static final String EXCEL_SHEET = "Asset";
50
 
51
        @Autowired
52
        public RoboColetorServiceImpl(CandleService candleService, Validador validador) {
53
                super(validador);
54
                this.candleService = candleService;
55
        }
56
 
57
        @Override
58
        protected GenericRepository<RoboDTO> getRepository() {
59
                return null;
60
        }
61
 
62
        public RoboDTO getRoboDTO() {
63
                return roboDTO;
64
        }
65
        public void setRoboDTO(RoboDTO roboDTO) {
66
                this.roboDTO = roboDTO;
67
        }
68
 
69
        @Override
70
        public void iniciarColetor1Minuto() {
71
                RoboDTO roboDTO = new RoboDTO();
72
                roboDTO.setRodando(true);
73
                setRoboDTO(roboDTO);
74
 
764 blopes 75
                this.profitDataProvider = new ExcelProfitTempoRealPorSegundoProvider(Paths.get(EXCEL_PATH), EXCEL_SHEET);
761 blopes 76
        if (!rodando.compareAndSet(false, true)) {
77
            // já está rodando
78
            return;
79
        }
80
 
81
        Thread t = new Thread(this::loopColetor, "CandleCollector-1M");
82
        t.setDaemon(true);
83
        t.start();
84
    }
85
 
86
        private void loopColetor() {
764 blopes 87
                System.out.println("INICIANDO COLETOR DE DADOS...");
88
                getRoboDTO().setObservacaoRobo("INICIANDO COLETOR DE DADOS...");
89
 
90
                /*
91
                try {
92
                        // INICIA NO PRIMEIRO SEGUNDO DO PRÓXIMO MINUTO HH:mm:01
93
                        LocalDateTime agora = LocalDateTime.now();
94
                        LocalDateTime proximoMinuto = agora
95
                                        .truncatedTo(ChronoUnit.MINUTES)
96
                                        .plusMinutes(1)
97
                                        .plusSeconds(1);
98
 
99
                        long millisAteProximaExecucao = Duration.between(agora, proximoMinuto).toMillis();
100
                        if (millisAteProximaExecucao > 0) {
101
                                System.out.println("AGUARDANDO PARA INICIAR NO PRÓXIMO MINUTO");
102
                                getRoboDTO().setObservacaoRobo("AGUARDANDO PARA INICIAR NO PRÓXIMO MINUTO");
103
                                Thread.sleep(millisAteProximaExecucao);
104
                        }
105
 
106
                } catch (InterruptedException e) {
107
                        // TODO Auto-generated catch block
108
                        e.printStackTrace();
109
                }
110
                */
111
 
112
                System.out.println("INICIANDO CAPTURA!");
113
                getRoboDTO().setObservacaoRobo("INICIANDO CAPTURA!");
114
 
761 blopes 115
        while (rodando.get()) {
116
            try {
117
                // Lê ticks atuais de TODOS os ativos (snapshot)
118
                Map<String, ProfitTick> ticks = profitDataProvider.readCurrentTicks();
119
 
120
                // Atualiza estado de cada ativo
121
                for (Map.Entry<String, ProfitTick> entry : ticks.entrySet()) {
122
                    String symbol = entry.getKey();
123
                    ProfitTick tick = entry.getValue();
124
                    processarTick(symbol, tick);
125
                }
126
 
127
                // Espera 1 segundo antes da próxima leitura
764 blopes 128
                TimeUnit.SECONDS.sleep(1);
761 blopes 129
            } catch (Exception e) {
130
                e.printStackTrace();
131
                try {
132
                    TimeUnit.SECONDS.sleep(1);
133
                } catch (InterruptedException ex) {
134
                    Thread.currentThread().interrupt();
135
                }
136
            }
137
        }
764 blopes 138
        System.out.println("CAPTURA FINALIZADA!");
139
        getRoboDTO().setObservacaoRobo("CAPTURA FINALIZADA!");
761 blopes 140
    }
141
 
142
        private void processarTick(String ativo, ProfitTick tick) {
143
        CandleState situacaoCandle = estados.get(ativo);
144
        LocalDateTime tickTime = tick.getDateTime();
145
 
146
        // Evita processar o mesmo tick de novo (mesma data/hora)
147
        if (situacaoCandle != null && situacaoCandle.getLastTickTime() != null
148
                && tickTime.equals(situacaoCandle.getLastTickTime())) {
149
            return;
150
        }
151
 
152
        LocalDateTime minutoTick = tickTime.truncatedTo(ChronoUnit.MINUTES);
153
        BigDecimal preco = tick.getPrice();
764 blopes 154
 
155
        System.out.println("CAPTURANDO: " + preco + " [" + tickTime + "]");
761 blopes 156
 
157
        if (situacaoCandle == null) {
158
            // Primeiro tick desse ativo
159
                situacaoCandle = new CandleState(minutoTick, preco, tickTime);
160
            estados.put(ativo, situacaoCandle);
161
            return;
162
        }
163
 
164
        // Se o minuto mudou → fecha candle anterior e salva no banco
165
        if (!minutoTick.equals(situacaoCandle.getMinutoAtual())) {
166
            LocalDateTime inicioCandle = situacaoCandle.getMinutoAtual();
167
            LocalDateTime fimCandle = inicioCandle.plusMinutes(1);
168
 
169
            candleService.cadastrar(ativo, inicioCandle, fimCandle, situacaoCandle);
170
 
171
            // Inicia o próximo candle (novo minuto) com o tick atual
172
            situacaoCandle = new CandleState(minutoTick, preco, tickTime);
173
        } else {
764 blopes 174
                System.out.println("PREÇO: " + preco + " [" + tickTime + "]");
175
 
761 blopes 176
            // Ainda dentro do mesmo minuto → atualiza OHLC
177
            if (preco.compareTo(situacaoCandle.getMaxima()) > 0) {
178
                situacaoCandle.setMaxima(preco);
179
            }
180
            if (preco.compareTo(situacaoCandle.getMinima()) < 0) {
181
                situacaoCandle.setMinima(preco);
182
            }
183
            situacaoCandle.setFechamento(preco);
184
            situacaoCandle.setLastTickTime(tickTime);
185
            // volume se tiver → state.volume += ...
186
        }
187
    }
188
 
189
        @Override
190
        public void pararColetor() {
191
        rodando.set(false);
192
    }
193
 
194
        @Override
195
        public Boolean isRodando() {
196
                return rodando.get();
197
        }
198
 
199
        @Override
200
        public RoboDTO statusRobo() {
201
                getRoboDTO().setRodando(isRodando());
202
                return getRoboDTO();
203
        }
204
 
205
}