peter
2025-07-08 83f9014a75f572154ae7732f0fc78d6467edde93
外汇
21 files modified
5 files added
1383 ■■■■ changed files
trading-order-admin/src/main/java/com/yami/trading/admin/task/AStockTradeListTask.java 8 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java 10 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiItemController.java 8 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/RealtimeController.java 13 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/websocket/WebSocketServer.java 12 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/application-local.yml 8 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/application-prod.yml 9 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/redisson/redisson-dev.yml 2 ●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/data/domain/Realtime.java 9 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/data/respDto/TradeTickResp.java 122 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java 3 ●●●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/util/MarketOpenChecker.java 3 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineConstant.java 1 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineInitServiceImpl.java 3 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineService.java 3 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java 37 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ForexGetDataJob.java 11 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AlltickBatchKlineResult.java 11 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AlltickNewPriceResult.java 14 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AllticktradeResult.java 42 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/HobiDataService.java 2 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/constant/AllticktradeMadeOptions.java 54 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/http/HttpHelper.java 82 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/FakeKlineInitService.java 116 ●●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/HobiDataServiceImpl.java 623 ●●●● patch | view | raw | blame | history
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java 177 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/task/AStockTradeListTask.java
@@ -66,13 +66,13 @@
    }
    private void fetchAStock() {
        String symbols = itemService.list().stream().filter(t->Item.A_STOCKS.equalsIgnoreCase(t.getOpenCloseType())).map(Item::getSymbol).collect(Collectors.joining(","));
        xueQiuDataService.tradeList(symbols, false);
//        String symbols = itemService.list().stream().filter(t->Item.A_STOCKS.equalsIgnoreCase(t.getOpenCloseType())).map(Item::getSymbol).collect(Collectors.joining(","));
//        xueQiuDataService.tradeList(symbols, false);
    }
    private void fetchUs() {
        String usSymbols = itemService.findByType(Item.US_STOCKS).stream().map(Item::getSymbol).collect(Collectors.joining(","));
        xueQiuDataService.tradeList(usSymbols, true);
//        String usSymbols = itemService.findByType(Item.US_STOCKS).stream().map(Item::getSymbol).collect(Collectors.joining(","));
//        xueQiuDataService.tradeList(usSymbols, true);
    }
trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java
@@ -50,8 +50,8 @@
    protected HighLowHandleJob highLowHandleJob;
//    @Autowired   外汇
//    protected StockGetDataJob stockGetDataJob;
//    @Autowired
//    protected ForexGetDataJob forexGetDataJob;
    @Autowired
    protected ForexGetDataJob forexGetDataJob;
    @Autowired
    protected CryptosGetDataJob cryptosGetDataJob;
    @Autowired
@@ -130,15 +130,15 @@
        }
        klineLoadCache.loadCache();
//        String symbols = items.stream().map(Item::getSymbol).collect(Collectors.joining(","));
        String symbols = items.stream().map(Item::getSymbol).collect(Collectors.joining(","));
        // 数据有问题初始化一下
//         klineInitService.klineInit(symbols);  外汇
         klineInitService.klineInit(symbols);  //外汇
        // 高低修正
        highLowHandleJob.start();
//        stockGetMarketJob.start();
//        // 获取realtime实时数据
//        stockGetDataJob.start();
//        forexGetDataJob.start();
        forexGetDataJob.start();
        cryptosGetDataJob.start();
        fakeSymbolGetDataJob.start();
        // 实时数据批量保存线程
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiItemController.java
@@ -9,6 +9,7 @@
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yami.trading.api.dto.RelatedStocksDto;
import com.yami.trading.bean.data.domain.Kline;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.data.dto.StocksDto;
import com.yami.trading.bean.item.domain.Item;
@@ -21,6 +22,8 @@
import com.yami.trading.common.lang.LangUtils;
import com.yami.trading.common.util.MarketOpenChecker;
import com.yami.trading.common.util.StringUtils;
import com.yami.trading.huobi.data.internal.KlineConstant;
import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.service.data.DataService;
import com.yami.trading.service.item.ItemService;
import com.yami.trading.service.syspara.LocalSysparaService;
@@ -31,6 +34,8 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -60,6 +65,8 @@
    @Autowired
    @Qualifier("dataService")
    private DataService dataService;
    @Autowired
    private KlineService klineService;
    /**
     * 产品列表数据
@@ -167,7 +174,6 @@
                symbolDTO.setTs(realtime.getTs());
                symbolDTO.setCurrent_time(realtime.getTs());
                symbolDTO.setChg(realtime.getClose().subtract(realtime.getOpen()));
            }
            dtos.add(symbolDTO);
        }
trading-order-admin/src/main/java/com/yami/trading/api/controller/RealtimeController.java
@@ -3,6 +3,7 @@
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yami.trading.bean.data.domain.Kline;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.data.domain.TradeDetails;
import com.yami.trading.bean.item.domain.Item;
@@ -12,6 +13,8 @@
import com.yami.trading.common.util.StringUtils;
import com.yami.trading.common.web.ResultObject;
import com.yami.trading.huobi.data.DataCache;
import com.yami.trading.huobi.data.internal.KlineConstant;
import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.service.data.DataService;
import com.yami.trading.service.item.ItemService;
import io.swagger.annotations.Api;
@@ -48,6 +51,8 @@
    private DataService dataService;
    @Autowired
    private ItemService itemService;
    @Autowired
    private KlineService klineService;
    @ApiOperation(value = "行情")
    @GetMapping(HOBI + "getRealtime.action")
@@ -73,6 +78,14 @@
                BigDecimal bigDecimal = BigDecimal.valueOf(1, decimals);
                d.setAsk(d.getClose().add(bigDecimal).setScale(decimals, RoundingMode.HALF_UP));
                d.setBid(d.getClose().subtract(bigDecimal).setScale(decimals, RoundingMode.HALF_UP));
                //涨跌幅 = (当天收盘价 - 前一日收盘价) / 前一日收盘价 * 100%
                if(null != bySymbol.getYesterdayLastPrice() && bySymbol.getYesterdayLastPrice().compareTo(BigDecimal.ZERO) != 0){
                    BigDecimal changePercent = (d.getClose().subtract(bySymbol.getYesterdayLastPrice()))
                            .divide(bySymbol.getYesterdayLastPrice(), 5, RoundingMode.HALF_UP) // 精确到4位小数
                            .multiply(new BigDecimal("100").setScale(2)); // 乘以100得到百分比
                    d.setChangeRatioStr(changePercent.toString());
                }
                if(d.getVolume()!=null){
                    d.setVolume(d.getVolume().setScale(2, RoundingMode.HALF_UP));
                }
trading-order-admin/src/main/java/com/yami/trading/api/websocket/WebSocketServer.java
@@ -1,6 +1,8 @@
package com.yami.trading.api.websocket;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import javax.websocket.*;
@@ -123,6 +125,16 @@
            if (WebSocketEnum.SOCKET_ENUM_REALTIME.getCode().equals(type)) {
                if (realtimeMap.get(key) != null) {
                    realtimeMap.get(key).sendMessage(message);
//                    JSONObject jsonObject = new JSONObject((message));
//                    JSONArray dataArray = jsonObject.getJSONArray("data");
//                    for (int i = 0; i < dataArray.length(); i++) {
//                        JSONObject item = dataArray.getJSONObject(i);
//                        if(item.get("name").equals("GBPUSD")){
//                            System.out.println("realtimeMap中取到的价格:"+item.get("close"));
//                        }
//                    }
                } else {
                    System.out.println("realtimeMap中没有此key,不推送消息");
                }
trading-order-admin/src/main/resources/application-local.yml
@@ -14,6 +14,8 @@
      validation-timeout: 3000  # 设置连接验证超时
      auto-commit: true
      connection-test-query: SELECT 1
    jpa:
      show-sql: true
  cache:
    type: redis
    redis:
@@ -26,7 +28,11 @@
    password:
logging:
  config: classpath:logback/logback-local.xml
alltick:
  token: 3ba36ca15660073739f25c4b1512086a-c-app
  trade-tick: "https://quote.alltick.io/quote-b-api/trade-tick?token=${alltick.token}&query={1}"
  trade-kline: "https://quote.alltick.io/quote-b-api/kline?token=${alltick.token}&query={1}"
  batch-kline: "https://quote.alltick.io/quote-b-api/batch-kline?token=${alltick.token}"
jetcache:
  statIntervalMinutes: 1
  default: # 默认default,可以配置更多的area
trading-order-admin/src/main/resources/application-prod.yml
@@ -1,10 +1,11 @@
server:
  port: 8111
  port: 8086
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:6306/trading_order?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
    username: root
    password: Err;2[eoGFUriwdgr
    url: jdbc:mysql://127.0.0.1:6306/trading_order_n?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
    username: trading_order_n
    password: 3BRTfLGX3j44WeAb
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
trading-order-admin/src/main/resources/redisson/redisson-dev.yml
@@ -1,7 +1,7 @@
# 单节点设置
singleServerConfig:
  address: redis://127.0.0.1:6380
  database: 10
  database: 12
  password:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
trading-order-bean/src/main/java/com/yami/trading/bean/data/domain/Realtime.java
@@ -66,6 +66,10 @@
     */
    @ApiModelProperty("最新价")
    private BigDecimal close;
    @ApiModelProperty("最新价")
    @TableField(exist = false)
    private BigDecimal closeOld;
    /**
     * 成交量 币个数
     */
@@ -79,6 +83,7 @@
    @ApiModelProperty(" 成交额 金额")
    private BigDecimal volume;
    /**
     * type
     */
@@ -91,6 +96,10 @@
    @ApiModelProperty("涨跌幅")
    private BigDecimal changeRatio;
    @TableField(exist = false)
    @ApiModelProperty("涨跌幅Str")
    private String changeRatioStr;
    /**
     * 净值涨跌幅
     */
trading-order-bean/src/main/java/com/yami/trading/bean/data/respDto/TradeTickResp.java
New file
@@ -0,0 +1,122 @@
package com.yami.trading.bean.data.respDto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
public class TradeTickResp {
    private int ret;
    private String msg;
    private String trace;
    private Data data;
    public static class Data {
        private List<Tick> tickList;
        @JsonProperty("tick_list")
        public List<Tick> getTickList() {
            return tickList;
        }
        public void setTickList(List<Tick> tickList) {
            this.tickList = tickList;
        }
    }
    public static class Tick {
        private String code;
        private String seq;
        private String tickTime;
        private String price;
        private String volume;
        private String turnover;
        private int tradeDirection;
        // Getters and Setters
        public String getCode() {
            return code;
        }
        public void setCode(String code) {
            this.code = code;
        }
        public String getSeq() {
            return seq;
        }
        public void setSeq(String seq) {
            this.seq = seq;
        }
        public String getTickTime() {
            return tickTime;
        }
        public void setTickTime(String tickTime) {
            this.tickTime = tickTime;
        }
        public String getPrice() {
            return price;
        }
        public void setPrice(String price) {
            this.price = price;
        }
        public String getVolume() {
            return volume;
        }
        public void setVolume(String volume) {
            this.volume = volume;
        }
        public String getTurnover() {
            return turnover;
        }
        public void setTurnover(String turnover) {
            this.turnover = turnover;
        }
        public int getTradeDirection() {
            return tradeDirection;
        }
        public void setTradeDirection(int tradeDirection) {
            this.tradeDirection = tradeDirection;
        }
    }
    public int getRet() {
        return ret;
    }
    public void setRet(int ret) {
        this.ret = ret;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public String getTrace() {
        return trace;
    }
    public void setTrace(String trace) {
        this.trace = trace;
    }
    public Data getData() {
        return data;
    }
    public void setData(Data data) {
        this.data = data;
    }
}
trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java
@@ -172,6 +172,9 @@
    @ApiModelProperty("报价货币")
    private String quoteCurrency;
    @ApiModelProperty(" 昨日成交价")
    private BigDecimal yesterdayLastPrice;
    @ApiModelProperty("前端显示状态,1显示,0不显示")
    private String showStatus;
    @ApiModelProperty("交易状态,1显示,0不显示")
trading-order-common/src/main/java/com/yami/trading/common/util/MarketOpenChecker.java
@@ -69,7 +69,8 @@
        if(stocksType.contains(closeType)){
            return isMarketOpen(closeType);
        }else if("forex".equalsIgnoreCase(closeType)){
            return UTCDateUtils.isOpen();
//            return UTCDateUtils.isOpen();
            return true;
        }else{
            return true;
        }
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineConstant.java
@@ -26,4 +26,5 @@
    public final static String PERIOD_1WEEK = "1week";
    public final static String PERIOD_QUARTER = "quarter";
    public final static String PERIOD_YEAR = "year";
    public final static String PERIOD_OTHER = "other";
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineInitServiceImpl.java
@@ -71,7 +71,8 @@
        if ("1".equalsIgnoreCase(bySymbol.getFake())) {
            return;
        }
        Map<String, List<Kline>> dailyWeekMonthHistoryMap = hobiDataService.getDailyWeekMonthHistory(symbol);
//        Map<String, List<Kline>> dailyWeekMonthHistoryMap = hobiDataService.getDailyWeekMonthHistory(symbol);
        Map<String, List<Kline>> dailyWeekMonthHistoryMap = null;
        Map<String, List<Kline>> hourlyAndMinuteHistoryMap = hobiDataService.getHourlyAndMinuteHistory(symbol);
        klineService.saveInit(symbol, dailyWeekMonthHistoryMap, hourlyAndMinuteHistoryMap);
    }
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineService.java
@@ -109,7 +109,8 @@
    Kline bulidKlineQuarter(Realtime realtime, String line);
    Kline bulidKlineYear(Realtime realtime, String line);
    public void smoothlyKline(Kline kline,  double probability);
    public Kline getLast(String symbol, String line);
    public Kline getLastTow(String symbol, String line);
    void clean();
    public List<Kline> calculateKline(String symbol, int seq, String period, List<Kline> klineList) ;
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java
@@ -59,16 +59,16 @@
        for (int i = 0; i <= Constants.TABLE_PARTITIONS - 1; i++) {
            namedParameterJdbcTemplate.update("DELETE FROM t_kline_" + i + " WHERE SYMBOL = :symbol", parameters);
        }
        for (String line : dailyWeekMonthHistoryMap.keySet()) {
            List<Kline> list = dailyWeekMonthHistoryMap.get(line);
            klineDBService.saveOrUpdateBatch(list);
            KlineTimeObject klineTimeObject = new KlineTimeObject();
            Collections.sort(list);
            klineTimeObject.setKline(list);
            klineTimeObject.setLastTime(new Date());
            DataCache.putKline(symbol, line, klineTimeObject);
        }
//        for (String line : dailyWeekMonthHistoryMap.keySet()) {
//            List<Kline> list = dailyWeekMonthHistoryMap.get(line);
//            klineDBService.saveOrUpdateBatch(list);
//
//            KlineTimeObject klineTimeObject = new KlineTimeObject();
//            Collections.sort(list);
//            klineTimeObject.setKline(list);
//            klineTimeObject.setLastTime(new Date());
//            DataCache.putKline(symbol, line, klineTimeObject);
//        }
        for (String line : hourlyAndMinuteHistoryMap.keySet()) {
            List<Kline> list = hourlyAndMinuteHistoryMap.get(line);
@@ -422,6 +422,7 @@
     * @param line
     * @return
     */
    @Override
    public Kline getLast(String symbol, String line) {
        KlineTimeObject timeObject = DataCache.getKline(symbol, line);
        List<Kline> kline = timeObject.getKline();
@@ -437,6 +438,22 @@
        return latestKilne;
    }
    @Override
    public Kline getLastTow(String symbol, String line) {
        KlineTimeObject timeObject = DataCache.getKline(symbol, line);
        List<Kline> kline = timeObject.getKline();
        Item item = itemService.findBySymbol(symbol);
        Kline latestKilne = null;
        if (null == kline || kline.size() <= 0) {
            if (item.getFake().equalsIgnoreCase("0")) {
                return null;
            }
        } else {
            latestKilne = kline.get(kline.size() - 2);
        }
        return latestKilne;
    }
    /**
     * 构建30分钟Kline数据
     */
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ForexGetDataJob.java
@@ -44,9 +44,9 @@
        while (true) {
            try {
                // 老外汇tradeView接口
                String symbols = itemService.findByType(Item.forex)
                        .stream().filter(i -> !i.getCategory().equalsIgnoreCase(Item.forex))
                        .map(Item::getSymbol).collect(Collectors.joining(","));
//                String symbols = itemService.findByType(Item.forex)
//                        .stream().filter(i -> !i.getCategory().equalsIgnoreCase(Item.forex))
//                        .map(Item::getSymbol).collect(Collectors.joining(","));
                // 新外汇
                String xinLangsymbols = itemService.findByType(Item.forex)
@@ -60,7 +60,7 @@
//                log.info("开市时间 {}", f.format(UTCDateUtils.getOpenTime()));
                Date now = f.parse(f.format(new Date()));
                if (MarketOpenChecker.isMarketOpenByItemCloseType(Item.forex)) {
                    this.realtimeHandle(symbols);
//                    this.realtimeHandle(symbols);
                    this.realtimeHandleXinLang(xinLangsymbols);
                } else {
                    logger.debug("当前为休市时间,当前UTS标准时间:{}, 开市时间:{}, 休市时间:{}",
@@ -95,7 +95,8 @@
            return;
        }
        List<Realtime> realtimeList = this.hobiDataService.realtimeXinLang(symbols);
        super.handleRealTimeList(realtimeList);
        List<Realtime> realtimeList1 = this.hobiDataService.realtimeNewPrice(symbols,realtimeList);
        super.handleRealTimeList(realtimeList1);
    }
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AlltickBatchKlineResult.java
New file
@@ -0,0 +1,11 @@
package com.yami.trading.huobi.data.model;
import lombok.Data;
import java.util.List;
@Data
public class AlltickBatchKlineResult {
    private String code;
    private Integer kline_type;
    private List<AllticktradeResult> kline_data;
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AlltickNewPriceResult.java
New file
@@ -0,0 +1,14 @@
package com.yami.trading.huobi.data.model;
import lombok.Data;
@Data
public class AlltickNewPriceResult {
    private String code;
    private String seq;
    private String tickTime;
    private String price;
    private String volume;
    private String turnover;
    private int tradeDirection;
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/AllticktradeResult.java
New file
@@ -0,0 +1,42 @@
package com.yami.trading.huobi.data.model;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class AllticktradeResult {
    private static final long serialVersionUID = -2654740103586762268L;
    /**
     * 收盘价
     */
    private BigDecimal close_price;
    /**
     * 开盘价
     */
    private BigDecimal open_price;
    /**
     * 最高价
     */
    private BigDecimal high_price;
    /**
     * 最低价
     */
    private BigDecimal low_price;
    /**
     * 时间
     */
    private String timestamp;
    /**
     * 成交量
     */
    private BigDecimal volume;
    /**
     * 成交金额
     */
    private BigDecimal turnover;
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/HobiDataService.java
@@ -19,6 +19,8 @@
    public List<Realtime> realtime(String symbols);
    public List<Realtime> realtimeXueQiu(String symbols);
    public List<Realtime> realtimeXinLang(String symbols);
    public List<Realtime> realtimeNewPrice(String symbols,List<Realtime> realtimes);
    /**
     * 1day       历史数据  : 周期 1年
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/constant/AllticktradeMadeOptions.java
New file
@@ -0,0 +1,54 @@
package com.yami.trading.huobi.hobi.constant;
public class AllticktradeMadeOptions {
    /**
     * 1分钟
     */
    public final static int minutePeriod = 1;
    /**
     * 5分钟
     */
    public final static int fivePeriod = 2;
    /**
     * 15分钟
     */
    public final static int fifteenPeriod = 3;
    /**
     * 30分钟
     */
    public final static int thirtyPeriod = 4;
    /**
     * 1小时
     */
    public final static int hourPeriod = 5;
    /**
     * 2小时
     */
    public final static int towHourPeriod = 6;
    /**
     * 4小时
     */
    public final static int fourHourPeriod = 7;
     /**
     * 1天
     */
    public final static int dayPeriod = 8;
    /**
     * 1周
     */
    public final static int weekPeriod = 9;
    /**
     * 1月
     */
    public final static int monthPeriod = 10;
    /**
     * 请求次数
     */
    public final static int dayKlineCountPeriod = 2;
    /**
     * 每次
     */
    public final static int dayKlineNumPeriod = 500;
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/http/HttpHelper.java
@@ -41,7 +41,13 @@
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -359,6 +365,10 @@
            HttpEntity entity = response.getEntity();
            return EntityUtils.toString(entity, "UTF-8");
        }
        case 603: {
                HttpEntity entity = response.getEntity();
                return EntityUtils.toString(entity, "UTF-8");
            }
        case 302: {
            return sendGetHttp(response.getFirstHeader("location").getValue(), "");
        }
@@ -423,4 +433,76 @@
    }
    public static String sendPostRequest(String targetUrl, Map<String, Object> requestData) throws IOException {
        // 创建连接
        URL url = new URL(targetUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 设置请求方法为POST
        connection.setRequestMethod("POST");
        // 启用输入输出流
        connection.setDoOutput(true);
        connection.setDoInput(true);
        // 设置请求头
        connection.setRequestProperty("Content-Type", "application/json");
        // 将Map转换为JSON字符串
        String jsonInputString = convertMapToJson(requestData);
        // 写入请求体
        try (OutputStream os = connection.getOutputStream()) {
            byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
            os.write(input, 0, input.length);
        }
        // 获取响应代码
        int responseCode = connection.getResponseCode();
        System.out.println("Response Code: " + responseCode);
        // 读取响应
        StringBuilder response = new StringBuilder();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
        }
        // 返回响应内容
        return response.toString();
    }
    public static String convertMapToJson(Map<String, Object> map) {
        StringBuilder jsonString = new StringBuilder("{");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (jsonString.length() > 1) {
                jsonString.append(",");
            }
            jsonString.append("\"").append(entry.getKey()).append("\":");
            if (entry.getValue() instanceof Map) {
                jsonString.append(convertMapToJson((Map<String, Object>) entry.getValue()));
            } else if (entry.getValue() instanceof List) {
                jsonString.append("[");
                List<?> list = (List<?>) entry.getValue();
                for (int i = 0; i < list.size(); i++) {
                    if (i > 0) {
                        jsonString.append(",");
                    }
                    jsonString.append(convertMapToJson((Map<String, Object>) list.get(i)));
                }
                jsonString.append("]");
            } else {
                jsonString.append("\"").append(entry.getValue()).append("\"");
            }
        }
        jsonString.append("}");
        return jsonString.toString();
    }
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/FakeKlineInitService.java
@@ -12,14 +12,21 @@
import com.yami.trading.bean.item.domain.Item;
import com.yami.trading.huobi.data.internal.KlineConstant;
import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.huobi.data.model.AllticktradeResult;
import com.yami.trading.huobi.hobi.constant.AllticktradeMadeOptions;
import com.yami.trading.huobi.hobi.constant.TraderMadeOptions;
import com.yami.trading.huobi.hobi.http.HttpHelper;
import com.yami.trading.service.etf.EtfMinuteKLineService;
import com.yami.trading.service.item.ItemService;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.checkerframework.checker.units.qual.K;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
@@ -29,6 +36,9 @@
    private KlineService klineService;
    @Autowired
    private EtfMinuteKLineService etfMinuteKLineService;
    @Value("${alltick.trade-kline}")
    private String tradeKline;
    public final void saveInit(String symbol) {
        Item bySymbol = itemService.findBySymbol(symbol);
@@ -46,9 +56,9 @@
            kline.setPeriod(Kline.PERIOD_1MIN);
            return kline;
        }).collect(Collectors.toList());
        Map<String, List<Kline>> dailyWeekMonthHistoryMap = getDailyWeekMonthHistory(symbol, klineList);
//        Map<String, List<Kline>> dailyWeekMonthHistoryMap = getDailyWeekMonthHistory(symbol, klineList);
        Map<String, List<Kline>> hourlyAndMinuteHistoryMap = getHourlyAndMinuteHistory(symbol, klineList);
        klineService.saveInit(symbol, dailyWeekMonthHistoryMap, hourlyAndMinuteHistoryMap);
        klineService.saveInit(symbol, null, hourlyAndMinuteHistoryMap);
    }
    @Autowired
@@ -58,31 +68,115 @@
     * 获取分钟数据
     */
    public Map<String, List<Kline>> getHourlyAndMinuteHistory(String symbol , List<Kline> klineList) {
//        Map<String, List<Kline>> map = new HashMap<>();
//
//        List<Kline> fourHourlyList = getTimeseriesForFourHourly(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_4HOUR, fourHourlyList);
//
//        List<Kline> twoHourlyList = getTimeseriesForTwoHourly(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_2HOUR, twoHourlyList);
//
//        List<Kline> oneHourlyList = getTimeseriesForOneHourly(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_60MIN, oneHourlyList);
//
//        List<Kline> thirtyMinuteList = getTimeseriesThirtyMinute(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_30MIN, thirtyMinuteList);
//
//        List<Kline> fifteenMinuteList = getTimeseriesFifteenMinute(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_15MIN, fifteenMinuteList);
//
//        List<Kline> fiveMinuteList = getTimeseriesFiveMinute(symbol,  klineList);
//        map.put(KlineConstant.PERIOD_5MIN, fiveMinuteList);
//
//        List<Kline> oneMinuteList = klineList;
//        map.put(KlineConstant.PERIOD_1MIN, oneMinuteList);
//        return map;
        Map<String, List<Kline>> map = new HashMap<>();
        List<Kline> fourHourlyList = getTimeseriesForFourHourly(symbol,  klineList);
        map.put(KlineConstant.PERIOD_4HOUR, fourHourlyList);
        List<Kline> monthList = getTimeseries(symbol,KlineConstant.PERIOD_1MON, AllticktradeMadeOptions.monthPeriod);
        map.put(KlineConstant.PERIOD_1MON, monthList);
        List<Kline> twoHourlyList = getTimeseriesForTwoHourly(symbol,  klineList);
        map.put(KlineConstant.PERIOD_2HOUR, twoHourlyList);
        List<Kline> weekList = getTimeseries(symbol,KlineConstant.PERIOD_1WEEK,AllticktradeMadeOptions.weekPeriod);
        map.put(KlineConstant.PERIOD_1WEEK, weekList);
        List<Kline> oneHourlyList = getTimeseriesForOneHourly(symbol,  klineList);
        List<Kline> dayList = getTimeseries(symbol,KlineConstant.PERIOD_1DAY,AllticktradeMadeOptions.dayPeriod);
        map.put(KlineConstant.PERIOD_1DAY, dayList);
        List<Kline> towHourlyList = getTimeseries(symbol,KlineConstant.PERIOD_2HOUR,AllticktradeMadeOptions.towHourPeriod);
        map.put(KlineConstant.PERIOD_2HOUR, towHourlyList);
        List<Kline> oneHourlyList = getTimeseries(symbol,KlineConstant.PERIOD_60MIN,AllticktradeMadeOptions.hourPeriod);
        map.put(KlineConstant.PERIOD_60MIN, oneHourlyList);
        List<Kline> thirtyMinuteList = getTimeseriesThirtyMinute(symbol,  klineList);
        List<Kline> thirtyMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_30MIN,AllticktradeMadeOptions.thirtyPeriod);
        map.put(KlineConstant.PERIOD_30MIN, thirtyMinuteList);
        List<Kline> fifteenMinuteList = getTimeseriesFifteenMinute(symbol,  klineList);
        List<Kline> fifteenMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_15MIN,AllticktradeMadeOptions.fifteenPeriod);
        map.put(KlineConstant.PERIOD_15MIN, fifteenMinuteList);
        List<Kline> fiveMinuteList = getTimeseriesFiveMinute(symbol,  klineList);
        List<Kline> fiveMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_5MIN,AllticktradeMadeOptions.fivePeriod);
        map.put(KlineConstant.PERIOD_5MIN, fiveMinuteList);
        List<Kline> oneMinuteList = klineList;
        List<Kline> oneMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_1MIN,AllticktradeMadeOptions.minutePeriod);
        map.put(KlineConstant.PERIOD_1MIN, oneMinuteList);
        return map;
    }
    public List<Kline> getTimeseries(String symbol,String period,int periodType){
        List<Kline> resList = new ArrayList<>();
        // 每次只能取一个月的数据,需要遍历3个月
        for (int i = 0; i < TraderMadeOptions.thirtyMinutePeriod; i++) {
            String resultStr = null;
            try {
                resultStr = getTradeKline(symbol,periodType,AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                continue;
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if(null == resultJson || 200 != resultJson.getInteger("ret")){
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(symbol);
                    kline.setPeriod(period);
                    // 毫秒
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
        }
        return resList;
    }
    public String getTradeKline(String symbol,int type,int num){
        JSONObject json = new JSONObject();
        json.put("trace", UUID.randomUUID().toString());
        JSONObject data = new JSONObject();
        data.put("code", symbol);
        data.put("kline_type", type);
        data.put("kline_timestamp_end", 0);
        data.put("query_kline_num", num);
        json.put("data", data);
        try {
            String url = tradeKline.replace("{1}", URLEncoder.encode(json.toString(), "UTF-8"));
            HttpGet request = new HttpGet(url);
            HttpResponse response = HttpHelper.getHttpclient().execute(request);
            return HttpHelper.responseProc(response);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }
    /**
     * 1day       历史数据  : 周期 1年
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/HobiDataServiceImpl.java
@@ -4,9 +4,11 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yami.trading.bean.data.domain.*;
import com.yami.trading.bean.data.respDto.TradeTickResp;
import com.yami.trading.bean.item.domain.Item;
import com.yami.trading.common.util.Arith;
import com.yami.trading.common.util.StringUtils;
@@ -14,6 +16,7 @@
import com.yami.trading.common.util.UTCDateUtils;
import com.yami.trading.huobi.data.internal.KlineConstant;
import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.huobi.data.model.AllticktradeResult;
import com.yami.trading.huobi.data.model.TimeseriesResult;
import com.yami.trading.huobi.data.websocket.model.market.MarketDepthEvent;
import com.yami.trading.huobi.data.websocket.model.market.MarketTrade;
@@ -21,17 +24,22 @@
import com.yami.trading.huobi.data.websocket.model.market.PriceLevel;
import com.yami.trading.huobi.hobi.Config;
import com.yami.trading.huobi.hobi.HobiDataService;
import com.yami.trading.huobi.hobi.constant.AllticktradeMadeOptions;
import com.yami.trading.huobi.hobi.constant.TraderMadeOptions;
import com.yami.trading.huobi.hobi.http.HttpHelper;
import com.yami.trading.huobi.hobi.http.HttpMethodType;
import com.yami.trading.service.item.ItemService;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
@@ -47,6 +55,9 @@
    private ItemService itemService;
    @Autowired
    private KlineService klineService;
    @Value("${alltick.trade-kline}")
    private String tradeKline;
    /**
     * 接口调用间隔(毫秒)
     */
@@ -135,7 +146,7 @@
        boolean current_lock = false;
        if (lock || (new Date().getTime() - last_time.getTime()) < interval) {
            ThreadUtils.sleep(sleep);
            if (maximum >= 100) {
            if (maximum >= 500) {
                return list;
            } else {
                return this.kline(symbol, period, num, ++maximum);
@@ -603,6 +614,10 @@
    public List<Realtime> realtimeXinLang(String symbols) {
        return xinLangDataService.realtimeSingle(symbols);
    }
    @Override
    public List<Realtime> realtimeNewPrice(String symbols,List<Realtime> realtimes) {
        return xinLangDataService.realtimeNewPrice(symbols,realtimes);
    }
    /**
     * 1day       历史数据  : 周期 1年
@@ -610,69 +625,28 @@
     * 请求 350次
     */
    public Map<String, List<Kline>> getDailyWeekMonthHistory(String symbol) {
        if (isXueQiu(symbol)) {
            return xueQiuDataService.getDailyWeekMonthHistory(symbol);
        }else if(isXinlang(symbol)){
            return xinLangDataService.getDailyWeekMonthHistory(symbol);
        }
        Map<String, List<Kline>> map = new HashMap<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        Date now = new Date();
        // 每次只能取一年的数据,需要遍历5年
        for (int i = 0; i < TraderMadeOptions.weekAndMonthPeriod; i++) {
            String startDate = UTCDateUtils.addYear(now, -1);
            String endDate = f.format(now);
            now = UTCDateUtils.toDate(startDate, "yyyy-MM-dd");
            Map<String, String> param = new HashMap<>();
            param.put("currency", symbol);
            param.put("start_date", startDate);
            param.put("end_date", endDate);
            param.put("format", "records");
            param.put("api_key", TraderMadeOptions.apiKey);
            String json = null;
        for (int i = 0; i < AllticktradeMadeOptions.dayKlineCountPeriod; i++) {
            String resultStr = null;
            try {
                json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
                resultStr = getTradeKline(symbol,AllticktradeMadeOptions.dayPeriod,AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", param);
                logger.error("采集外汇k线图失败:{} " , e);
                continue;
            }
            JSONObject resultJson = JSON.parseObject(json);
            JSONArray dataArray = resultJson.getJSONArray("quotes");
            JSONObject resultJson = JSON.parseObject(resultStr);
            if(200 != resultJson.getInteger("ret")){
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
                Map<String, List<TimeseriesResult>> monthMap = new LinkedHashMap<>();
                Map<String, List<TimeseriesResult>> weekMap = new LinkedHashMap<>();
                for (TimeseriesResult result : list) {
                    String month = result.getDate().substring(0, 7);
                    if (monthMap.containsKey(month)) {
                        monthMap.get(month).add(result);
                    } else {
                        List<TimeseriesResult> monthList = new ArrayList<>();
                        monthList.add(result);
                        monthMap.put(month, monthList);
                    }
                    String firstDateOfWeek = UTCDateUtils.getFirstDateOfWeek(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd"));
                    if (weekMap.containsKey(firstDateOfWeek)) {
                        weekMap.get(firstDateOfWeek).add(result);
                    } else {
                        List<TimeseriesResult> weekList = new ArrayList<>();
                        weekList.add(result);
                        weekMap.put(firstDateOfWeek, weekList);
                    }
                }
                map.put(Kline.PERIOD_1WEEK, buildOneWeekPeriod(weekMap, symbol));
                map.put(Kline.PERIOD_1MON, buildOneMonthPeriod(monthMap, symbol));
                // 1day历史数据  : 周期 1年
                if (0 == i) {
                    map.put(Kline.PERIOD_1DAY, buildOneDayPeriod(list, symbol));
                }
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                map.put(Kline.PERIOD_1DAY, buildOneDayPeriod(list, symbol));
            }
        }
        try {
@@ -701,59 +675,133 @@
    public Map<String, List<Kline>> getHourlyAndMinuteHistory(String symbol) {
        Map<String, List<Kline>> map = new HashMap<>();
        List<Kline> fourHourlyList = getTimeseriesForFourHourly(symbol);
        map.put(KlineConstant.PERIOD_4HOUR, fourHourlyList);
        List<Kline> monthList = getTimeseries(symbol,KlineConstant.PERIOD_1MON,AllticktradeMadeOptions.monthPeriod);
        map.put(KlineConstant.PERIOD_1MON, monthList);
        List<Kline> oneHourlyList = getTimeseriesForOneHourly(symbol);
        List<Kline> weekList = getTimeseries(symbol,KlineConstant.PERIOD_1WEEK,AllticktradeMadeOptions.weekPeriod);
        map.put(KlineConstant.PERIOD_1WEEK, weekList);
        List<Kline> dayList = getTimeseries(symbol,KlineConstant.PERIOD_1DAY,AllticktradeMadeOptions.dayPeriod);
        map.put(KlineConstant.PERIOD_1DAY, dayList);
        List<Kline> towHourlyList = getTimeseries(symbol,KlineConstant.PERIOD_2HOUR,AllticktradeMadeOptions.towHourPeriod);
        map.put(KlineConstant.PERIOD_2HOUR, towHourlyList);
        List<Kline> oneHourlyList = getTimeseries(symbol,KlineConstant.PERIOD_60MIN,AllticktradeMadeOptions.hourPeriod);
        map.put(KlineConstant.PERIOD_60MIN, oneHourlyList);
        List<Kline> twoHourlyList = getTimeseriesForTwoHourly(symbol);
        if (CollectionUtil.isEmpty(twoHourlyList)) {
            try {
                List<Kline> hourList = map.get(Kline.PERIOD_60MIN);
                if (CollectionUtil.isNotEmpty(hourList)) {
                    map.put(Kline.PERIOD_2HOUR, klineService.calculateKline(symbol, 2, Kline.PERIOD_2HOUR, hourList));
                }
            } catch (Exception e) {
                logger.error("外汇计算 120mink线图失败", e);
            }
        } else {
            map.put(KlineConstant.PERIOD_2HOUR, twoHourlyList);
        }
        List<Kline> thirtyMinuteList = getTimeseriesThirtyMinute(symbol);
        List<Kline> thirtyMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_30MIN,AllticktradeMadeOptions.thirtyPeriod);
        map.put(KlineConstant.PERIOD_30MIN, thirtyMinuteList);
        List<Kline> fifteenMinuteList = getTimeseriesFifteenMinute(symbol);
        List<Kline> fifteenMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_15MIN,AllticktradeMadeOptions.fifteenPeriod);
        map.put(KlineConstant.PERIOD_15MIN, fifteenMinuteList);
        List<Kline> fiveMinuteList = getTimeseriesFiveMinute(symbol);
        List<Kline> fiveMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_5MIN,AllticktradeMadeOptions.fivePeriod);
        map.put(KlineConstant.PERIOD_5MIN, fiveMinuteList);
        List<Kline> oneMinuteList = getTimeseriesOneMinute(symbol);
        List<Kline> oneMinuteList = getTimeseries(symbol,KlineConstant.PERIOD_1MIN,AllticktradeMadeOptions.minutePeriod);
        map.put(KlineConstant.PERIOD_1MIN, oneMinuteList);
        //昨日收盘价
        BigDecimal yesterdayLastPrice = realtimeSingleZdf(symbol);
        Item item = itemService.findBySymbol(symbol);
        item.setYesterdayLastPrice(yesterdayLastPrice);
        itemService.updateById(item);
        return map;
    }
    public List<Kline> buildOneDayPeriod(List<TimeseriesResult> list, String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.buildOneDayPeriod(currency);
        }if (isXinlang(currency)) {
            return xinLangDataService.buildOneDayPeriod(currency);
    public BigDecimal realtimeSingleZdf(String symbol){
        //计算24小时涨跌幅
        BigDecimal yesterdayLastPrice = BigDecimal.ZERO;
        List<Kline> dayklines = getTimeseries(symbol,KlineConstant.PERIOD_OTHER,AllticktradeMadeOptions.dayPeriod);
        int decimal = itemService.getDecimal(symbol);
        long minTimestamp = Long.MAX_VALUE;
        for (Kline kline : dayklines) {
            long currentTimestamp = kline.getTs();
            if (currentTimestamp < minTimestamp) {
                minTimestamp = currentTimestamp;
                yesterdayLastPrice = kline.getClose().setScale(decimal, RoundingMode.HALF_UP);
            }
        }
        return yesterdayLastPrice;
    }
    public List<Kline> getTimeseries(String symbol,String period,int periodType){
        List<Kline> resList = new ArrayList<>();
        for (TimeseriesResult result : list) {
        int klineCount;
        if (KlineConstant.PERIOD_1MIN.equals(period)) {
//            klineCount = 1440; // 当天的1分钟K线
            klineCount = 1000;
        } else if (KlineConstant.PERIOD_5MIN.equals(period)) {
            klineCount = 288; // 当天的5分钟K线
        } else if (KlineConstant.PERIOD_15MIN.equals(period)) {
            klineCount = 192; // 2天的15分钟K线,15分钟间隔
        } else if (KlineConstant.PERIOD_30MIN.equals(period)) {
            klineCount = 480; // 10天的30分钟K线
        } else if (KlineConstant.PERIOD_60MIN.equals(period)) {
            klineCount = 720; // 1个月的60分钟K线
        } else if (KlineConstant.PERIOD_2HOUR.equals(period)) {
            klineCount = 12; // 2个月的120分钟K线
        } else if (KlineConstant.PERIOD_4HOUR.equals(period)) {
            klineCount = 540; // 3个月的4小时K线
        } else if (KlineConstant.PERIOD_1DAY.equals(period)) {
            klineCount = 1 * 365; // 1年的日K线,1天 * 12个月 = 540
        } else if (KlineConstant.PERIOD_1WEEK.equals(period)) {
            klineCount = 52 * 5; // 5年的1周K线 (1年52周,5年共260周)
        } else if (KlineConstant.PERIOD_1MON.equals(period)) {
            klineCount = 12 * 5; // 5年的1个月K线,12个月每年,乘以5年 = 60
        }else{
            klineCount = 2;
        }
        String resultStr = null;
        try {
            resultStr = getTradeKline(symbol, periodType, klineCount);
        } catch (Exception e) {
            logger.error("采集外汇k线图失败:{} ", e);
        }
        JSONObject resultJson = JSON.parseObject(resultStr);
        if (null == resultJson || 200 != resultJson.getInteger("ret")) {
            logger.error("采集外汇k线图失败,--"+period+"--返回:{} ", resultStr);
        }
        JSONObject tempdata = resultJson.getJSONObject("data");
        JSONArray dataArray = tempdata.getJSONArray("kline_list");
        if (dataArray.size() > 0) {
            List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
            for (AllticktradeResult result : list) {
                Kline kline = new Kline();
                kline.setSymbol(symbol);
                kline.setPeriod(period);
                // 毫秒
                kline.setTs(Long.valueOf(result.getTimestamp() + "000"));
                kline.setOpen(result.getOpen_price());
                kline.setClose(result.getClose_price());
                kline.setHigh(result.getHigh_price());
                kline.setLow(result.getLow_price());
                kline.setVolume(result.getVolume());
                resList.add(kline);
            }
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            logger.error("延时中断: {}", e);
        }
        return resList;
    }
    public List<Kline> buildOneDayPeriod(List<AllticktradeResult> list, String currency) {
        List<Kline> resList = new ArrayList<>();
        for (AllticktradeResult result : list) {
            Kline kline = new Kline();
            kline.setSymbol(currency);
            kline.setPeriod(Kline.PERIOD_1DAY);
            kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd").getTime());
            kline.setOpen(result.getOpen());
            kline.setClose(result.getClose());
            kline.setHigh(result.getHigh());
            kline.setLow(result.getLow());
            kline.setVolume(BigDecimal.ZERO);
            kline.setTs(Long.parseLong(result.getTimestamp()));
            kline.setOpen(result.getOpen_price());
            kline.setClose(result.getClose_price());
            kline.setHigh(result.getHigh_price());
            kline.setLow(result.getLow_price());
            kline.setVolume(result.getVolume());
            resList.add(kline);
        }
        return resList;
@@ -859,47 +907,35 @@
     * 4hourly 3月
     */
    public List<Kline> getTimeseriesForFourHourly(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesForFourHourly(currency);
        } else if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesForFourHourly(currency);
        }
        List<Kline> resList = new ArrayList<>();
        // 每次只能取一个月的数据,需要遍历3个月
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        // Date now = UTCDateUtils.toDate(UTCDateUtils.addHour(new Date(), -4), "yyyy-MM-dd-HH:mm");
        Date now = new Date();
        for (int i = 0; i < TraderMadeOptions.fourHourlyPeriod; i++) {
            String startDate = UTCDateUtils.addDay(now, -30);
            String endDate = f.format(now);
            now = UTCDateUtils.toDate(startDate, "yyyy-MM-dd-HH:mm");
            Map<String, String> param = new HashMap<>();
            param.put("currency", currency);
            param.put("start_date", startDate);
            param.put("end_date", endDate);
            param.put("interval", "hourly");
            param.put("period", "4");
            param.put("format", "records");
            param.put("api_key", TraderMadeOptions.apiKey);
            String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
            JSONObject resultJson = JSON.parseObject(json);
            JSONArray dataArray = resultJson.getJSONArray("quotes");
            String resultStr = null;
            try {
                resultStr = getTradeKline(currency,AllticktradeMadeOptions.fourHourPeriod,AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
                continue;
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if(null == resultJson || 200 != resultJson.getInteger("ret")){
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
                for (TimeseriesResult result : list) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_4HOUR);
                    // 毫秒
                    kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                    kline.setOpen(result.getOpen());
                    kline.setClose(result.getClose());
                    kline.setHigh(result.getHigh());
                    kline.setLow(result.getLow());
                    kline.setVolume(BigDecimal.ZERO);
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
@@ -912,44 +948,32 @@
     * 1hourly 1月
     */
    public List<Kline> getTimeseriesForOneHourly(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesForOneHourly(currency);
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesForOneHourly(currency);
        }
        List<Kline> resList = new ArrayList<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        // Date now = UTCDateUtils.toDate(UTCDateUtils.addHour(new Date(), -1), "yyyy-MM-dd-HH:mm");
        Date now = new Date();
        String startDate = UTCDateUtils.addDay(now, -30);
        String endDate = f.format(now);
        Map<String, String> param = new HashMap<>();
        param.put("currency", currency);
        param.put("start_date", startDate);
        param.put("end_date", endDate);
        param.put("interval", "hourly");
        param.put("period", "1");
        param.put("format", "records");
        param.put("api_key", TraderMadeOptions.apiKey);
        String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
        JSONObject resultJson = JSON.parseObject(json);
        JSONArray dataArray = resultJson.getJSONArray("quotes");
        String resultStr = null;
        try {
            resultStr = getTradeKline(currency,AllticktradeMadeOptions.hourPeriod,AllticktradeMadeOptions.dayKlineNumPeriod);
        } catch (Exception e) {
            logger.error("采集外汇k线图失败:{} ", e);
        }
        JSONObject resultJson = JSON.parseObject(resultStr);
        if(null == resultJson || 200 != resultJson.getInteger("ret")){
            logger.error("采集外汇k线图失败,返回:{} ", resultStr);
        }
        JSONObject tempdata = resultJson.getJSONObject("data");
        JSONArray dataArray = tempdata.getJSONArray("kline_list");
        if (dataArray.size() > 0) {
            List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
            for (TimeseriesResult result : list) {
            List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
            for (AllticktradeResult result : list) {
                Kline kline = new Kline();
                kline.setSymbol(currency);
                kline.setPeriod(Kline.PERIOD_60MIN);
                // 毫秒
                kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                kline.setOpen(result.getOpen());
                kline.setClose(result.getClose());
                kline.setHigh(result.getHigh());
                kline.setLow(result.getLow());
                kline.setVolume(BigDecimal.ZERO);
                kline.setTs(Long.parseLong(result.getTimestamp()));
                kline.setOpen(result.getOpen_price());
                kline.setClose(result.getClose_price());
                kline.setHigh(result.getHigh_price());
                kline.setLow(result.getLow_price());
                kline.setVolume(result.getVolume());
                resList.add(kline);
            }
        }
@@ -958,13 +982,38 @@
    @Override
    public List<Kline> getTimeseriesForTwoHourly(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesForTwoHourly(currency);
        List<Kline> resList = new ArrayList<>();
        String resultStr = null;
        for (int i = 0; i < TraderMadeOptions.fifteenMinutePeriod; i++) {
            try {
                resultStr = getTradeKline(currency, AllticktradeMadeOptions.towHourPeriod, AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if (null == resultJson || 200 != resultJson.getInteger("ret")) {
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_2HOUR);
                    // 毫秒
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesForTwoHourly(currency);
        }
        return Lists.newArrayList();
        return resList;
    }
    /**
@@ -975,44 +1024,35 @@
     * 1minute  1天
     */
    public List<Kline> getTimeseriesOneMinute(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesOneMinute(currency);
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesOneMinute(currency);
        }
        List<Kline> resList = new ArrayList<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        Date now = new Date();
        String startDate = UTCDateUtils.addDay(now, -1);
        String endDate = f.format(now);
        Map<String, String> param = new HashMap<>();
        param.put("currency", currency);
        param.put("start_date", startDate);
        param.put("end_date", endDate);
        param.put("interval", "minute");
        param.put("period", "1");
        param.put("format", "records");
        param.put("api_key", TraderMadeOptions.apiKey);
        String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
        JSONObject resultJson = JSON.parseObject(json);
        JSONArray dataArray = resultJson.getJSONArray("quotes");
        if (dataArray.size() > 0) {
            List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
            for (TimeseriesResult result : list) {
                Kline kline = new Kline();
                kline.setSymbol(currency);
                kline.setPeriod(Kline.PERIOD_1MIN);
                // 毫秒
                kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                kline.setOpen(result.getOpen());
                kline.setClose(result.getClose());
                kline.setHigh(result.getHigh());
                kline.setLow(result.getLow());
                kline.setVolume(BigDecimal.ZERO);
                resList.add(kline);
        String resultStr = null;
        for (int i = 0; i < TraderMadeOptions.fifteenMinutePeriod; i++) {
            try {
                resultStr = getTradeKline(currency, AllticktradeMadeOptions.minutePeriod, AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if (null == resultJson || 200 != resultJson.getInteger("ret")) {
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_1MIN);
                    // 毫秒
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
        }
        return resList;
@@ -1026,44 +1066,35 @@
     * 1minute  1天
     */
    public List<Kline> getTimeseriesFiveMinute(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesFiveMinute(currency);
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesFiveMinute(currency);
        }
        List<Kline> resList = new ArrayList<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        Date now = new Date();
        String startDate = UTCDateUtils.addDay(now, -2);
        String endDate = f.format(now);
        Map<String, String> param = new HashMap<>();
        param.put("currency", currency);
        param.put("start_date", startDate);
        param.put("end_date", endDate);
        param.put("interval", "minute");
        param.put("period", "5");
        param.put("format", "records");
        param.put("api_key", TraderMadeOptions.apiKey);
        String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
        JSONObject resultJson = JSON.parseObject(json);
        JSONArray dataArray = resultJson.getJSONArray("quotes");
        if (dataArray.size() > 0) {
            List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
            for (TimeseriesResult result : list) {
                Kline kline = new Kline();
                kline.setSymbol(currency);
                kline.setPeriod(Kline.PERIOD_5MIN);
                // 毫秒
                kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                kline.setOpen(result.getOpen());
                kline.setClose(result.getClose());
                kline.setHigh(result.getHigh());
                kline.setLow(result.getLow());
                kline.setVolume(BigDecimal.ZERO);
                resList.add(kline);
        String resultStr = null;
        for (int i = 0; i < TraderMadeOptions.fifteenMinutePeriod; i++) {
            try {
                resultStr = getTradeKline(currency, AllticktradeMadeOptions.fivePeriod, AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if (null == resultJson || 200 != resultJson.getInteger("ret")) {
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_5MIN);
                    // 毫秒
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
        }
        return resList;
@@ -1077,44 +1108,33 @@
     * 1minute  1天
     */
    public List<Kline> getTimeseriesFifteenMinute(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesFifteenMinute(currency);
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesFifteenMinute(currency);
        }
        List<Kline> resList = new ArrayList<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        Date now = new Date();
        String resultStr = null;
        for (int i = 0; i < TraderMadeOptions.fifteenMinutePeriod; i++) {
            String startDate = UTCDateUtils.addDay(now, -2);
            String endDate = f.format(now);
            now = UTCDateUtils.toDate(startDate, "yyyy-MM-dd-HH:mm");
            Map<String, String> param = new HashMap<>();
            param.put("currency", currency);
            param.put("start_date", startDate);
            param.put("end_date", endDate);
            param.put("interval", "minute");
            param.put("period", "15");
            param.put("format", "records");
            param.put("api_key", TraderMadeOptions.apiKey);
            String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
            JSONObject resultJson = JSON.parseObject(json);
            JSONArray dataArray = resultJson.getJSONArray("quotes");
            try {
                resultStr = getTradeKline(currency, AllticktradeMadeOptions.fifteenPeriod, AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if (null == resultJson || 200 != resultJson.getInteger("ret")) {
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
                for (TimeseriesResult result : list) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_15MIN);
                    // 毫秒
                    kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                    kline.setOpen(result.getOpen());
                    kline.setClose(result.getClose());
                    kline.setHigh(result.getHigh());
                    kline.setLow(result.getLow());
                    kline.setVolume(BigDecimal.ZERO);
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
@@ -1130,48 +1150,57 @@
     * 1minute  1天
     */
    public List<Kline> getTimeseriesThirtyMinute(String currency) {
        if (isXueQiu(currency)) {
            return xueQiuDataService.getTimeseriesThirtyMinute(currency);
        }
        if (isXinlang(currency)) {
            return xinLangDataService.getTimeseriesThirtyMinute(currency);
        }
        List<Kline> resList = new ArrayList<>();
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
        f.setTimeZone(TimeZone.getTimeZone(UTCDateUtils.GMT_TIME_ZONE));
        Date now = new Date();
        String resultStr = null;
        for (int i = 0; i < TraderMadeOptions.thirtyMinutePeriod; i++) {
            String startDate = UTCDateUtils.addDay(now, -2);
            String endDate = f.format(now);
            now = UTCDateUtils.toDate(startDate, "yyyy-MM-dd-HH:mm");
            Map<String, String> param = new HashMap<>();
            param.put("currency", currency);
            param.put("start_date", startDate);
            param.put("end_date", endDate);
            param.put("interval", "minute");
            param.put("period", "15");
            param.put("format", "records");
            param.put("api_key", TraderMadeOptions.apiKey);
            String json = HttpHelper.getJSONFromHttpNew(TraderMadeOptions.timeseries, param, HttpMethodType.GET);
            JSONObject resultJson = JSON.parseObject(json);
            JSONArray dataArray = resultJson.getJSONArray("quotes");
            try {
                resultStr = getTradeKline(currency,AllticktradeMadeOptions.thirtyPeriod,AllticktradeMadeOptions.dayKlineNumPeriod);
            } catch (Exception e) {
                logger.error("采集外汇k线图失败:{} ", e);
            }
            JSONObject resultJson = JSON.parseObject(resultStr);
            if(null == resultJson || 200 != resultJson.getInteger("ret")){
                logger.error("采集外汇k线图失败,返回:{} ", resultStr);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<TimeseriesResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), TimeseriesResult.class);
                for (TimeseriesResult result : list) {
                List<AllticktradeResult> list = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AllticktradeResult.class);
                for (AllticktradeResult result : list) {
                    Kline kline = new Kline();
                    kline.setSymbol(currency);
                    kline.setPeriod(Kline.PERIOD_30MIN);
                    // 毫秒
                    kline.setTs(UTCDateUtils.toDate(result.getDate(), "yyyy-MM-dd HH:mm").getTime());
                    kline.setOpen(result.getOpen());
                    kline.setClose(result.getClose());
                    kline.setHigh(result.getHigh());
                    kline.setLow(result.getLow());
                    kline.setVolume(BigDecimal.ZERO);
                    kline.setTs(Long.parseLong(result.getTimestamp()));
                    kline.setOpen(result.getOpen_price());
                    kline.setClose(result.getClose_price());
                    kline.setHigh(result.getHigh_price());
                    kline.setLow(result.getLow_price());
                    kline.setVolume(result.getVolume());
                    resList.add(kline);
                }
            }
        }
        return resList;
    }
    public String getTradeKline(String symbol,int type,int num){
        JSONObject json = new JSONObject();
        json.put("trace", UUID.randomUUID().toString());
        JSONObject data = new JSONObject();
        data.put("code", symbol);
        data.put("kline_type", type);
        data.put("kline_timestamp_end", 0);
        data.put("query_kline_num", num);
        json.put("data", data);
        try {
            String url = tradeKline.replace("{1}", URLEncoder.encode(json.toString(), "UTF-8"));
            HttpGet request = new HttpGet(url);
            HttpResponse response = HttpHelper.getHttpclient().execute(request);
            return HttpHelper.responseProc(response);
        } catch (Exception e) {
            logger.error("采集外汇k线图失败:{} ", e);
        }
        return null;
    }
}
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java
@@ -4,16 +4,22 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.yami.trading.bean.cms.Infomation;
import com.yami.trading.bean.data.domain.*;
import com.yami.trading.bean.data.respDto.TradeTickResp;
import com.yami.trading.common.util.RedisUtil;
import com.yami.trading.common.util.StringUtils;
import com.yami.trading.common.util.UTCDateUtils;
import com.yami.trading.huobi.data.DataCache;
import com.yami.trading.huobi.data.internal.DepthTimeObject;
import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.huobi.data.internal.TradeTimeObject;
import com.yami.trading.huobi.data.model.AlltickBatchKlineResult;
import com.yami.trading.huobi.data.model.AlltickNewPriceResult;
import com.yami.trading.huobi.data.model.AllticktradeResult;
import com.yami.trading.huobi.hobi.http.HttpHelper;
import com.yami.trading.huobi.hobi.http.HttpMethodType;
import com.yami.trading.service.cms.InfomationService;
@@ -24,15 +30,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
@@ -55,6 +60,7 @@
     */
//    public final static String live = "https://hq.sinajs.cn/rn={1}list={2}";//todo 要调整
    public final static String live = "https://hq.sinajs.cn/etag.php?_={1}&list={2}";//todo 要调整
    public final static String live_tick = "https://quote.alltick.io/quote-b-api/kline?token={1}&query={2}";
    private static Logger logger = LoggerFactory.getLogger(XinLangDataServiceImpl.class);
@@ -64,10 +70,15 @@
    @Autowired
    private ItemService itemService;
    @Value("${alltick.trade-tick}")
    private String tradeTick;
    @Value("${alltick.batch-kline}")
    private String batchKline;
    public static void main(String[] args) {
        XinLangDataServiceImpl service = new XinLangDataServiceImpl();
        List<Realtime> usdsgd = service.realtimeSingle("USDSGD");
        List<Realtime> usdsgd = service.realtimeSingle("USDJPY");
        for (Realtime re : usdsgd) {
            System.out.println(JSONObject.toJSONString(re));
        }
@@ -76,8 +87,57 @@
//        List<Kline> eurusd = service.getTimeseriesByPeriodOneDay("EURUSD");
//        System.out.println(JSONObject.toJSONString(eurusd));
    }
    public Map<String, Object> createRequest(List<String> strings) {
        Map<String, Object> requestData = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (String symbolCode : strings) {
            for (int i = 1; i <= 3; i++) {
                Map<String, Object> dataItem = new HashMap<>();
                dataItem.put("code", symbolCode);
                dataItem.put("kline_type", i);
                dataItem.put("kline_timestamp_end", 0);
                dataItem.put("query_kline_num", 1);
                dataList.add(dataItem);
            }
        }
        data.put("data_list", dataList);
        requestData.put("trace", UUID.randomUUID().toString());
        requestData.put("data", data);
        return requestData;
    }
    public Map<String, Object> createRequestTick(List<String> strings) {
        // 创建 JSON 对象
        JSONObject response = new JSONObject();
        response.put("trace", UUID.randomUUID().toString());
        // 创建数据部分
        JSONObject dataObject = new JSONObject();
        JSONArray symbolList = new JSONArray();
        // 构造符号列表
        for (String code : strings) {
            JSONObject symbol = new JSONObject();
            symbol.put("code", code);
            symbolList.add(symbol);
        }
        dataObject.put("symbol_list", symbolList);
        response.put("data", dataObject);
        return response;
    }
    public Map<String, Object> createRequestZdf(String symbolCode) {
        JSONObject json = new JSONObject();
        json.put("trace", UUID.randomUUID().toString());
        JSONObject data = new JSONObject();
        data.put("code", symbolCode);
        data.put("kline_type", 8);
        data.put("kline_timestamp_end", 0);
        data.put("query_kline_num", 2);
        json.put("data", data);
        return json;
    }
    /**
     * 获取原始的K线图数据
     *
@@ -92,49 +152,80 @@
        return HttpHelper.sendGetHttp(url, null, cookie);
    }
    public List<Realtime> realtimeNewPrice(String symbols,List<Realtime> realtimes) {
        //获取最新价
        try{
            List<String> strings = Arrays.asList(symbols.split(","));
            Map<String, Object> requestDataTick = createRequestTick(strings);
            String url = tradeTick.replace("{1}", URLEncoder.encode(requestDataTick.toString(), "UTF-8"));
            HttpGet request = new HttpGet(url);
            HttpResponse response = HttpHelper.getHttpclient().execute(request);
            String resultTickStr = HttpHelper.responseProc(response);
            JSONObject resultJsonTick = JSON.parseObject(resultTickStr);
            if(null == resultJsonTick || 200 != resultJsonTick.getInteger("ret")){
                logger.error("数据,返回:{} ", resultJsonTick);
            }
            JSONObject tempdataTick = resultJsonTick.getJSONObject("data");
            JSONArray dataArrayTick = tempdataTick.getJSONArray("tick_list");
            if (dataArrayTick.size() > 0) {
                List<AlltickNewPriceResult> alltickNewPriceResults = JSONObject.parseArray(JSONObject.toJSONString(dataArrayTick), AlltickNewPriceResult.class);
                for (AlltickNewPriceResult tickNewPrice : alltickNewPriceResults) {
                    for (Realtime realtime : realtimes){
                        if(tickNewPrice.getCode().equals(realtime.getName())){
                            realtime.setCloseOld(realtime.getClose());
                            realtime.setClose(new BigDecimal(tickNewPrice.getPrice()));
                            realtime.setVolume(new BigDecimal(tickNewPrice.getVolume()));
                        }
                    }
                }
            }
        } catch (Exception e){
            logger.error("error", e);
        }
        for (Realtime realtime : realtimes) {
            if(realtime.getName().equals("USDSGD")){
                System.out.println("USDSGD实时价格数据替换前=="+realtime.getCloseOld());
                System.out.println("USDSGD实时价格数据替换后=="+realtime.getClose());
            }
        }
        return realtimes;
    }
    public List<Realtime> realtimeSingle(String symbols) {
        List<Realtime> list = new ArrayList<Realtime>();
        try {
            List<String> strings = Arrays.asList(symbols.split(","));
            for (String symbol: strings) {
                String url = live.replace("{1}",System.currentTimeMillis()+"").replace("{2}", "fx_s"+symbol.toLowerCase());
                HttpGet request = new HttpGet(url);
                request.addHeader("Referer","https://finance.sina.com.cn");
                request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36");
                HttpResponse response = HttpHelper.getHttpclient().execute(request);
                String result = HttpHelper.responseProc(response);
                int firstQuoteIndex = result.indexOf("\"");
                int secondQuoteIndex = result.indexOf("\"", firstQuoteIndex + 1);
                String extractedString = result.substring(firstQuoteIndex + 1, secondQuoteIndex);
                if(extractedString.split(",").length != 18){
                    return list;
            Map<String, Object> requestData = createRequest(strings);
            String resultStr = HttpHelper.sendPostRequest(batchKline,requestData);
            JSONObject resultJson = JSON.parseObject(resultStr);
            if(null == resultJson || 200 != resultJson.getInteger("ret")){
                logger.error("数据,返回:{} ", resultJson);
            }
            JSONObject tempdata = resultJson.getJSONObject("data");
            JSONArray dataArray = tempdata.getJSONArray("kline_list");
            if (dataArray.size() > 0) {
                List<AlltickBatchKlineResult> batchKlines = JSONObject.parseArray(JSONObject.toJSONString(dataArray), AlltickBatchKlineResult.class);
                for (AlltickBatchKlineResult batchKline : batchKlines) {
                    for (AllticktradeResult result : batchKline.getKline_data()){
                        Realtime realtime = new Realtime();
                        int decimal = itemService.getDecimal(batchKline.getCode());
                        realtime.setSymbol(batchKline.getCode());
                        realtime.setTs(Long.parseLong(result.getTimestamp()));
                        realtime.setName(batchKline.getCode());
                        realtime.setOpen(result.getOpen_price().setScale(decimal, RoundingMode.HALF_UP));
                        realtime.setHigh(result.getHigh_price().setScale(decimal, RoundingMode.HALF_UP));
                        realtime.setLow(result.getLow_price().setScale(decimal, RoundingMode.HALF_UP));
                        realtime.setClose(result.getClose_price().setScale(decimal, RoundingMode.HALF_UP));
                        realtime.setMarketCapital(0L);
                        realtime.setFloatMarketCapital(0L);
                        realtime.setPeForecast(BigDecimal.ZERO);
                        realtime.setVolumeRatio(BigDecimal.ZERO);
                        realtime.setTurnoverRate(BigDecimal.ZERO);
                        realtime.setAmount(result.getVolume());
                        realtime.setVolume(result.getTurnover());
                        list.add(realtime);
                    }
                }
                String[] split = extractedString.split(",");
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = sdf.parse(split[17]+" " +split[0]);
                long timestamp = date.getTime();
                Realtime realtime = new Realtime();
                int decimal = itemService.getDecimal(symbol);
                realtime.setSymbol(symbol);
                realtime.setTs(timestamp);
                realtime.setName(symbol);
                realtime.setOpen(BigDecimal.valueOf(Double.parseDouble(split[5])).setScale(decimal, RoundingMode.HALF_UP));
                realtime.setHigh(BigDecimal.valueOf(Double.parseDouble(split[6])).setScale(decimal, RoundingMode.HALF_UP));
                realtime.setLow(BigDecimal.valueOf(Double.parseDouble(split[7])).setScale(decimal, RoundingMode.HALF_UP));
                if(StringUtils.isNotEmpty(split[1])){
                    realtime.setClose(BigDecimal.valueOf(Double.parseDouble(split[1])).setScale(decimal, RoundingMode.HALF_UP));
                }else{
                    realtime.setClose(BigDecimal.valueOf(Double.parseDouble(split[7])).setScale(decimal, RoundingMode.HALF_UP));
                }
                realtime.setMarketCapital(0L);
                realtime.setFloatMarketCapital(0L);
                realtime.setPeForecast(BigDecimal.ZERO);
                realtime.setVolumeRatio(BigDecimal.ZERO);
                realtime.setTurnoverRate(BigDecimal.ZERO);
                realtime.setAmount(BigDecimal.ZERO);
                realtime.setVolume(BigDecimal.ZERO);
                list.add(realtime);
            }
        } catch (Exception e) {
            logger.error("error", e);