package top.lvzhiqiang.service.impl; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; import org.jsoup.Connection; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import top.lvzhiqiang.entity.CoinBinanceOrderHistory; import top.lvzhiqiang.entity.CoinBinanceSymbol; import top.lvzhiqiang.mapper.CoinMapper; import top.lvzhiqiang.util.JsoupUtil; import javax.annotation.Resource; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.management.RuntimeErrorException; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.Proxy; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.stream.Collectors; /** * Coin ServiceImpl * * @author lvzhiqiang * 2023/9/5 15:23 */ @Service @Slf4j public class CoinService2Impl implements CoinService2 { private static final String secretKey = "Do5YDooH9OFimHXsF6nhi7rTZfxIZWWxaP35zsBEktGvCbogtbzBHpJs5cdVmple"; private static final String apiKey = "1qY3LgxmNcW1dku8NiL8NWX8KZG4SBevXHtqLFgzWZbAuJ207CUuf0FSNzIAONh5"; @Resource private CoinMapper coinMapper; private static Mac MAC; static { try { CoinService2Impl.MAC = Mac.getInstance("HmacSHA256"); } catch (NoSuchAlgorithmException var1) { throw new RuntimeErrorException(new Error("Can't get Mac's instance.")); } } @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void syncData4Binance(String startTime, String endTime, String pageSize) { String baseUrl = "https://fapi.binance.com"; String businessUrl; String businessUrl2; Connection.Response response = null; Proxy proxy = Proxy.NO_PROXY; Map paramMap = new LinkedHashMap<>(); Map headerMap = new HashMap<>(); // 1同步合约交易对 /*try { businessUrl = "/fapi/v1/exchangeInfo"; response = JsoupUtil.requestBody(baseUrl + businessUrl, "GET", proxy, headerMap, paramMap); JSONArray symbolList = JSONObject.parseObject(response.body()).getJSONArray("symbols"); if (symbolList.size() > 0) { coinMapper.insertCoinBinanceSymbolList(JSONArray.parseArray(symbolList.toJSONString(), CoinBinanceSymbol.class)); log.warn("syncData4Binance->exchangeInfo,startTime={},endTime={},size={}", startTime, endTime, symbolList.size()); } } catch (Exception e) { log.error("syncData4Binance->exchangeInfo error,response={}", response, e); }*/ // 2同步订单历史 // 2.1获取合约交易对 Map queryParamMap = new HashMap<>(); queryParamMap.put("status", "TRADING"); queryParamMap.put("marginAsset", "USDT"); queryParamMap.put("contractType", "PERPETUAL"); queryParamMap.put("sortField", "onboardDate"); queryParamMap.put("sort", "desc"); List coinBinanceSymbolList = coinMapper.findCoinBinanceSymbolListByParams(queryParamMap); // 2.2获取历史订单号集合 List orderIdList = coinMapper.findAllCoinBinanceOrderIdList(); // 2.3循环调取查询所有订单(包括历史订单)接口 headerMap.put("X-MBX-APIKEY", apiKey); try { businessUrl = "/fapi/v1/allOrders"; businessUrl2 = "/fapi/v1/userTrades"; for (CoinBinanceSymbol coinBinanceSymbol : coinBinanceSymbolList) { List coinBinanceOrderHistoryListAll = new ArrayList<>(); //权重: 5;每12秒调1次 Thread.sleep(12000L); paramMap.clear(); String timestamp = String.valueOf(System.currentTimeMillis()); paramMap.put("symbol", coinBinanceSymbol.getSymbol()); paramMap.put("startTime", startTime); paramMap.put("endTime", endTime); paramMap.put("timestamp", timestamp); String queryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); String sign = generate("", "", "", queryString, null, secretKey); paramMap.put("signature", sign); try { response = JsoupUtil.requestBody(baseUrl + businessUrl, "GET", proxy, headerMap, paramMap); JSONArray orderList = JSONArray.parseArray(response.body()); if (orderList != null && orderList.size() > 0) { List coinBinanceOrderHistoryList = JSONArray.parseArray(orderList.toJSONString(), CoinBinanceOrderHistory.class); for (CoinBinanceOrderHistory coinBinanceOrderHistory : coinBinanceOrderHistoryList) { if (orderIdList.contains(coinBinanceOrderHistory.getOrderId())) { continue; } paramMap.clear(); timestamp = String.valueOf(System.currentTimeMillis()); paramMap.put("symbol", coinBinanceSymbol.getSymbol()); paramMap.put("orderId", coinBinanceOrderHistory.getOrderId()); paramMap.put("startTime", startTime); paramMap.put("endTime", endTime); paramMap.put("timestamp", timestamp); queryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&")); sign = generate("", "", "", queryString, null, secretKey); paramMap.put("signature", sign); response = JsoupUtil.requestBody(baseUrl + businessUrl2, "GET", proxy, headerMap, paramMap); JSONArray userTradeList = JSONArray.parseArray(response.body()); BigDecimal commission = BigDecimal.ZERO; BigDecimal realizedPnl = BigDecimal.ZERO; if (userTradeList != null && userTradeList.size() > 0) { for (int i = 0; i < userTradeList.size(); i++) { JSONObject userTradeJO = userTradeList.getJSONObject(i); commission = commission.add(new BigDecimal(userTradeJO.getString("commission"))); realizedPnl = realizedPnl.add(new BigDecimal(userTradeJO.getString("realizedPnl"))); } coinBinanceOrderHistory.setCommission(commission.setScale(4, RoundingMode.HALF_UP)); coinBinanceOrderHistory.setRealizedPnl(realizedPnl.setScale(4, RoundingMode.HALF_UP)); } coinBinanceOrderHistoryListAll.add(coinBinanceOrderHistory); System.out.println(coinBinanceOrderHistory); } } if (coinBinanceOrderHistoryListAll.size() > 0) { coinMapper.insertOrUpdateBinanceOrderHistoryList(coinBinanceOrderHistoryListAll); log.warn("syncData4Binance->allOrders sub,startTime={},endTime={},size={}", startTime, endTime, coinBinanceOrderHistoryListAll.size()); } } catch (Exception ee) { log.error("syncData4Binance->allOrders sub error,response={}", response, ee); } } } catch (Exception e) { log.error("syncData4Binance->allOrders error,response={}", response, e); } } private static String generate(String timestamp, String method, String requestPath, String queryString, String body, String secretKey) throws CloneNotSupportedException, InvalidKeyException { method = StringUtils.defaultIfBlank(method.toUpperCase(), StringUtils.EMPTY); body = StringUtils.defaultIfBlank(body, StringUtils.EMPTY); queryString = StringUtils.isBlank(queryString) ? StringUtils.EMPTY : (StringUtils.isEmpty(method) ? "" : "?") + queryString; String preHash = timestamp + method + requestPath + queryString + body; //log.info("preHash:{}", preHash); byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, "HmacSHA256"); Mac mac = (Mac) CoinService2Impl.MAC.clone(); mac.init(secretKeySpec); return new String(new Hex().encode(mac.doFinal(preHash.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8); } }