Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
795 blopes 1
package br.com.kronus.binance.robos;
2
 
3
import java.io.BufferedReader;
4
import java.io.BufferedWriter;
5
import java.io.IOException;
6
import java.math.BigDecimal;
7
import java.nio.charset.StandardCharsets;
8
import java.nio.file.Files;
9
import java.nio.file.Path;
10
import java.nio.file.Paths;
11
import java.nio.file.StandardOpenOption;
12
import java.time.LocalDate;
13
import java.time.LocalDateTime;
14
import java.time.LocalTime;
15
import java.time.ZoneId;
16
import java.time.format.DateTimeFormatter;
17
import java.util.ArrayList;
18
import java.util.Comparator;
19
import java.util.Date;
20
import java.util.HashSet;
21
import java.util.List;
22
import java.util.Set;
23
import java.util.concurrent.Executors;
24
import java.util.concurrent.ScheduledExecutorService;
25
import java.util.concurrent.TimeUnit;
26
 
27
import br.com.kronus.core.Candle;
28
import br.com.kronus.core.DetectorGatilhos;
29
import br.com.kronus.core.EstrategiaGatilhoTipo3Sinais;
30
import br.com.kronus.core.PadraoGatilho;
31
import br.com.kronus.core.SinalTradeGatilho3;
32
import br.com.kronus.core.TipoPeriodoCandle;
33
 
34
/**
35
 * RoboSinaisMain:
36
 *
37
 * - Monitora o arquivo BTCUSDT_1m.csv
38
 * - A cada 2 segundos verifica se foi modificado
39
 * - Se houve modificação:
40
 *      * Carrega TODOS os candles do arquivo
41
 *      * Identifica padrões e gera sinais (DetectorGatilhos + Estratégia)
42
 *      * Grava os sinais em SINAIS.csv com status 'P' (Pendente)
43
 *      * Evita gravar sinais duplicados via ID de sinal
44
 *
45
 * Layout BTCUSDT_1m.csv:
46
 * BTCUSDT;30/11/2025;14:12:00;91390,2;91410,7;91390;91390;226,94;155
47
 * 0       1           2        3       4       5      6      7      8
48
 *
49
 * Layout SINAIS.csv (mesmo do RoboGatilhosSinaisMain):
50
 * ID;Ativo;Data;Hora;TipoOperacao;PrecoEntrada;StopLoss;TakeProfit;Quantidade;Status;ClientOrderId
51
 */
52
public class RoboSinaisMain {
53
 
54
    private static final String ARQUIVO_SINAIS   = "D:/Dropbox/BLP/INVESTIMENTOS/DAYTRADE/sinais/SINAIS.csv";
55
    private static final String ARQUIVO_CANDLES = "D:/Dropbox/BLP/INVESTIMENTOS/DAYTRADE/temporeal/BTCUSDT_5m.csv";
56
 
57
    private static final BigDecimal VALOR_ENTRADA = new BigDecimal(0.005);
58
 
59
    private final ZoneId zone = ZoneId.of("America/Maceio");
60
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
61
 
62
    // Data/hora para candles (arquivo BTCUSDT_1m.csv)
63
    private final DateTimeFormatter fmtDataCandle = DateTimeFormatter.ofPattern("dd/MM/yyyy");
64
    private final DateTimeFormatter fmtHoraCandle = DateTimeFormatter.ofPattern("HH:mm:ss");
65
 
66
    // Data/hora para sinais (arquivo SINAIS.csv)
67
    private final DateTimeFormatter fmtDataSinal = DateTimeFormatter.ofPattern("dd/MM/yyyy");
68
    private final DateTimeFormatter fmtHoraSinal = DateTimeFormatter.ofPattern("HH:mm:ss");
69
 
70
    // Controle de modificação do arquivo de candles
71
    private long ultimaModificacaoCandles = 0L;
72
 
73
    // IDs de sinais já gravados no arquivo SINAIS.csv (para evitar duplicidade)
74
    private final Set<String> idsSinaisGravados = new HashSet<>();
75
 
76
    // =====================================================================
77
    // MAIN
78
    // =====================================================================
79
    public static void main(String[] args) {
80
        try {
81
            RoboSinaisMain r = new RoboSinaisMain();
82
            r.iniciar();
83
 
84
            Runtime.getRuntime().addShutdownHook(new Thread(r::parar));
85
        } catch (Exception e) {
86
            e.printStackTrace();
87
        }
88
    }
89
 
90
    // =====================================================================
91
    // CONSTRUTOR / INÍCIO / FIM
92
    // =====================================================================
93
    public RoboSinaisMain() {
94
        System.out.println("[ROBO-SINAIS] Inicializando RoboSinaisMain...");
95
        carregarIdsSinaisExistentes();
96
    }
97
 
98
    public void iniciar() {
99
        System.out.println("[ROBO-SINAIS] Iniciando monitor de candles (BTCUSDT_1m) a cada 2 segundos...");
100
 
101
        scheduler.scheduleAtFixedRate(() -> {
102
            try {
103
                ciclo();
104
            } catch (Exception e) {
105
                e.printStackTrace();
106
            }
107
        }, 0, 2, TimeUnit.SECONDS);
108
    }
109
 
110
    public void parar() {
111
        System.out.println("[ROBO-SINAIS] Encerrando RoboSinaisMain.");
112
        scheduler.shutdownNow();
113
    }
114
 
115
    // =====================================================================
116
    // CICLO A CADA 2 SEGUNDOS
117
    // =====================================================================
118
    private void ciclo() {
119
        if (arquivoCandlesFoiModificado()) {
120
            System.out.println("[ROBO-SINAIS] BTCUSDT_1m.csv modificado. Recarregando candles e gerando sinais...");
121
 
122
            List<Candle> candles = carregarCandlesDoArquivo();
123
            if (candles.isEmpty()) {
124
                System.out.println("[ROBO-SINAIS] Nenhum candle carregado. Ignorando ciclo.");
125
                return;
126
            }
127
 
128
            // 1) Detector de padrões
129
            DetectorGatilhos detector = new DetectorGatilhos();
130
            List<PadraoGatilho> padroes = detector.identificarPadroes(candles);
131
 
132
            if (padroes == null || padroes.isEmpty()) {
133
                System.out.println("[ROBO-SINAIS] Nenhum padrão encontrado.");
134
                return;
135
            }
136
 
137
            System.out.println("[ROBO-SINAIS] Padrões encontrados: " + padroes.size());
138
 
139
            // 2) Estratégia para gerar sinais
140
            EstrategiaGatilhoTipo3Sinais estrategia = new EstrategiaGatilhoTipo3Sinais();
141
            List<SinalTradeGatilho3> sinais = estrategia.gerarSinais(padroes);
142
 
143
            if (sinais == null || sinais.isEmpty()) {
144
                System.out.println("[ROBO-SINAIS] Nenhum sinal gerado.");
145
                return;
146
            }
147
 
148
            // Ordena por data/hora de entrada DESC (mais recente primeiro)
149
            sinais.sort(Comparator.comparing(SinalTradeGatilho3::getDataHoraEntrada).reversed());
150
 
151
            System.out.println("[ROBO-SINAIS] Sinais gerados: " + sinais.size());
152
 
153
            // 3) Grava apenas os sinais ainda não registrados em SINAIS.csv
154
            gravarNovosSinais(sinais);
155
        }
156
    }
157
 
158
    private boolean arquivoCandlesFoiModificado() {
159
        try {
160
            Path path = Paths.get(ARQUIVO_CANDLES);
161
            if (!Files.exists(path)) {
162
                System.out.println("[ROBO-SINAIS] Arquivo de candles não encontrado: " + path.toAbsolutePath());
163
                return false;
164
            }
165
            long mod = Files.getLastModifiedTime(path).toMillis();
166
            if (mod > ultimaModificacaoCandles) {
167
                ultimaModificacaoCandles = mod;
168
                return true;
169
            }
170
        } catch (IOException e) {
171
            System.err.println("[ROBO-SINAIS] Erro ao verificar modificação do arquivo de candles: " + e.getMessage());
172
        }
173
        return false;
174
    }
175
 
176
    // =====================================================================
177
    // CARREGAR CANDLES DO ARQUIVO BTCUSDT_1m.csv
178
    // =====================================================================
179
    private List<Candle> carregarCandlesDoArquivo() {
180
        List<Candle> lista = new ArrayList<>();
181
        Path path = Paths.get(ARQUIVO_CANDLES);
182
 
183
        if (!Files.exists(path)) {
184
            System.out.println("[ROBO-SINAIS] Arquivo de candles não encontrado: " + path.toAbsolutePath());
185
            return lista;
186
        }
187
 
188
        try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
189
            String linha;
190
            boolean primeira = true;
191
            int contador = 0;
192
 
193
            while ((linha = reader.readLine()) != null) {
194
                if (primeira && linha.toLowerCase().contains("data")) {
195
                    primeira = false;
196
                    continue; // pula cabeçalho, se houver
197
                }
198
                primeira = false;
199
 
200
                if (linha.trim().isEmpty()) continue;
201
 
202
                Candle c = parseLinhaParaCandle(linha, contador);
203
                if (c != null) {
204
                    lista.add(c);
205
                    contador++;
206
                }
207
            }
208
 
209
            System.out.println("[ROBO-SINAIS] Candles carregados: " + lista.size());
210
 
211
        } catch (IOException e) {
212
            System.err.println("[ROBO-SINAIS] Erro ao ler arquivo de candles: " + e.getMessage());
213
            e.printStackTrace();
214
        }
215
 
216
        return lista;
217
    }
218
 
219
    /**
220
     * Formato BTCUSDT_1m.csv:
221
     * BTCUSDT;30/11/2025;14:12:00;91390,2;91410,7;91390;91390;226,94;155
222
     * 0       1           2        3       4       5      6      7      8
223
     */
224
    private Candle parseLinhaParaCandle(String linha, int contadorCandle) {
225
        try {
226
            String[] p = linha.split(";", -1);
227
            if (p.length < 7) {
228
                System.out.println("[ROBO-SINAIS] Linha inválida em BTCUSDT_1m: " + linha);
229
                return null;
230
            }
231
 
232
            String ativo = p[0].trim();
233
 
234
            LocalDate data = LocalDate.parse(p[1].trim(), fmtDataCandle);
235
            LocalTime hora = LocalTime.parse(p[2].trim(), fmtHoraCandle);
236
            LocalDateTime dt = LocalDateTime.of(data, hora);
237
 
238
            BigDecimal abertura   = parseBigDecimal(p[3]);
239
            BigDecimal maxima     = parseBigDecimal(p[4]);
240
            BigDecimal minima     = parseBigDecimal(p[5]);
241
            BigDecimal fechamento = parseBigDecimal(p[6]);
242
            BigDecimal volume     = (p.length > 7) ? parseBigDecimal(p[7]) : BigDecimal.ZERO;
243
 
244
            Candle c = new Candle(
245
                    contadorCandle,
246
                    ativo,
247
                    dt,
248
                    abertura,
249
                    maxima,
250
                    minima,
251
                    fechamento,
252
                    TipoPeriodoCandle.M1.getValor()
253
            );
254
            c.setVolume(volume);
255
 
256
            return c;
257
 
258
        } catch (Exception e) {
259
            System.out.println("[ROBO-SINAIS] Erro ao parsear linha de candle: " + linha);
260
            e.printStackTrace();
261
            return null;
262
        }
263
    }
264
 
265
    // =====================================================================
266
    // GRAVAÇÃO DE SINAIS EM SINAIS.csv (STATUS = P)
267
    // =====================================================================
268
    private void gravarNovosSinais(List<SinalTradeGatilho3> sinais) {
269
        if (sinais == null || sinais.isEmpty()) {
270
            return;
271
        }
272
 
273
        Path path = Paths.get(ARQUIVO_SINAIS);
274
        boolean novoArquivo = !Files.exists(path);
275
 
276
        try {
277
            if (path.getParent() != null && !Files.exists(path.getParent())) {
278
                Files.createDirectories(path.getParent());
279
            }
280
 
281
            try (BufferedWriter writer = Files.newBufferedWriter(
282
                    path,
283
                    StandardCharsets.UTF_8,
284
                    StandardOpenOption.CREATE,
285
                    StandardOpenOption.APPEND)
286
            ) {
287
                // Cabeçalho se arquivo recém-criado
288
                if (novoArquivo) {
289
                    writer.write("ID;Ativo;Data;Hora;TipoOperacao;PrecoEntrada;StopLoss;TakeProfit;Quantidade;Status;ClientOrderId");
290
                    writer.newLine();
291
                }
292
 
293
                int novos = 0;
294
 
295
                for (SinalTradeGatilho3 s : sinais) {
296
                    if (s == null) continue;
297
                    if (s.getDataHoraEntrada() == null) continue;
298
 
299
                    String id = gerarIdSinal(s);
300
 
301
                    // Evita duplicidade
302
                    if (idsSinaisGravados.contains(id)) {
303
                        continue;
304
                    }
305
 
306
                    idsSinaisGravados.add(id);
307
 
308
                    // ==== Mapear campos ====
309
                    String ativo = s.getIdAtivo(); // AJUSTE AQUI se o getter tiver outro nome
310
                    if (ativo == null || ativo.trim().isEmpty()) {
311
                        ativo = "BTCUSDT";
312
                    }
313
 
314
                    Date dataHora = s.getDataHoraEntrada();
315
                    if (dataHora == null) {
316
                        return; // ou continue; dependendo do contexto
317
                    }
318
 
319
                    LocalDateTime dt = LocalDateTime.ofInstant(dataHora.toInstant(), zone);  // use o ZoneId que você já tem na classe
320
                    String data = dt.toLocalDate().format(fmtDataSinal);
321
                    String hora = dt.toLocalTime().format(fmtHoraSinal);
322
 
323
 
324
                    String tipoOperacao = (s.getTipoOperacao() != null)? s.getTipoOperacao().getValor() : "";
325
 
326
                    BigDecimal precoEntrada = s.getPrecoEntrada1();
327
                    BigDecimal stopLoss     = s.getStopMenos100();
328
                    BigDecimal takeProfit   = s.getAlvo2();
329
                    BigDecimal quantidade   = VALOR_ENTRADA; // AJUSTE se usar outro nome (ex.: getContratos)
330
 
331
                    String precoEntradaStr = toStr(precoEntrada);
332
                    String stopLossStr     = toStr(stopLoss);
333
                    String takeProfitStr   = toStr(takeProfit);
334
                    String quantidadeStr   = toStr(quantidade);
335
 
336
                    String status = "P";         // sempre pendente ao gravar
337
                    String clientOrderId = "";   // ainda não enviado pra Binance
338
 
339
                    String linha = id + ";" +
340
                            ativo + ";" +
341
                            data + ";" +
342
                            hora + ";" +
343
                            tipoOperacao + ";" +
344
                            precoEntradaStr + ";" +
345
                            stopLossStr + ";" +
346
                            takeProfitStr + ";" +
347
                            quantidadeStr + ";" +
348
                            status + ";" +
349
                            clientOrderId;
350
 
351
                    writer.write(linha);
352
                    writer.newLine();
353
                    novos++;
354
                }
355
 
356
                System.out.println("[ROBO-SINAIS] Novos sinais gravados: " + novos);
357
 
358
            }
359
 
360
        } catch (IOException e) {
361
            System.err.println("[ROBO-SINAIS] Erro ao gravar SINAIS.csv: " + e.getMessage());
362
            e.printStackTrace();
363
        }
364
    }
365
 
366
    /**
367
     * Gera um ID único para o sinal, baseado em:
368
     *  Ativo + DataHoraEntrada + TipoOperacao + PrecoEntrada
369
     *
370
     * Isso garante que, se o mesmo sinal for recalculado depois,
371
     * não será gravado novamente.
372
     */
373
    private String gerarIdSinal(SinalTradeGatilho3 s) {
374
        String ativo = s.getIdAtivo();
375
        if (ativo == null || ativo.trim().isEmpty()) {
376
            ativo = "BTCUSDT";
377
        }
378
 
379
        Date dataHora = s.getDataHoraEntrada();
380
        LocalDateTime dt = LocalDateTime.ofInstant(
381
                dataHora.toInstant(),
382
                zone
383
        );
384
 
385
        String tipo = (s.getTipoOperacao() != null) ? s.getTipoOperacao().getValor() : "";
386
        String preco = (s.getAlvo1() != null)? s.getAlvo1().toPlainString(): "0";
387
 
388
        return ativo + "_" + dt.toString() + "_" + tipo + "_" + preco;
389
    }
390
 
391
 
392
    // =====================================================================
393
    // CARREGAR IDs JÁ EXISTENTES EM SINAIS.csv (para não duplicar)
394
    // =====================================================================
395
    private void carregarIdsSinaisExistentes() {
396
        Path path = Paths.get(ARQUIVO_SINAIS);
397
        if (!Files.exists(path)) {
398
            return;
399
        }
400
 
401
        try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
402
            String linha;
403
            boolean primeira = true;
404
 
405
            while ((linha = reader.readLine()) != null) {
406
                if (primeira) {
407
                    primeira = false;
408
                    continue; // cabeçalho
409
                }
410
                if (linha.trim().isEmpty()) continue;
411
 
412
                String[] p = linha.split(";", -1);
413
                if (p.length < 1) continue;
414
 
415
                String id = p[0].trim();
416
                if (!id.isEmpty()) {
417
                    idsSinaisGravados.add(id);
418
                }
419
            }
420
 
421
            System.out.println("[ROBO-SINAIS] IDs de sinais existentes carregados: " + idsSinaisGravados.size());
422
 
423
        } catch (IOException e) {
424
            System.err.println("[ROBO-SINAIS] Erro ao carregar IDs de SINAIS.csv: " + e.getMessage());
425
            e.printStackTrace();
426
        }
427
    }
428
 
429
    // =====================================================================
430
    // UTILS
431
    // =====================================================================
432
    private BigDecimal parseBigDecimal(String s) {
433
        if (s == null) return BigDecimal.ZERO;
434
        s = s.trim();
435
        if (s.isEmpty()) return BigDecimal.ZERO;
436
        return new BigDecimal(s.replace(",", "."));
437
    }
438
 
439
    private String toStr(BigDecimal v) {
440
        if (v == null) return "";
441
        return v.toPlainString().replace(".", ",");
442
    }
443
}