Subversion Repositories Integrator Subversion

Rev

Rev 783 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
760 blopes 1
package br.com.sl.core;
2
 
785 blopes 3
import java.io.BufferedReader;
760 blopes 4
import java.io.FileInputStream;
5
import java.io.IOException;
6
import java.math.BigDecimal;
785 blopes 7
import java.nio.charset.StandardCharsets;
779 blopes 8
import java.nio.file.Files;
760 blopes 9
import java.nio.file.Path;
10
import java.time.LocalDate;
11
import java.time.LocalDateTime;
12
import java.time.LocalTime;
13
import java.time.format.DateTimeFormatter;
764 blopes 14
import java.util.ArrayList;
15
import java.util.Collections;
782 blopes 16
import java.util.HashMap;
761 blopes 17
import java.util.List;
764 blopes 18
import java.util.Locale;
760 blopes 19
import java.util.Map;
779 blopes 20
import java.util.stream.Stream;
760 blopes 21
 
764 blopes 22
import org.apache.poi.EncryptedDocumentException;
760 blopes 23
import org.apache.poi.ss.usermodel.Cell;
24
import org.apache.poi.ss.usermodel.Row;
25
import org.apache.poi.ss.usermodel.Sheet;
26
import org.apache.poi.ss.usermodel.Workbook;
27
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
28
 
782 blopes 29
import br.com.ec.core.util.VerificadorUtil;
764 blopes 30
import br.com.kronus.core.Timeframe;
760 blopes 31
import br.com.sl.domain.dto.robo.ProfitTick;
761 blopes 32
import br.com.sl.domain.model.Candle;
764 blopes 33
import br.com.sl.domain.model.tipos.TipoPeriodoCandle;
785 blopes 34
import br.com.sl.domain.util.BigDecimalUtils;
767 blopes 35
import br.com.sl.shared.ExcelDataUtils;
760 blopes 36
 
37
public class ExcelProfitDataProvider implements ProfitDataProvider {
38
 
764 blopes 39
        private final Path excelFile;
760 blopes 40
    private final String sheetName;
41
 
42
    // índices de coluna (0 = A, 1 = B, etc.)
43
    private final int colAsset = 0;
44
    private final int colDate  = 1;
45
    private final int colTime  = 2;
46
    private final int colLast  = 3;
47
 
785 blopes 48
    private static final DateTimeFormatter DATE_FORMAT_CSV = DateTimeFormatter.ofPattern("dd/MM/yyyy");
49
    private static final DateTimeFormatter TIME_FORMAT_CSV = DateTimeFormatter.ofPattern("HH:mm:ss");
50
 
779 blopes 51
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
52
    private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
760 blopes 53
 
54
    public ExcelProfitDataProvider(Path excelFile, String sheetName) {
55
        this.excelFile = excelFile;
56
        this.sheetName = sheetName;
57
    }
764 blopes 58
 
59
    /**
779 blopes 60
     * Lê um ou vários arquivos:
61
     * - Se excelFile for um arquivo: lê apenas esse arquivo (.xlsx, .xls ou .csv)
62
     * - Se excelFile for uma pasta: lê todos os .xlsx, .xls e .csv da pasta.
764 blopes 63
     */
64
    public List<Candle> lerCandles() throws IOException {
65
        List<Candle> candles = new ArrayList<>();
760 blopes 66
 
779 blopes 67
        if (Files.isDirectory(excelFile)) {
68
            // Percorre todos os arquivos da pasta
69
            try (Stream<Path> stream = Files.list(excelFile)) {
70
                stream
71
                    .filter(Files::isRegularFile)
72
                    .filter(p -> {
73
                        String name = p.getFileName().toString().toLowerCase(Locale.ROOT);
74
                        return name.endsWith(".xlsm") || name.endsWith(".xlsx") || name.endsWith(".xls") || name.endsWith(".csv");
75
                    })
76
                    .forEach(path -> {
77
                        try {
78
                            lerCandlesDeArquivo(path, candles);
79
                        } catch (IOException e) {
80
                            // aqui você pode trocar por log
81
                            e.printStackTrace();
82
                        }
83
                    });
84
            }
85
        } else {
86
            // Apenas um arquivo
87
            lerCandlesDeArquivo(excelFile, candles);
88
        }
89
 
90
        return adicionarContadores(candles);
91
    }
92
 
93
    /**
94
     * Decide se o arquivo é Excel ou CSV e delega para o método correto.
95
     */
96
    private void lerCandlesDeArquivo(Path arquivo, List<Candle> candles) throws IOException {
97
        String name = arquivo.getFileName().toString().toLowerCase(Locale.ROOT);
98
 
99
        if (name.endsWith(".xlsm") || name.endsWith(".xlsx") || name.endsWith(".xls")) {
100
            lerCandlesDeArquivoExcel(arquivo, candles);
101
        } else if (name.endsWith(".csv")) {
785 blopes 102
            lerCandlesDeArquivoCsv(arquivo, candles);
779 blopes 103
        } else {
104
            // Tipo não suportado, ignora ou loga
105
        }
106
    }
107
 
108
    /**
109
     * Lê os candles de UM arquivo Excel e adiciona na lista passada.
110
     * (É basicamente o seu código original, só movido para cá)
111
     */
112
    private void lerCandlesDeArquivoExcel(Path arquivoExcel, List<Candle> candles) throws IOException {
113
        try (FileInputStream fis = new FileInputStream(arquivoExcel.toFile());
114
             Workbook workbook = new XSSFWorkbook(fis)) {
115
 
764 blopes 116
            int numberOfSheets = workbook.getNumberOfSheets();
779 blopes 117
 
118
            // LER APENAS OS ATIVOS
119
            List<String> ativos = new ArrayList<String>();
764 blopes 120
            for (int i = 0; i < numberOfSheets; i++) {
121
                Sheet sheet = workbook.getSheetAt(i);
122
                if (sheet.getSheetName().equals(sheetName)) {
123
                        boolean firstRow = true;
124
 
125
                        for (Row row : sheet) {
126
                            if (firstRow) {
127
                                firstRow = false; // pula o cabeçalho
128
                                continue;
129
                            }
130
 
782 blopes 131
                            Cell ativoCell = row.getCell(1);
132
                            if (VerificadorUtil.naoEstaNulo(ativoCell)) {
133
                                String ativoString = ativoCell.getStringCellValue();
134
                                if (VerificadorUtil.naoEstaNuloOuVazio(ativoString)) {
135
                                        if (!ativos.contains(ativoString)) {
136
                                                ativos.add(ativoString);
137
                                        }
138
                                }
764 blopes 139
                            }
140
                        }
760 blopes 141
                }
142
            }
779 blopes 143
 
144
            for (String ativo : ativos) {
145
                    for (int i = 0; i < numberOfSheets; i++) {
146
                        Sheet sheet = workbook.getSheetAt(i);
147
                        if (sheet.getSheetName().equals(sheetName)) {
148
                                boolean firstRow = true;
149
 
150
                                for (Row row : sheet) {
151
                                    if (firstRow) {
152
                                        firstRow = false; // pula o cabeçalho
153
                                        continue;
154
                                    }
155
 
156
                                    // 0 = Contador
157
                                    // 1 = Ativo
158
                                    // 2 = Dia
159
                                    // 3 = Hora
160
                                    // 4 = Abertura
161
                                    // 5 = Máxima
162
                                    // 6 = Mínima
163
                                    // 7 = Fechamento
164
 
165
                                    Cell contadorCell   = row.getCell(0);
166
                                    Cell ativoCell      = row.getCell(1);
167
                                    Cell dataCell       = row.getCell(2);
168
                                    Cell horaCell       = row.getCell(3);
169
                                    Cell aberturaCell   = row.getCell(4);
170
                                    Cell maximaCell     = row.getCell(5);
171
                                    Cell minimaCell     = row.getCell(6);
172
                                    Cell fechamentoCell = row.getCell(7);
173
                                    Cell finalizadoCell = row.getCell(8);
174
 
175
                                    if (!ExcelDataUtils.isNumeric(aberturaCell) || !ExcelDataUtils.isNumeric(maximaCell)
782 blopes 176
                                                || !ExcelDataUtils.isNumeric(minimaCell) || !ExcelDataUtils.isNumeric(fechamentoCell)) {
779 blopes 177
                                        continue;
178
                                    }
179
 
782 blopes 180
                                    String ativoDescricao = ativoCell.getStringCellValue();
181
                                    if (!ativo.equals(ativoDescricao)) {
182
                                        continue;
183
                                    }
184
 
779 blopes 185
                                    Integer contador = BigDecimal.valueOf(contadorCell.getNumericCellValue()).intValue();
186
 
187
                                    LocalDate data = ExcelDataUtils.lerData(dataCell);
188
                                    LocalTime hora = ExcelDataUtils.lerHora(horaCell);
189
                                    LocalDateTime dataHora = LocalDateTime.of(data, hora);
190
 
191
                                    BigDecimal abertura = BigDecimal.valueOf(aberturaCell.getNumericCellValue());
192
                                    BigDecimal topo = BigDecimal.valueOf(maximaCell.getNumericCellValue());
193
                                    BigDecimal fundo = BigDecimal.valueOf(minimaCell.getNumericCellValue());
194
                                    BigDecimal fechamento = BigDecimal.valueOf(fechamentoCell.getNumericCellValue());
195
 
196
                                    String finalizado = finalizadoCell.getStringCellValue();
197
                                    if (finalizado.equals("S")) {
198
                                        Candle candle = new Candle(contador, ativoDescricao, dataHora, abertura, topo, fundo, fechamento, TipoPeriodoCandle.M1.getValor());
199
                                        candles.add(candle);
200
                                    }
201
                                }
202
                        }
203
                    }
204
            }
764 blopes 205
        } catch (EncryptedDocumentException e) {
779 blopes 206
            e.printStackTrace();
207
        }
764 blopes 208
    }
209
 
779 blopes 210
    /**
211
     * Lê os candles de UM arquivo CSV e adiciona na lista passada.
212
     * Espera layout:
213
     * 0 = Ativo
214
     * 1 = Dia  (dd/MM/yyyy)
215
     * 2 = Hora (HH:mm:ss)
216
     * 3 = Abertura
217
     * 4 = Máxima
218
     * 5 = Mínima
219
     * 6 = Fechamento
220
     */
785 blopes 221
    private void lerCandlesDeArquivoCsv(Path arquivoCsv, List<Candle> candles) throws IOException {
222
        try (BufferedReader br = Files.newBufferedReader(arquivoCsv, StandardCharsets.UTF_8)) {
223
            String line;
224
            while ((line = br.readLine()) != null) {
225
 
226
                // Substitui line.isBlank() por trim().isEmpty()
227
                String trimmed = line.trim();
228
                if (trimmed.isEmpty()) {
229
                    continue;
230
                }
231
 
232
                // Ajuste aqui se o separador do seu CSV for vírgula
233
                String[] parts = trimmed.split(";", -1);
234
                if (parts.length < 7) {
235
                    continue;
236
                }
237
 
238
                String ativoDescricao = "";
239
                String dataStr        = "";
240
                String horaStr        = "";
241
                String aberturaStr    = "";
242
                String maximaStr      = "";
243
                String minimaStr      = "";
244
                String fechamentoStr  = "";
245
 
246
                ativoDescricao = parts[0].trim();
247
                dataStr        = parts[1].trim();
248
                if (parts.length >= 9) {
249
                        horaStr        = parts[2].trim();
250
                        aberturaStr    = parts[3].trim();
251
                        maximaStr      = parts[4].trim();
252
                        minimaStr      = parts[5].trim();
253
                        fechamentoStr  = parts[6].trim();
254
                } else {
255
                        horaStr        = "18:00:00";
256
                        aberturaStr    = parts[2].trim();
257
                        maximaStr      = parts[3].trim();
258
                        minimaStr      = parts[4].trim();
259
                        fechamentoStr  = parts[5].trim();
260
                }
261
 
262
                // Ignora header, caso exista
263
                if (ativoDescricao.equalsIgnoreCase("ativo")) {
264
                    continue;
265
                }
266
 
267
                if (!isNumericString(aberturaStr) ||
268
                    !isNumericString(maximaStr)   ||
269
                    !isNumericString(minimaStr)   ||
270
                    !isNumericString(fechamentoStr)) {
271
                    continue;
272
                }
273
 
274
                LocalDate data = LocalDate.parse(dataStr, DATE_FORMAT_CSV);
275
                LocalTime hora = LocalTime.parse(horaStr, TIME_FORMAT_CSV);
276
                LocalDateTime dataHora = LocalDateTime.of(data, hora);
277
 
278
                BigDecimal abertura   = BigDecimalUtils.converterStringEmBigDecimal(aberturaStr);
279
                BigDecimal topo       = BigDecimalUtils.converterStringEmBigDecimal(maximaStr);
280
                BigDecimal fundo      = BigDecimalUtils.converterStringEmBigDecimal(minimaStr);
281
                BigDecimal fechamento = BigDecimalUtils.converterStringEmBigDecimal(fechamentoStr);
282
 
283
                Candle candle = new Candle(
284
                        null,
285
                        ativoDescricao,
286
                        dataHora,
287
                        abertura,
288
                        topo,
289
                        fundo,
290
                        fechamento,
291
                        TipoPeriodoCandle.M1.getValor()
292
                );
293
                candles.add(candle);
294
            }
295
        }
779 blopes 296
 
785 blopes 297
 
298
    }
299
 
779 blopes 300
    private boolean isNumericString(String value) {
301
        if (value == null) return false;
302
        String normalized = value.trim().replace(".", "").replace(",", ".");
303
        if (normalized.isEmpty()) return false;
304
        try {
305
            new BigDecimal(normalized);
306
            return true;
307
        } catch (NumberFormatException e) {
308
            return false;
309
        }
310
    }
311
 
764 blopes 312
    public static List<Candle> inverterLista(List<Candle> candles) {
313
        List<Candle> invertida = new ArrayList<>(candles);
314
        Collections.reverse(invertida);
315
        return invertida;
316
    }
760 blopes 317
 
782 blopes 318
    // Contador separado para cada ativo iniciando pelo primeiro contador encontrado
764 blopes 319
    public static List<Candle> adicionarContadores(List<Candle> candles) {
782 blopes 320
        Map<String, Integer> contadorPorAtivo = new HashMap<>();
779 blopes 321
        List<Candle> comContadores = new ArrayList<>();
322
 
764 blopes 323
        for (Candle candle : candles) {
779 blopes 324
            String ativo = candle.getNomeAtivo();
325
 
782 blopes 326
            // Se for o primeiro candle do ativo, usar o contador original dele como ponto de partida
327
            if (!contadorPorAtivo.containsKey(ativo)) {
328
                int contadorInicial = candle.getContadorCandle() != null
329
                        ? candle.getContadorCandle()
330
                        : 1;  // fallback, se vier nulo
331
                contadorPorAtivo.put(ativo, contadorInicial);
332
                candle.setContadorCandle(contadorInicial);
333
                comContadores.add(candle);
334
                continue;
779 blopes 335
            }
336
 
782 blopes 337
            // Se não é o primeiro candle do ativo, incrementar baseado no último
338
            int proximoContador = contadorPorAtivo.get(ativo) + 1;
339
            contadorPorAtivo.put(ativo, proximoContador);
340
            candle.setContadorCandle(proximoContador);
341
 
779 blopes 342
            comContadores.add(candle);
760 blopes 343
        }
782 blopes 344
 
764 blopes 345
        return comContadores;
760 blopes 346
    }
782 blopes 347
 
764 blopes 348
 
349
    /**
350
     * 1 minuto = 1, 5 minutos = 2, 15 minutos = 3, 1 dia = 4
351
     */
352
    private Timeframe resolveTipoTemporizador(String sheetName) {
353
        if (sheetName == null) return null;
354
 
355
        String name = sheetName.toUpperCase(Locale.ROOT);
356
 
357
        if (name.startsWith("1 MIN"))  return Timeframe.M1;
358
        if (name.startsWith("5 MIN"))  return Timeframe.M5;
359
        if (name.startsWith("15 MIN")) return Timeframe.M15;
360
        if (name.startsWith("1 DIA"))  return Timeframe.D1;
361
 
362
        return null;
363
    }
364
 
760 blopes 365
}