Parcourir la source

add:增加币安历史记录表对接v1

lvzhiqiang il y a 1 an
Parent
commit
98c3aba0e8

+ 14 - 0
src/main/java/top/lvzhiqiang/config/MyCoinJobs.java

@@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import top.lvzhiqiang.service.CoinService;
+import top.lvzhiqiang.service.impl.CoinService2;
 import top.lvzhiqiang.util.DateUtils;
 
 import javax.annotation.Resource;
@@ -21,6 +22,8 @@ public class MyCoinJobs {
 
     @Resource
     private CoinService coinService;
+    @Resource
+    private CoinService2 coinService2;
 
     private static final String SCHEDULED_ZONE = "Asia/Shanghai";
 
@@ -44,6 +47,17 @@ public class MyCoinJobs {
     }
 
     /**
+     * 同步币安数据
+     */
+    //@Scheduled(cron = "0 0 5 * * ?", zone = SCHEDULED_ZONE)
+    public void syncData4Binance() {
+        String startTime = String.valueOf(DateUtils.localDateTimeToMilliseconds(LocalDateTime.now().minusDays(1)));
+        String endTime = String.valueOf(System.currentTimeMillis());
+        String pageSize = "500";
+        coinService2.syncData4Binance(startTime, endTime, pageSize);
+    }
+
+    /**
      * 每天6:00 jsoup coinmarketcap map
      */
     @Scheduled(cron = "0 0 6 * * ?", zone = SCHEDULED_ZONE)

+ 144 - 0
src/main/java/top/lvzhiqiang/entity/CoinBinanceOrderHistory.java

@@ -0,0 +1,144 @@
+package top.lvzhiqiang.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * coin-币安历史订单
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 0:37
+ */
+@Data
+public class CoinBinanceOrderHistory implements Serializable {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 系统订单号
+     */
+    private String orderId;
+
+    /**
+     * 交易对
+     */
+    private String symbol;
+
+    /**
+     * 订单状态
+     * <p>
+     * NEW 新建订单
+     * PARTIALLY_FILLED 部分成交
+     * FILLED 全部成交
+     * CANCELED 已撤销
+     * REJECTED 订单被拒绝
+     * EXPIRED 订单过期(根据timeInForce参数规则)
+     * EXPIRED_IN_MATCH 订单被STP过期
+     */
+    private String status;
+
+    /**
+     * 委托价格
+     */
+    private String price;
+
+    /**
+     * 平均成交价
+     */
+    private String avgPrice;
+
+    /**
+     * 原始委托数量
+     */
+    private String origQty;
+
+    /**
+     * 成交量
+     */
+    private String executedQty;
+
+    /**
+     * 成交金额
+     */
+    private String cumQuote;
+
+    /**
+     * 有效方式
+     * <p>
+     * GTC - Good Till Cancel 成交为止
+     * IOC - Immediate or Cancel 无法立即成交(吃单)的部分就撤销
+     * FOK - Fill or Kill 无法全部立即成交就撤销
+     * GTX - Good Till Crossing 无法成为挂单方就撤销
+     * GTD - Good Till Date 在特定时间之前有效,到期自动撤销
+     */
+    private String timeInForce;
+
+    /**
+     * 订单类型
+     * <p>
+     * MARKET 市价单
+     * LIMIT 限价单
+     * STOP 止损单
+     * TAKE_PROFIT 止盈单
+     * LIQUIDATION 强平单
+     */
+    private String type;
+
+    /**
+     * 买卖方向
+     */
+    private String side;
+
+    /**
+     * 持仓方向
+     * <p>
+     * BUY 买入
+     * SELL 卖出
+     */
+    private String positionSide;
+
+    /**
+     * 触发价,对`TRAILING_STOP_MARKET`无效
+     */
+    private String stopPrice;
+
+    /**
+     * 条件价格触发类型,MARK_PRICE(标记价格), CONTRACT_PRICE(合约最新价). 默认 CONTRACT_PRICE
+     */
+    private String workingType;
+
+    /**
+     * 触发前订单类型
+     */
+    private String origType;
+
+    /**
+     * 订单时间
+     */
+    private String time;
+
+    /**
+     * 更新时间
+     */
+    private String updateTime;
+
+    /**
+     * 手续费
+     */
+    private BigDecimal commission;
+
+    /**
+     * 实现盈亏
+     */
+    private BigDecimal realizedPnl;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime modifyTime;
+}

+ 111 - 0
src/main/java/top/lvzhiqiang/entity/CoinBinanceSymbol.java

@@ -0,0 +1,111 @@
+package top.lvzhiqiang.entity;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * coin-币安交易对
+ *
+ * @author lvzhiqiang
+ * 2023/9/9 0:37
+ */
+@Data
+public class CoinBinanceSymbol implements Serializable {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 交易对
+     */
+    private String symbol;
+
+    /**
+     * 交易对状态
+     * <p>
+     * PENDING_TRADING 待上市
+     * TRADING 交易中
+     * PRE_DELIVERING 预交割
+     * DELIVERING 交割中
+     * DELIVERED 已交割
+     * PRE_SETTLE 预结算
+     * SETTLING 结算中
+     * CLOSE 已下架
+     */
+    private String status;
+
+    /**
+     * 标的资产
+     */
+    private String baseAsset;
+
+    /**
+     * 保证金资产
+     */
+    private String marginAsset;
+
+    /**
+     * 标的资产精度
+     */
+    private String baseAssetPrecision;
+
+    /**
+     * 合约类型
+     * <p>
+     * PERPETUAL 永续合约
+     * CURRENT_MONTH 当月交割合约
+     * NEXT_MONTH 次月交割合约
+     * CURRENT_QUARTER 当季交割合约
+     * NEXT_QUARTER 次季交割合约
+     * PERPETUAL_DELIVERING 交割结算中合约
+     */
+    private String contractType;
+
+    /**
+     * 分类
+     */
+    private String underlyingSubType;
+
+    /**
+     * filters
+     */
+    private String filters;
+
+    /**
+     * 订单类型
+     */
+    private String orderTypes;
+
+    /**
+     * 有效方式
+     */
+    private String timeInForce;
+
+    /**
+     * 强平费率
+     */
+    private String liquidationFee;
+
+    /**
+     * 市价吃单(相对于标记价格)允许可造成的最大价格偏离比例
+     */
+    private String marketTakeBound;
+
+    /**
+     * 交割日期
+     */
+    private String deliveryDate;
+
+    /**
+     * 上线日期
+     */
+    private String onboardDate;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private LocalDateTime modifyTime;
+}

+ 46 - 0
src/main/java/top/lvzhiqiang/mapper/CoinMapper.java

@@ -182,4 +182,50 @@ public interface CoinMapper {
             " ON DUPLICATE KEY UPDATE cmc_id=values(cmc_id),track_category=values(track_category),issuing_date=values(issuing_date),coingecko_id=values(coingecko_id)" +
             ",coingecko_url=values(coingecko_url),cmc_url=values(cmc_url),feixiaohao_url=values(feixiaohao_url),filter_flag=values(filter_flag),modify_time=now()")
     int insertOrUpdateWatchlist(CoinWatchlist coinWatchlist);
+
+    @Insert({"<script>" +
+            "INSERT INTO coin_binance_symbol(symbol,status,baseAsset,marginAsset,baseAssetPrecision,contractType,underlyingSubType," +
+            "filters,orderTypes,timeInForce,liquidationFee,marketTakeBound,deliveryDate,onboardDate,modify_time)" +
+            " VALUES " +
+            "<foreach collection='list' item='cbs' index=\"index\" separator=\",\">" +
+            "   (#{cbs.symbol},#{cbs.status},#{cbs.baseAsset},#{cbs.marginAsset},#{cbs.baseAssetPrecision},#{cbs.contractType},#{cbs.underlyingSubType}," +
+            "#{cbs.filters},#{cbs.orderTypes},#{cbs.timeInForce},#{cbs.liquidationFee},#{cbs.marketTakeBound},#{cbs.deliveryDate},#{cbs.onboardDate},now())" +
+            " </foreach>" +
+            " ON DUPLICATE KEY UPDATE status=values(status),baseAsset=values(baseAsset),marginAsset=values(marginAsset),baseAssetPrecision=values(baseAssetPrecision)," +
+            "contractType=values(contractType),underlyingSubType=values(underlyingSubType),filters=values(filters),orderTypes=values(orderTypes)," +
+            "timeInForce=values(timeInForce),liquidationFee=values(liquidationFee),marketTakeBound=values(marketTakeBound),deliveryDate=values(deliveryDate),onboardDate=values(onboardDate),modify_time=now()" +
+            "</script>"})
+    void insertCoinBinanceSymbolList(List<CoinBinanceSymbol> coinBinanceSymbolList);
+
+    @Select({"<script>" +
+            "select * from coin_binance_symbol WHERE 1 = 1" +
+            "<if test=\"keyword != null and keyword != ''\">" +
+            "   and symbol like concat('%',#{keyword},'%')" +
+            "</if>" +
+            "<if test=\"status != null and status != ''\">" +
+            "   and status = #{status}" +
+            "</if>" +
+            "<if test=\"marginAsset != null and marginAsset != ''\">" +
+            "   and marginAsset = #{marginAsset}" +
+            "</if>" +
+            "<if test=\"contractType != null and contractType != ''\">" +
+            "   and contractType = #{contractType}" +
+            "</if>" +
+            " order by ${sortField} ${sort}" +
+            "</script>"})
+    List<CoinBinanceSymbol> findCoinBinanceSymbolListByParams(Map<String, Object> params);
+
+    @Select("select orderId from coin_binance_order_history")
+    List<String> findAllCoinBinanceOrderIdList();
+
+    @Insert({"<script>" +
+            "INSERT ignore INTO coin_binance_order_history(orderId,symbol,status,price,avgPrice,origQty,executedQty,cumQuote,timeInForce,type" +
+            ",side,positionSide,stopPrice,workingType,origType,time,updateTime,commission,realizedPnl,modifyTime)" +
+            " VALUES " +
+            "<foreach collection='list' item='p' index=\"index\" separator=\",\">" +
+            "   ( #{p.orderId}, #{p.symbol}, #{p.status}, #{p.price}, #{p.avgPrice}, #{p.origQty}, #{p.executedQty}, #{p.cumQuote}, #{p.timeInForce}, #{p.type}" +
+            ", #{p.side}, #{p.positionSide}, #{p.stopPrice}, #{p.workingType}, #{p.origType}, #{p.time}, #{p.updateTime}, #{p.commission}, #{p.realizedPnl}, now())" +
+            "</foreach>" +
+            "</script>"})
+    void insertOrUpdateBinanceOrderHistoryList(List<CoinBinanceOrderHistory> coinBinanceOrderHistoryList);
 }

+ 20 - 0
src/main/java/top/lvzhiqiang/service/impl/CoinService2.java

@@ -0,0 +1,20 @@
+package top.lvzhiqiang.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.article.NewArticle;
+
+import java.util.Map;
+
+/**
+ * Coin Service
+ *
+ * @author lvzhiqiang
+ * 2023/9/5 15:23
+ */
+public interface CoinService2 {
+
+
+    void syncData4Binance(String startTime, String endTime, String pageSize);
+}

+ 174 - 0
src/main/java/top/lvzhiqiang/service/impl/CoinService2Impl.java

@@ -0,0 +1,174 @@
+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<String, String> paramMap = new LinkedHashMap<>();
+        Map<String, String> 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<String, Object> queryParamMap = new HashMap<>();
+        queryParamMap.put("status", "TRADING");
+        queryParamMap.put("marginAsset", "USDT");
+        queryParamMap.put("contractType", "PERPETUAL");
+        queryParamMap.put("sortField", "onboardDate");
+        queryParamMap.put("sort", "desc");
+        List<CoinBinanceSymbol> coinBinanceSymbolList = coinMapper.findCoinBinanceSymbolListByParams(queryParamMap);
+        // 2.2获取历史订单号集合
+        List<String> 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<CoinBinanceOrderHistory> coinBinanceOrderHistoryListAll = new ArrayList<>();
+                //权重: 5;每12秒调1次
+                Thread.sleep(12000L);
+
+                paramMap.clear();
+                String timestamp = String.valueOf(System.currentTimeMillis());
+                paramMap.put("symbol", coinBinanceSymbol.getSymbol());
+                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<CoinBinanceOrderHistory> 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("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);
+    }
+}

+ 95 - 0
src/main/java/top/lvzhiqiang/util/CheckSign4Binance.java

@@ -0,0 +1,95 @@
+package top.lvzhiqiang.util;
+
+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 javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.management.RuntimeErrorException;
+import java.net.Proxy;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class CheckSign4Binance {
+    // q:美国是限制国家,目前没有不限制国家列表,可以参考以下链接,里边都是不限制国家,如果说对于不在链接里的国家想要了解,可以咨询
+    // a:https://www.binance.com/zh-CN/country-region-selector
+    // a:请问有获取所有合约交易对的接口吗
+    // a:exchangeInfo接口,查询status=TRADING的交易对,https://binance-docs.github.io/apidocs/futures/cn/#0f3f2d5ee7
+    // q:请问有获取所有合约交易对的历史交易记录的接口吗
+    // a:账户内的成交历史的话没有,只有针对单一交易对请求查询的接口,需要逐个查询,https://binance-docs.github.io/apidocs/futures/cn/#user_data-8
+    // a:行情的成交历史一样是需要依据交易对查询,https://binance-docs.github.io/apidocs/futures/cn/#c59e471e81
+
+    private static final String secretKey = "Do5YDooH9OFimHXsF6nhi7rTZfxIZWWxaP35zsBEktGvCbogtbzBHpJs5cdVmple";
+    private static final String apiKey = "1qY3LgxmNcW1dku8NiL8NWX8KZG4SBevXHtqLFgzWZbAuJ207CUuf0FSNzIAONh5";
+
+    public static void main(String[] args) throws Exception {
+        Map<String, String> headerMap = new HashMap<>();
+        headerMap.put("X-MBX-APIKEY", apiKey);
+        Map<String, String> paramMap = new LinkedHashMap<>();
+        String timestamp = String.valueOf(System.currentTimeMillis());
+        System.out.println(timestamp);
+        paramMap.put("symbol", "THETAUSDT");
+        paramMap.put("symbol", "SUSHIUSDT");
+        paramMap.put("orderId", "216127078081");
+        paramMap.put("timestamp", timestamp);
+        String queryString = paramMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
+        String sign = generate("", "", "", queryString, null, secretKey);
+        System.out.println("sign:" + sign);
+        paramMap.put("signature", sign);
+        try {
+            String baseUrl = "https://fapi.binance.com";
+            //baseUrl = "https://api.binance.com";
+            String businessUrl = "/fapi/v1/userTrades";
+            //businessUrl = "/fapi/v1/exchangeInfo";
+            //businessUrl = "/api/v3/exchangeInfo";
+            //businessUrl = "/fapi/v2/positionRisk";
+            //businessUrl = "/fapi/v1/openOrders";
+            //businessUrl = "/fapi/v1/allOrders";
+            String requestUrl = baseUrl + businessUrl;
+            Proxy proxy = Proxy.NO_PROXY;
+            //headerMap.clear();
+            //paramMap.clear();
+
+            Connection.Response response = JsoupUtil.requestBody(requestUrl, "GET", proxy, headerMap, paramMap);
+            System.out.println(response.body());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    private static Mac MAC;
+
+    static {
+        try {
+            CheckSign4Binance.MAC = Mac.getInstance("HmacSHA256");
+        } catch (NoSuchAlgorithmException var1) {
+            throw new RuntimeErrorException(new Error("Can't get Mac's instance."));
+        }
+    }
+
+    public 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) CheckSign4Binance.MAC.clone();
+        mac.init(secretKeySpec);
+
+        return new String(new Hex().encode(mac.doFinal(preHash.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
+    }
+}

+ 13 - 0
src/test/java/top/lvzhiqiang/TestCoin.java

@@ -10,6 +10,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import top.lvzhiqiang.entity.CoinWatchlist;
 import top.lvzhiqiang.mapper.CoinMapper;
 import top.lvzhiqiang.service.CoinService;
+import top.lvzhiqiang.service.impl.CoinService2;
 import top.lvzhiqiang.util.DateUtils;
 
 import javax.annotation.Resource;
@@ -35,6 +36,9 @@ public class TestCoin {
 
     @Resource
     private CoinService coinService;
+
+    @Resource
+    private CoinService2 coinService2;
     @Resource
     private CoinMapper coinMapper;
 
@@ -48,6 +52,15 @@ public class TestCoin {
     }
 
     @Test
+    public void testSyncData4Binance() {
+        LocalDateTime now = LocalDateTime.now();
+        String startTime = String.valueOf(DateUtils.localDateTimeToMilliseconds(now.minusMonths(8)));
+        String endTime = String.valueOf(DateUtils.localDateTimeToMilliseconds(now.minusMonths(3)));
+        String pageSize = "100";
+        coinService2.syncData4Binance(startTime, endTime, pageSize);
+    }
+
+    @Test
     public void testMonitorJob() {
         coinService.monitorJob();
     }