package br.com.sl.core;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.List;
import br.com.sl.domain.dto.OrdemBinanceDTO;
import br.com.sl.domain.dto.robo.SinalTradeGatilho3;
import br.com.sl.domain.model.Candle;
import br.com.sl.domain.model.tipos.TipoSinal;
public class ExportadorSinalBinance
{
// Ajuste a pasta como preferir
private static final String PASTA_SINAIS =
"D:/Dropbox/BLP/INVESTIMENTOS/DAYTRADE/sinais";
// Se quiser usar em algum momento para quantidade padrão
private static final BigDecimal QTDE_PADRAO =
BigDecimal.
ONE;
/**
* Exporta todos os sinais para arquivos CSV,
* 1 arquivo por sinal, pronto para ser lido por outro serviço.
*/
public static void exportarSinaisParaPasta
(List<SinalTradeGatilho3
> sinais
) {
if (sinais ==
null || sinais.
isEmpty()) {
System.
out.
println("[BinanceSignalExporter] Nenhum sinal para exportar.");
return;
}
File pasta =
new File(PASTA_SINAIS
);
if (!pasta.
exists()) {
boolean ok = pasta.
mkdirs();
if (!ok
) {
System.
err.
println("[BinanceSignalExporter] Não foi possível criar a pasta: " + PASTA_SINAIS
);
return;
}
}
for (SinalTradeGatilho3 sinal : sinais
) {
try {
OrdemBinanceDTO payload = converterParaPayloadBinance
(sinal
);
String csv = converterParaCsv
(payload
);
String nomeArquivo = montarNomeArquivoCsv
(pasta, payload, sinal
);
gravarArquivo
(nomeArquivo, csv
);
} catch (Exception e
) {
System.
err.
println("[BinanceSignalExporter] Erro ao exportar sinal: " + e.
getMessage());
e.
printStackTrace();
}
}
}
/**
* Converte um SinalTradeGatilho3 para o payload de ordem "modelo Binance".
*/
private static OrdemBinanceDTO converterParaPayloadBinance
(SinalTradeGatilho3 sinal
) {
OrdemBinanceDTO p =
new OrdemBinanceDTO
();
// 1) Symbol da Binance
String symbol = mapearParaSymbolBinance
(sinal
);
// 2) Side -> BUY ou SELL
String side = sinal.
getTipoOperacao() == TipoSinal.
COMPRA_C ? "BUY" :
"SELL";
// 3) Tipo de ordem – exemplo LIMIT padrão
String type =
"LIMIT";
String timeInForce =
"GTC";
// 4) Quantidade – usa contratosTotais, mas pode ajustar
BigDecimal quantity =
BigDecimal.
valueOf(sinal.
getContratosTotais());
// 5) Preço de entrada – Entrada 1 como principal
BigDecimal price = sinal.
getPrecoEntrada1();
// 6) Stops e Targets
BigDecimal stopLoss = sinal.
getStopMenos100();
BigDecimal tp1 = sinal.
getAlvo1();
BigDecimal tp2 = sinal.
getAlvo2();
// 7) ClientOrderId – algo identificável
Candle g3 = sinal.
getGatilho3();
String dataHora =
"";
if (g3
!=
null && g3.
getDataHora() !=
null) {
SimpleDateFormat sdf =
new SimpleDateFormat("yyyyMMdd_HHmmss");
dataHora = sdf.
format(g3.
getDataHora()); // aqui getDataHora() é Date
}
String clientOrderId =
"G3_" + symbol +
"_" + dataHora +
"_c" + sinal.
getGatilho3().
getContadorCandle();
p.
setSymbol(symbol
);
p.
setSide(side
);
p.
setType(type
);
p.
setTimeInForce(timeInForce
);
p.
setQuantity(quantity
);
p.
setPrice(price
);
p.
setStopLoss(stopLoss
);
p.
setTakeProfit1(tp1
);
p.
setTakeProfit2(tp2
);
p.
setClientOrderId(clientOrderId
);
return p
;
}
/**
* Mapeia o ativo interno para o símbolo da Binance.
*/
private static String mapearParaSymbolBinance
(SinalTradeGatilho3 sinal
) {
String nomeAtivo =
null;
if (sinal.
getReferencia() !=
null && sinal.
getReferencia().
getAtivo() !=
null) {
nomeAtivo = sinal.
getReferencia().
getAtivo().
getNome();
} else if (sinal.
getReferencia() !=
null) {
nomeAtivo = sinal.
getReferencia().
getNomeAtivo();
}
if (nomeAtivo ==
null) {
return "BTCUSDT";
}
if (nomeAtivo.
equalsIgnoreCase("BTC") || nomeAtivo.
equalsIgnoreCase("BTCUSDT")) {
return "BTCUSDT";
}
if (nomeAtivo.
equalsIgnoreCase("ETH") || nomeAtivo.
equalsIgnoreCase("ETHUSDT")) {
return "ETHUSDT";
}
return nomeAtivo.
toUpperCase() +
"USDT";
}
/**
* Gera o conteúdo CSV (cabeçalho + linha única).
* Novo campo: status = "P" (pendente)
*/
private static String converterParaCsv
(OrdemBinanceDTO p
) {
StringBuilder sb =
new StringBuilder();
// Cabeçalho
sb.
append("symbol,side,type,timeInForce,quantity,price,stopLoss,takeProfit1,takeProfit2,clientOrderId,status\n");
// Linha de dados
sb.
append(escapeCsv
(p.
getSymbol())).
append(",");
sb.
append(escapeCsv
(p.
getSide())).
append(",");
sb.
append(escapeCsv
(p.
getType())).
append(",");
sb.
append(escapeCsv
(p.
getTimeInForce())).
append(",");
sb.
append(p.
getQuantity()).
append(",");
sb.
append(p.
getPrice()).
append(",");
sb.
append(p.
getStopLoss()).
append(",");
sb.
append(p.
getTakeProfit1()).
append(",");
sb.
append(p.
getTakeProfit2()).
append(",");
sb.
append(escapeCsv
(p.
getClientOrderId())).
append(",");
sb.
append("P"); // status pendente
sb.
append("\n");
return sb.
toString();
}
/**
* Escapa campos texto para CSV básico.
*/
private static String escapeCsv
(String s
) {
if (s ==
null) return "";
// Se tiver vírgula, aspas ou quebra de linha, envolve em aspas e escapa aspas
boolean precisaAspas = s.
contains(",") || s.
contains("\"") || s.
contains("\n") || s.
contains("\r");
String valor = s.
replace("\"",
"\"\"");
return precisaAspas
? "\"" + valor +
"\"" : valor
;
}
/**
* Monta nome de arquivo: BINANCE_SIGNAL_<symbol>_<clientOrderId>.csv
*/
private static String montarNomeArquivoCsv
(File pasta, OrdemBinanceDTO payload, SinalTradeGatilho3 sinal
) {
String symbol = payload.
getSymbol();
String clientId = payload.
getClientOrderId();
String nome =
"BINANCE_SIGNAL_" + symbol +
"_" + clientId +
".csv";
return new File(pasta, nome
).
getAbsolutePath();
}
private static void gravarArquivo
(String caminho,
String conteudo
) throws IOException {
try (FileWriter fw =
new FileWriter(caminho,
false)) {
fw.
write(conteudo
);
}
System.
out.
println("[BinanceSignalExporter] Arquivo CSV criado: " + caminho
);
}
}