Subversion Repositories Integrator Subversion

Rev

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