From 038c7e5b9c8338103496d40ffb0122b3f61a5185 Mon Sep 17 00:00:00 2001
From: zyy <zyy@email.com>
Date: Fri, 29 May 2026 12:19:47 +0800
Subject: [PATCH] 1

---
 trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/RemoteDataServiceImpl.java |  106 +++++-------
 trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java            |   48 +++--
 trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java      |  198 +++++++++++++++++++++++-
 trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java     |  113 ++++++++++---
 4 files changed, 348 insertions(+), 117 deletions(-)

diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java
index e9e9936..082e20c 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java
@@ -129,24 +129,24 @@
 
     private List<Map<String, Object>> build(List<Kline> data, String line, String symbol) {
         Collections.sort(data);
+        // 相同时间戳保留最新一条(进行中K线会覆盖缓存中的旧数据)
+        Map<Long, Kline> latestByTs = new LinkedHashMap<>();
+        for (Kline kline : data) {
+            latestByTs.put(kline.getTs(), kline);
+        }
+        data = new ArrayList<>(latestByTs.values());
+        Collections.sort(data);
         int len = data.size();
         for (int i = 1; i < len; i++) {
             data.get(i).setOpen(data.get(i - 1).getClose());
         }
 
-
-        Set<Long> tsSet = new HashSet<Long>();
         List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
         Item bySymbol = itemService.findBySymbol(symbol);
 
         for (int i = 0; i < data.size(); i++) {
             Kline kline = data.get(i);
             Long ts = kline.getTs();
-            if (tsSet.contains(ts)) {
-                continue;
-            } else {
-                tsSet.add(ts);
-            }
             String fake = bySymbol.getFake();
             //	if("1".equalsIgnoreCase(fake)){
             //		klineService.smoothlyKline(kline, 0.99);
@@ -181,20 +181,32 @@
             map.put("low", low.setScale(decimal, RoundingMode.HALF_UP));
             map.put("volume", kline.getVolume());
 
-            //if (line.equalsIgnoreCase(Kline.PERIOD_15MIN) || line.equalsIgnoreCase(Kline.PERIOD_30MIN) || line.equalsIgnoreCase(Kline.PERIOD_60MIN)) {
-                if (i == data.size() - 1) {
-                    //获取当前价格
-                    Realtime realtime = DataCache.getLatestRealTime(symbol);
-                    if (realtime != null) {
-                        map.put("close", realtime.getClose().setScale(decimal, RoundingMode.HALF_UP));
+            if (i == data.size() - 1) {
+                Realtime realtime = DataCache.getLatestRealTime(symbol);
+                if (realtime != null && realtime.getClose() != null) {
+                    close = realtime.getClose();
+                    map.put("close", close.setScale(decimal, RoundingMode.HALF_UP));
+                    if (close.compareTo(high) > 0) {
+                        high = close;
                     }
-                    BeforeClose beforeClose = dataDBService.getBeforeClose(kline.getSymbol(), line, ts, realtime);
-                    if (beforeClose != null) {
-                        map.put("high", beforeClose.getMaxClose().setScale(decimal, RoundingMode.HALF_UP));
-                        map.put("low", beforeClose.getMinClose().setScale(decimal, RoundingMode.HALF_UP));
+                    if (close.compareTo(low) < 0) {
+                        low = close;
                     }
                 }
-            //}
+                BeforeClose beforeClose = dataDBService.getBeforeClose(kline.getSymbol(), line, ts, realtime);
+                if (beforeClose != null) {
+                    if (beforeClose.getMaxClose() != null
+                            && beforeClose.getMaxClose().compareTo(BigDecimal.ZERO) > 0) {
+                        high = beforeClose.getMaxClose();
+                    }
+                    if (beforeClose.getMinClose() != null
+                            && beforeClose.getMinClose().compareTo(BigDecimal.ZERO) > 0) {
+                        low = beforeClose.getMinClose();
+                    }
+                }
+                map.put("high", high.setScale(decimal, RoundingMode.HALF_UP));
+                map.put("low", low.setScale(decimal, RoundingMode.HALF_UP));
+            }
             list.add(map);
         }
         return list;
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java
index 45112bb..bfe29df 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/DataDBServiceImpl.java
@@ -146,43 +146,96 @@
         BeforeClose beforeClose = (BeforeClose) redisTemplate.opsForValue().get(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line);
         //超出时间重新计算
         if (beforeClose == null || ts > beforeClose.getTs()) {
-            // 直接获取当前时间的毫秒级时间戳(系统默认时区,但值是全球统一的)
-            long currentTimeStamp = System.currentTimeMillis();
-
-            // 如果需要严格基于东京时区的当前时间戳(结果和上面一致,因为时间戳是UTC绝对时间)
-            //long currentTokyoTimeStamp = Instant.now().atZone(ZoneId.of("America/New_York")).toInstant().toEpochMilli();
-            RequestDataHelper.set("symbol", symbol);
-            QueryWrapper<Realtime> queryWrapper = new QueryWrapper<Realtime>()
-                    .eq("symbol", symbol) // 直接写数据库字段名(需和表字段一致)
-                    .ge("ts", ts)
-                    .le("ts", currentTimeStamp)
-                    .select("MAX(CAST(close AS DECIMAL(10,4))) as maxClose",
-                            "MIN(CAST(close AS DECIMAL(10,4))) as minClose");
-            // 4. 执行聚合查询,用selectMap接收结果(键值对:maxClose/minClose -> 对应值)
-            Map<String, Object> resultMap = realtimeService.getMap(queryWrapper);
-            RequestDataHelper.clear();
-            beforeClose = new BeforeClose();
-            if (resultMap == null || resultMap.isEmpty()) {
-                return beforeClose;
+            beforeClose = calcBeforeClose(symbol, line, ts);
+            if (beforeClose.getMaxClose().compareTo(BigDecimal.ZERO) > 0) {
+                redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose);
             }
-            beforeClose.setMaxClose(convertToBigDecimal(resultMap.get("maxClose")));
-            beforeClose.setMinClose(convertToBigDecimal(resultMap.get("minClose")));
-            beforeClose.setTs(ts);
+        }
+
+        if (realtime != null && realtime.getClose() != null) {
+            if (beforeClose.getMaxClose() == null || beforeClose.getMaxClose().compareTo(BigDecimal.ZERO) <= 0) {
+                beforeClose.setMaxClose(realtime.getClose());
+            } else if (realtime.getClose().compareTo(beforeClose.getMaxClose()) > 0) {
+                beforeClose.setMaxClose(realtime.getClose());
+            }
+            if (beforeClose.getMinClose() == null || beforeClose.getMinClose().compareTo(BigDecimal.ZERO) <= 0) {
+                beforeClose.setMinClose(realtime.getClose());
+            } else if (realtime.getClose().compareTo(beforeClose.getMinClose()) < 0) {
+                beforeClose.setMinClose(realtime.getClose());
+            }
             redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose);
         }
+        return beforeClose;
+    }
 
-
-        if (realtime != null) {
-            if (realtime.getClose().compareTo(beforeClose.getMaxClose()) > 0) {
-                beforeClose.setMaxClose(realtime.getClose());
-                redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose);
+    private BeforeClose calcBeforeClose(String symbol, String line, Long ts) {
+        BeforeClose beforeClose = new BeforeClose();
+        beforeClose.setTs(ts);
+        int interval = sysparaService.find("data_interval").getInteger() / 1000;
+        if (interval <= 0) {
+            interval = 1;
+        }
+        HighLow highLow = null;
+        switch (line) {
+            case Kline.PERIOD_1MIN:
+                highLow = HighLowHandle.get(symbol, 60 / interval, interval);
+                break;
+            case Kline.PERIOD_5MIN:
+                highLow = HighLowHandle.get(symbol, (60 * 5) / interval, interval);
+                break;
+            case Kline.PERIOD_15MIN:
+                highLow = HighLowHandle.get(symbol, (60 * 15) / interval, interval);
+                break;
+            case Kline.PERIOD_30MIN:
+                highLow = HighLowHandle.get(symbol, (60 * 30) / interval, interval);
+                break;
+            case Kline.PERIOD_60MIN:
+                highLow = HighLowHandle.get(symbol, (60 * 60) / interval, interval);
+                break;
+            case Kline.PERIOD_4HOUR:
+                highLow = HighLowHandle.get(symbol, (60 * 60 * 4) / interval, interval);
+                break;
+            case Kline.PERIOD_1DAY:
+                highLow = HighLowHandle.get(symbol, (60 * 60 * 24) / interval, interval);
+                break;
+            case Kline.PERIOD_1WEEK:
+                highLow = HighLowHandle.getByDay(symbol, 7);
+                break;
+            case Kline.PERIOD_1MON:
+                highLow = HighLowHandle.getByDay(symbol, 30);
+                break;
+            default:
+                break;
+        }
+        if (highLow != null && highLow.getHigh() != null) {
+            beforeClose.setMaxClose(highLow.getHigh());
+        }
+        if (highLow != null && highLow.getLow() != null) {
+            beforeClose.setMinClose(highLow.getLow());
+        }
+        if (beforeClose.getMaxClose().compareTo(BigDecimal.ZERO) > 0) {
+            return beforeClose;
+        }
+        long currentTimeStamp = System.currentTimeMillis();
+        RequestDataHelper.set("symbol", symbol);
+        QueryWrapper<Realtime> queryWrapper = new QueryWrapper<Realtime>()
+                .eq("symbol", symbol)
+                .ge("ts", ts)
+                .le("ts", currentTimeStamp)
+                .select("MAX(CAST(close AS DECIMAL(10,4))) as maxClose",
+                        "MIN(CAST(close AS DECIMAL(10,4))) as minClose");
+        Map<String, Object> resultMap = realtimeService.getMap(queryWrapper);
+        RequestDataHelper.clear();
+        if (resultMap != null && !resultMap.isEmpty()) {
+            BigDecimal maxClose = convertToBigDecimal(resultMap.get("maxClose"));
+            BigDecimal minClose = convertToBigDecimal(resultMap.get("minClose"));
+            if (maxClose.compareTo(BigDecimal.ZERO) > 0) {
+                beforeClose.setMaxClose(maxClose);
             }
-            if (realtime.getClose().compareTo(beforeClose.getMinClose()) < 0) {
-                beforeClose.setMinClose(realtime.getClose());
-                redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose);
+            if (minClose.compareTo(BigDecimal.ZERO) > 0) {
+                beforeClose.setMinClose(minClose);
             }
         }
-        System.out.println("realtime.getClose():" + realtime.getClose() + "==" + beforeClose);
         return beforeClose;
     }
 
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java
index 52a25de..83f5b4b 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/KlineServiceImpl.java
@@ -29,6 +29,9 @@
 import java.math.RoundingMode;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -180,6 +183,165 @@
 
 
     public Kline buildKline(String symbol, String line, String smallLevelLine, int nums) {
+        if (Kline.PERIOD_5DAY.equals(line)) {
+            return buildKlineLegacy(symbol, line, smallLevelLine, nums);
+        }
+        return buildInProgressKline(symbol, line, smallLevelLine);
+    }
+
+    /**
+     * 按当前周期起点拼接进行中的K线(ts 对齐到周期开盘时间,如 5 分钟线的 9:35)
+     */
+    private Kline buildInProgressKline(String symbol, String line, String smallLevelLine) {
+        try {
+            KlineTimeObject timeObject = DataCache.getKline(symbol, line);
+            if (timeObject == null) {
+                return null;
+            }
+            List<Kline> klineList = timeObject.getKline();
+            Item item = itemService.findBySymbol(symbol);
+            Kline latestSameLineKline = null;
+            if (klineList != null && !klineList.isEmpty()) {
+                latestSameLineKline = klineList.get(klineList.size() - 1);
+            } else if (item.getFake().equalsIgnoreCase("0")) {
+                return null;
+            }
+
+            Realtime latestRealtime = DataCache.getLatestRealTime(symbol);
+            if (latestRealtime == null) {
+                latestRealtime = DataCache.getRealtime(symbol);
+            }
+            if (latestRealtime == null || latestRealtime.getClose() == null) {
+                return null;
+            }
+
+            long currentPeriodTs = alignPeriodStartTs(line, latestRealtime.getTs());
+            if (latestSameLineKline != null && latestSameLineKline.getTs() != null
+                    && latestSameLineKline.getTs() > currentPeriodTs) {
+                return null;
+            }
+
+            KlineTimeObject smallObject = DataCache.getKline(symbol, smallLevelLine);
+            List<Kline> periodBars = new ArrayList<>();
+            if (smallObject != null && smallObject.getKline() != null) {
+                periodBars = smallObject.getKline().stream()
+                        .filter(k -> k.getTs() != null && k.getTs() >= currentPeriodTs)
+                        .collect(Collectors.toList());
+            }
+
+            Kline kline = new Kline();
+            kline.setSymbol(symbol);
+            kline.setPeriod(line);
+            kline.setTs(currentPeriodTs);
+
+            if (latestSameLineKline != null && latestSameLineKline.getTs() != null
+                    && latestSameLineKline.getTs() < currentPeriodTs) {
+                kline.setOpen(latestSameLineKline.getClose());
+            } else if (!periodBars.isEmpty() && periodBars.get(0).getOpen() != null) {
+                kline.setOpen(periodBars.get(0).getOpen());
+            } else if (latestRealtime.getOpen() != null) {
+                kline.setOpen(latestRealtime.getOpen());
+            } else {
+                kline.setOpen(latestRealtime.getClose());
+            }
+
+            if (!periodBars.isEmpty()) {
+                Double high = null;
+                Double low = null;
+                for (Kline bar : periodBars) {
+                    if (bar.getHigh() != null) {
+                        if (high == null || high <= bar.getHigh().doubleValue()) {
+                            high = bar.getHigh().doubleValue();
+                        }
+                    }
+                    if (bar.getLow() != null) {
+                        if (low == null || low >= bar.getLow().doubleValue()) {
+                            low = bar.getLow().doubleValue();
+                        }
+                    }
+                }
+                kline.setHigh(high == null ? latestRealtime.getClose() : new BigDecimal(high));
+                kline.setLow(low == null ? latestRealtime.getClose() : new BigDecimal(low));
+                kline.setClose(periodBars.get(periodBars.size() - 1).getClose());
+                kline.setVolume(periodBars.stream()
+                        .map(Kline::getVolume)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add));
+                kline.setAmount(periodBars.stream()
+                        .map(Kline::getAmount)
+                        .filter(Objects::nonNull)
+                        .reduce(BigDecimal.ZERO, BigDecimal::add));
+            } else {
+                kline.setHigh(latestRealtime.getClose());
+                kline.setLow(latestRealtime.getClose());
+                kline.setClose(latestRealtime.getClose());
+                kline.setVolume(latestRealtime.getVolume());
+                kline.setAmount(latestRealtime.getAmount());
+            }
+
+            kline.setClose(latestRealtime.getClose());
+            if (latestRealtime.getClose().compareTo(kline.getHigh()) > 0) {
+                kline.setHigh(latestRealtime.getClose());
+            }
+            if (latestRealtime.getClose().compareTo(kline.getLow()) < 0) {
+                kline.setLow(latestRealtime.getClose());
+            }
+
+            repairKline(kline);
+            if (kline.getOpen().compareTo(BigDecimal.ZERO) == 0 || kline.getClose().compareTo(BigDecimal.ZERO) == 0) {
+                return null;
+            }
+            return kline;
+        } catch (Exception e) {
+            logger.error("buildInProgressKline error: {}, {}", symbol, line, e);
+        }
+        return null;
+    }
+
+    /**
+     * 将时间戳对齐到K线周期起点(UTC,与火币 id 字段一致)
+     * 1week:周一 00:00 UTC;1mon:每月 1 日 00:00 UTC
+     */
+    private long alignPeriodStartTs(String line, long tsMillis) {
+        ZonedDateTime zdt = Instant.ofEpochMilli(tsMillis).atZone(ZoneOffset.UTC);
+        switch (line) {
+            case Kline.PERIOD_1MIN:
+                return zdt.withSecond(0).withNano(0).toInstant().toEpochMilli();
+            case Kline.PERIOD_5MIN: {
+                int minute = zdt.getMinute();
+                return zdt.withMinute(minute - minute % 5).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            }
+            case Kline.PERIOD_15MIN: {
+                int minute = zdt.getMinute();
+                return zdt.withMinute(minute - minute % 15).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            }
+            case Kline.PERIOD_30MIN: {
+                int minute = zdt.getMinute();
+                return zdt.withMinute(minute - minute % 30).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            }
+            case Kline.PERIOD_60MIN:
+                return zdt.withMinute(0).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            case Kline.PERIOD_1DAY:
+                return zdt.withHour(0).withMinute(0).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            case Kline.PERIOD_1WEEK: {
+                zdt = zdt.withHour(0).withMinute(0).withSecond(0).withNano(0);
+                int dayOfWeek = zdt.getDayOfWeek().getValue();
+                return zdt.minusDays(dayOfWeek - 1L).toInstant().toEpochMilli();
+            }
+            case Kline.PERIOD_1MON:
+                return zdt.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            case Kline.PERIOD_2HOUR:
+                return zdt.withMinute(0).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            case Kline.PERIOD_4HOUR: {
+                int hour = zdt.getHour();
+                return zdt.withHour(hour - hour % 4).withMinute(0).withSecond(0).withNano(0).toInstant().toEpochMilli();
+            }
+            default:
+                return zdt.withSecond(0).withNano(0).toInstant().toEpochMilli();
+        }
+    }
+
+    private Kline buildKlineLegacy(String symbol, String line, String smallLevelLine, int nums) {
         try {
             // 取5分钟K线全部数据集合
             KlineTimeObject timeObject = DataCache.getKline(symbol, line);
@@ -211,14 +373,27 @@
             if (realtimeKline == null) {
                 return null;
             }
-            if (latestSameLineKline != null && latestSameLineKline.getTs() >= realtimeKline.getTs()) {
+            if (latestSameLineKline != null && latestSameLineKline.getTs() > realtimeKline.getTs()) {
                 return null;
             }
             if (latestSameLineKline != null) {
                 long latestSameLineKlineTs = latestSameLineKline.getTs();
-                klineOneTop5 = klineOneTop5.stream().filter(r -> r.getTs() > latestSameLineKlineTs).collect(Collectors.toList());
+                if (latestSameLineKlineTs == realtimeKline.getTs()) {
+                    klineOneTop5 = klineOne.stream()
+                            .filter(r -> r.getTs() >= latestSameLineKlineTs)
+                            .collect(Collectors.toList());
+                    if (klineOneTop5.size() > nums) {
+                        klineOneTop5 = new ArrayList<>(klineOneTop5.subList(klineOneTop5.size() - nums, klineOneTop5.size()));
+                    }
+                } else {
+                    klineOneTop5 = klineOneTop5.stream()
+                            .filter(r -> r.getTs() > latestSameLineKlineTs)
+                            .collect(Collectors.toList());
+                }
             }
-
+            if (klineOneTop5.isEmpty()) {
+                return null;
+            }
 
             Double high = null;
             Double low = null;
@@ -673,11 +848,16 @@
                 latestKilne = klineList.get(klineList.size() - 1);
             }
             Realtime realtime = realTimeList.get(realTimeList.size() - 1);
-            if (latestKilne != null && latestKilne.getTs() >= realtime.getTs()) {
+            long currentMinuteTs = alignPeriodStartTs(Kline.PERIOD_1MIN, realtime.getTs());
+            if (latestKilne != null && latestKilne.getTs() != null && latestKilne.getTs() > currentMinuteTs) {
                 return null;
             }
-            long lastKlineTs = latestKilne.getTs();
-            realTimeList = realTimeList.stream().filter(r -> r.getTs() > lastKlineTs).collect(Collectors.toList());
+            realTimeList = realTimeList.stream()
+                    .filter(r -> r.getTs() != null && r.getTs() >= currentMinuteTs)
+                    .collect(Collectors.toList());
+            if (realTimeList.isEmpty()) {
+                realTimeList = Collections.singletonList(realtime);
+            }
             Double high = null;
             Double low = null;
             for (Realtime realTime : realTimeList) {
@@ -692,11 +872,11 @@
             // 保存K线到数据库
             Kline kline = new Kline();
             kline.setSymbol(symbol);
-            kline.setTs(realtime.getTs());
-            if (latestKilne != null) {
+            kline.setTs(currentMinuteTs);
+            if (latestKilne != null && latestKilne.getTs() != null && latestKilne.getTs() < currentMinuteTs) {
                 kline.setOpen(latestKilne.getClose());
             } else {
-                kline.setOpen(realTimeList.get(0).getOpen());
+                kline.setOpen(realTimeList.get(0).getOpen() != null ? realTimeList.get(0).getOpen() : realtime.getClose());
             }
             kline.setHigh(new BigDecimal(high));
             kline.setLow(new BigDecimal(low));
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/RemoteDataServiceImpl.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/RemoteDataServiceImpl.java
index 785ae72..c97d876 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/RemoteDataServiceImpl.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/internal/RemoteDataServiceImpl.java
@@ -73,10 +73,6 @@
 
     @Override
     public List<Kline> kline(String symbol, String line) {
-        Item bySymbol = itemService.findBySymbol(symbol);
-        if(Item.cryptos.equals(bySymbol.getType())){
-            return klineCryptos(symbol, line);
-        }
         KlineTimeObject timeObject = DataCache.getKline(symbol, line);
         List<Kline> list = new ArrayList<Kline>();
         if (timeObject != null) {
@@ -85,7 +81,7 @@
         List<Kline> list_clone = new ArrayList<Kline>();
         try {
             for (int i = 0; i < list.size(); i++) {
-                if(list.get(i) == null){
+                if (list.get(i) == null) {
                     continue;
                 }
                 Kline kline = (Kline) list.get(i).clone();
@@ -96,71 +92,61 @@
         }
 
         Realtime realtime = DataCache.getLatestRealTime(symbol);
-        if (realtime != null) {
-            Kline kline = null;
-            if (KlineConstant.PERIOD_1MIN.equals(line)) {
-                kline = klineService.bulidKline1Minute(realtime, KlineConstant.PERIOD_1MIN);
-            } else if (KlineConstant.PERIOD_5MIN.equals(line)) {
-                kline = klineService.bulidKline5Minute(realtime, KlineConstant.PERIOD_5MIN);
-            } else if (KlineConstant.PERIOD_15MIN.equals(line)) {
-                kline = klineService.bulidKline15Minute(realtime, KlineConstant.PERIOD_15MIN);
-            } else if (KlineConstant.PERIOD_30MIN.equals(line)) {
-                kline = klineService.bulidKline30Minute(realtime, KlineConstant.PERIOD_30MIN);
-            } else if (KlineConstant.PERIOD_60MIN.equals(line)) {
-                kline = klineService.bulidKline60Minute(realtime, KlineConstant.PERIOD_60MIN);
-            } else if (KlineConstant.PERIOD_4HOUR.equals(line)) {
-                kline = klineService.bulidKline4Hour(realtime, KlineConstant.PERIOD_4HOUR);
-            } else if (KlineConstant.PERIOD_1DAY.equals(line)) {
-                kline = klineService.bulidKline1Day(realtime, KlineConstant.PERIOD_1DAY);
-            } else if (KlineConstant.PERIOD_5DAY.equals(line)) {
-                kline = klineService.bulidKline5Day(realtime, KlineConstant.PERIOD_5DAY);
-            } else if (KlineConstant.PERIOD_1WEEK.equals(line)) {
-                kline = klineService.bulidKline1Week(realtime, KlineConstant.PERIOD_1WEEK);
-            } else if (KlineConstant.PERIOD_1MON.equals(line)) {
-                kline = klineService.bulidKline1Mon(realtime, KlineConstant.PERIOD_1MON);
-            } else if (KlineConstant.PERIOD_QUARTER.equals(line)) {
-                kline = klineService.bulidKline1Mon(realtime, KlineConstant.PERIOD_QUARTER);
-            } else if (KlineConstant.PERIOD_YEAR.equals(line)) {
-                kline = klineService.bulidKline1Mon(realtime, KlineConstant.PERIOD_YEAR);
-            }
-            if (null != kline) {
-                list_clone.add(kline);
-            }
+        if (realtime == null) {
+            realtime = DataCache.getRealtime(symbol);
         }
-        // 按时间升序
+        if (realtime != null) {
+            appendOrReplaceKline(list_clone, buildCurrentKline(realtime, line));
+        }
         Collections.sort(list_clone);
         return list_clone;
+    }
 
+    private Kline buildCurrentKline(Realtime realtime, String line) {
+        if (KlineConstant.PERIOD_1MIN.equals(line)) {
+            return klineService.bulidKline1Minute(realtime, KlineConstant.PERIOD_1MIN);
+        } else if (KlineConstant.PERIOD_5MIN.equals(line)) {
+            return klineService.bulidKline5Minute(realtime, KlineConstant.PERIOD_5MIN);
+        } else if (KlineConstant.PERIOD_15MIN.equals(line)) {
+            return klineService.bulidKline15Minute(realtime, KlineConstant.PERIOD_15MIN);
+        } else if (KlineConstant.PERIOD_30MIN.equals(line)) {
+            return klineService.bulidKline30Minute(realtime, KlineConstant.PERIOD_30MIN);
+        } else if (KlineConstant.PERIOD_60MIN.equals(line)) {
+            return klineService.bulidKline60Minute(realtime, KlineConstant.PERIOD_60MIN);
+        } else if (KlineConstant.PERIOD_4HOUR.equals(line)) {
+            return klineService.bulidKline4Hour(realtime, KlineConstant.PERIOD_4HOUR);
+        } else if (KlineConstant.PERIOD_1DAY.equals(line)) {
+            return klineService.bulidKline1Day(realtime, KlineConstant.PERIOD_1DAY);
+        } else if (KlineConstant.PERIOD_5DAY.equals(line)) {
+            return klineService.bulidKline5Day(realtime, KlineConstant.PERIOD_5DAY);
+        } else if (KlineConstant.PERIOD_1WEEK.equals(line)) {
+            return klineService.bulidKline1Week(realtime, KlineConstant.PERIOD_1WEEK);
+        } else if (KlineConstant.PERIOD_1MON.equals(line)) {
+            return klineService.bulidKline1Mon(realtime, KlineConstant.PERIOD_1MON);
+        } else if (KlineConstant.PERIOD_QUARTER.equals(line)) {
+            return klineService.bulidKlineQuarter(realtime, KlineConstant.PERIOD_QUARTER);
+        } else if (KlineConstant.PERIOD_YEAR.equals(line)) {
+            return klineService.bulidKlineYear(realtime, KlineConstant.PERIOD_YEAR);
+        }
+        return null;
     }
 
     public List<Kline> klineCryptos(String symbol, String line) {
-        KlineTimeObject timeObject = DataCache.getKline(symbol, line);
-        List<Kline> list = new ArrayList<Kline>();
-        if (timeObject != null) {
-            list = timeObject.getKline();
+        return kline(symbol, line);
+    }
+
+    private void appendOrReplaceKline(List<Kline> list, Kline kline) {
+        if (kline == null) {
+            return;
         }
-        List<Kline> list_clone = new ArrayList<Kline>();
-        try {
-            for (int i = 0; i < list.size(); i++) {
-                Kline kline = (Kline) list.get(i).clone();
-                list_clone.add(kline);
+        for (int i = list.size() - 1; i >= 0; i--) {
+            Kline existing = list.get(i);
+            if (existing.getTs() != null && existing.getTs().equals(kline.getTs())) {
+                list.set(i, kline);
+                return;
             }
-        } catch (CloneNotSupportedException e) {
-            e.printStackTrace();
         }
-        Realtime realtime = DataCache.getRealtime(symbol);
-        Kline hobiOne = DataCache.getKline_hobi().get(symbol + "_" + line);
-
-        Kline lastOne = null;
-        if (list != null && list.size() > 0) {
-            lastOne = list.get(list.size() - 1);
-        }
-        if (realtime != null && hobiOne != null && lastOne != null) {
-            list_clone.add(this.klineService.bulidKline(realtime, lastOne, hobiOne, line));
-        }
-        Collections.sort(list_clone); // 按时间升序
-        return list_clone;
-
+        list.add(kline);
     }
 
     @Override

--
Gitblit v1.9.3