Subversion Repositories Integrator Subversion

Rev

Rev 771 | Rev 776 | 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.core;
2
 
775 blopes 3
import java.io.BufferedReader;
767 blopes 4
import java.io.FileInputStream;
761 blopes 5
import java.io.IOException;
6
import java.math.BigDecimal;
775 blopes 7
import java.nio.charset.StandardCharsets;
8
import java.nio.file.Files;
767 blopes 9
import java.nio.file.Path;
10
import java.time.LocalDate;
761 blopes 11
import java.time.LocalDateTime;
767 blopes 12
import java.time.LocalTime;
761 blopes 13
import java.time.format.DateTimeFormatter;
14
import java.util.ArrayList;
15
import java.util.Collections;
16
import java.util.List;
17
import java.util.Locale;
18
import java.util.Map;
775 blopes 19
import java.util.stream.Stream;
761 blopes 20
 
21
import org.apache.poi.EncryptedDocumentException;
22
import org.apache.poi.ss.usermodel.Cell;
23
import org.apache.poi.ss.usermodel.Row;
24
import org.apache.poi.ss.usermodel.Sheet;
25
import org.apache.poi.ss.usermodel.Workbook;
767 blopes 26
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
761 blopes 27
 
28
import br.com.kronus.core.Timeframe;
29
import br.com.sl.domain.dto.robo.ProfitTick;
30
import br.com.sl.domain.model.Candle;
31
import br.com.sl.domain.model.tipos.TipoPeriodoCandle;
767 blopes 32
import br.com.sl.shared.ExcelDataUtils;
761 blopes 33
 
34
public class ExcelProfitHistoricoDataProvider implements ProfitDataProvider {
35
 
775 blopes 36
    private final Path excelFile; // agora pode ser arquivo OU pasta
761 blopes 37
    private final String sheetName;
38
 
775 blopes 39
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy");
40
    private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss");
41
 
767 blopes 42
    public ExcelProfitHistoricoDataProvider(Path excelFile, String sheetName) {
43
        this.excelFile = excelFile;
761 blopes 44
        this.sheetName = sheetName;
45
    }
775 blopes 46
 
761 blopes 47
    @Override
48
    public Map<String, ProfitTick> readCurrentTicks() {
775 blopes 49
        // TODO Auto-generated method stub
50
        return null;
761 blopes 51
    }
775 blopes 52
 
761 blopes 53
    /**
775 blopes 54
     * Lê um ou vários arquivos:
55
     * - Se excelFile for um arquivo: lê apenas esse arquivo (.xlsx, .xls ou .csv)
56
     * - Se excelFile for uma pasta: lê todos os .xlsx, .xls e .csv da pasta.
761 blopes 57
     */
58
    public List<Candle> lerCandles() throws IOException {
59
        List<Candle> candles = new ArrayList<>();
60
 
775 blopes 61
        if (Files.isDirectory(excelFile)) {
62
            // Percorre todos os arquivos da pasta
63
            try (Stream<Path> stream = Files.list(excelFile)) {
64
                stream
65
                    .filter(Files::isRegularFile)
66
                    .filter(p -> {
67
                        String name = p.getFileName().toString().toLowerCase(Locale.ROOT);
68
                        return name.endsWith(".xlsx") || name.endsWith(".xls") || name.endsWith(".csv");
69
                    })
70
                    .forEach(path -> {
71
                        try {
72
                            lerCandlesDeArquivo(path, candles);
73
                        } catch (IOException e) {
74
                            // aqui você pode trocar por log
75
                            e.printStackTrace();
76
                        }
77
                    });
78
            }
79
        } else {
80
            // Apenas um arquivo
81
            lerCandlesDeArquivo(excelFile, candles);
82
        }
83
 
84
        return adicionarContadores(inverterLista(candles));
85
    }
86
 
87
    /**
88
     * Decide se o arquivo é Excel ou CSV e delega para o método correto.
89
     */
90
    private void lerCandlesDeArquivo(Path arquivo, List<Candle> candles) throws IOException {
91
        String name = arquivo.getFileName().toString().toLowerCase(Locale.ROOT);
92
 
93
        if (name.endsWith(".xlsx") || name.endsWith(".xls")) {
94
            lerCandlesDeArquivoExcel(arquivo, candles);
95
        } else if (name.endsWith(".csv")) {
96
            lerCandlesDeArquivoCsv(arquivo, candles);
97
        } else {
98
            // Tipo não suportado, ignora ou loga
99
        }
100
    }
101
 
102
    /**
103
     * Lê os candles de UM arquivo Excel e adiciona na lista passada.
104
     * (É basicamente o seu código original, só movido para cá)
105
     */
106
    private void lerCandlesDeArquivoExcel(Path arquivoExcel, List<Candle> candles) throws IOException {
107
        try (FileInputStream fis = new FileInputStream(arquivoExcel.toFile());
108
             Workbook workbook = new XSSFWorkbook(fis)) {
109
 
761 blopes 110
            int numberOfSheets = workbook.getNumberOfSheets();
111
 
112
            for (int i = 0; i < numberOfSheets; i++) {
113
                Sheet sheet = workbook.getSheetAt(i);
775 blopes 114
 
771 blopes 115
                for (Row row : sheet) {
116
 
117
                    // 0 = Ativo
118
                    // 1 = Dia
119
                    // 2 = Hora
120
                    // 3 = Abertura
121
                    // 4 = Máxima
122
                    // 5 = Mínima
123
                    // 6 = Fechamento
124
                    // 7 = Volume
125
                    // 8 = ...
126
 
127
                    Cell ativoCell      = row.getCell(0);
128
                    Cell dataCell       = row.getCell(1);
129
                    Cell horaCell       = row.getCell(2);
130
                    Cell aberturaCell   = row.getCell(3);
131
                    Cell maximaCell     = row.getCell(4);
132
                    Cell minimaCell     = row.getCell(5);
133
                    Cell fechamentoCell = row.getCell(6);
134
 
135
                    if (!ExcelDataUtils.isNumeric(aberturaCell) || !ExcelDataUtils.isNumeric(maximaCell)
775 blopes 136
                            || !ExcelDataUtils.isNumeric(minimaCell) || !ExcelDataUtils.isNumeric(fechamentoCell)) {
771 blopes 137
                        continue;
138
                    }
775 blopes 139
 
771 blopes 140
                    LocalDate data = ExcelDataUtils.lerData(dataCell);
141
                    LocalTime hora = ExcelDataUtils.lerHora(horaCell);
142
                    hora = hora.plusMinutes(6).plusSeconds(28);
143
                    LocalDateTime dataHora = LocalDateTime.of(data, hora);
775 blopes 144
 
771 blopes 145
                    String ativoDescricao = ativoCell.getStringCellValue();
146
                    BigDecimal abertura = BigDecimal.valueOf(aberturaCell.getNumericCellValue());
147
                    BigDecimal topo = BigDecimal.valueOf(maximaCell.getNumericCellValue());
148
                    BigDecimal fundo = BigDecimal.valueOf(minimaCell.getNumericCellValue());
149
                    BigDecimal fechamento = BigDecimal.valueOf(fechamentoCell.getNumericCellValue());
150
 
775 blopes 151
                    Candle candle = new Candle(
152
                            null,
153
                            ativoDescricao,
154
                            dataHora,
155
                            abertura,
156
                            topo,
157
                            fundo,
158
                            fechamento,
159
                            TipoPeriodoCandle.M1.getValor()
160
                    );
161
                    candles.add(candle);
761 blopes 162
                }
163
            }
164
        } catch (EncryptedDocumentException e) {
775 blopes 165
            e.printStackTrace();
767 blopes 166
        }
761 blopes 167
    }
775 blopes 168
 
169
    /**
170
     * Lê os candles de UM arquivo CSV e adiciona na lista passada.
171
     * Espera layout:
172
     * 0 = Ativo
173
     * 1 = Dia  (dd/MM/yyyy)
174
     * 2 = Hora (HH:mm:ss)
175
     * 3 = Abertura
176
     * 4 = Máxima
177
     * 5 = Mínima
178
     * 6 = Fechamento
179
     */
180
    private void lerCandlesDeArquivoCsv(Path arquivoCsv, List<Candle> candles) throws IOException {
181
        try (BufferedReader br = Files.newBufferedReader(arquivoCsv, StandardCharsets.UTF_8)) {
182
            String line;
183
            while ((line = br.readLine()) != null) {
184
 
185
                // Substitui line.isBlank() por trim().isEmpty()
186
                String trimmed = line.trim();
187
                if (trimmed.isEmpty()) {
188
                    continue;
189
                }
190
 
191
                // Ajuste aqui se o separador do seu CSV for vírgula
192
                String[] parts = trimmed.split(";", -1);
193
                if (parts.length < 7) {
194
                    continue;
195
                }
196
 
197
                String ativoDescricao = parts[0].trim();
198
                String dataStr        = parts[1].trim();
199
                String horaStr        = parts[2].trim();
200
                String aberturaStr    = parts[3].trim();
201
                String maximaStr      = parts[4].trim();
202
                String minimaStr      = parts[5].trim();
203
                String fechamentoStr  = parts[6].trim();
204
 
205
                // Ignora header, caso exista
206
                if (ativoDescricao.equalsIgnoreCase("ativo")) {
207
                    continue;
208
                }
209
 
210
                if (!isNumericString(aberturaStr) ||
211
                    !isNumericString(maximaStr)   ||
212
                    !isNumericString(minimaStr)   ||
213
                    !isNumericString(fechamentoStr)) {
214
                    continue;
215
                }
216
 
217
                LocalDate data = LocalDate.parse(dataStr, DATE_FORMAT);
218
                LocalTime hora = LocalTime.parse(horaStr, TIME_FORMAT);
219
                LocalDateTime dataHora = LocalDateTime.of(data, hora);
220
 
221
                BigDecimal abertura   = parseBigDecimal(aberturaStr);
222
                BigDecimal topo       = parseBigDecimal(maximaStr);
223
                BigDecimal fundo      = parseBigDecimal(minimaStr);
224
                BigDecimal fechamento = parseBigDecimal(fechamentoStr);
225
 
226
                Candle candle = new Candle(
227
                        null,
228
                        ativoDescricao,
229
                        dataHora,
230
                        abertura,
231
                        topo,
232
                        fundo,
233
                        fechamento,
234
                        TipoPeriodoCandle.M1.getValor()
235
                );
236
                candles.add(candle);
237
            }
238
        }
239
    }
240
 
241
 
242
    private BigDecimal parseBigDecimal(String value) {
243
        if (value == null) return null;
244
        String normalized = value.trim().replace(".", "").replace(",", ".");
245
        // Se o Profit já exportar com ponto como separador decimal, remova o replace(".","")
246
        // e deixe apenas: value.trim().replace(",", ".")
247
        if (normalized.isEmpty()) return null;
248
        return new BigDecimal(normalized);
249
    }
250
 
251
    private boolean isNumericString(String value) {
252
        if (value == null) return false;
253
        String normalized = value.trim().replace(".", "").replace(",", ".");
254
        if (normalized.isEmpty()) return false;
255
        try {
256
            new BigDecimal(normalized);
257
            return true;
258
        } catch (NumberFormatException e) {
259
            return false;
260
        }
261
    }
262
 
761 blopes 263
    public static List<Candle> inverterLista(List<Candle> candles) {
264
        List<Candle> invertida = new ArrayList<>(candles);
265
        Collections.reverse(invertida);
266
        return invertida;
267
    }
268
 
269
    public static List<Candle> adicionarContadores(List<Candle> candles) {
270
        Integer contador = 1;
775 blopes 271
        List<Candle> comContadores = new ArrayList<>();
761 blopes 272
        for (Candle candle : candles) {
775 blopes 273
            candle.setContadorCandle(contador);
274
            comContadores.add(candle);
275
            contador++;
761 blopes 276
        }
277
        return comContadores;
278
    }
775 blopes 279
 
761 blopes 280
    /**
281
     * 1 minuto = 1, 5 minutos = 2, 15 minutos = 3, 1 dia = 4
282
     */
283
    private Timeframe resolveTipoTemporizador(String sheetName) {
284
        if (sheetName == null) return null;
285
 
286
        String name = sheetName.toUpperCase(Locale.ROOT);
287
 
288
        if (name.startsWith("1 MIN"))  return Timeframe.M1;
289
        if (name.startsWith("5 MIN"))  return Timeframe.M5;
290
        if (name.startsWith("15 MIN")) return Timeframe.M15;
291
        if (name.startsWith("1 DIA"))  return Timeframe.D1;
292
 
293
        return null;
294
    }
295
 
775 blopes 296
}