| | |
| | | LocalDate yesterday = LocalDate.now(ZoneId.of("America/New_York")).minusDays(1); |
| | | |
| | | // 4. 判断是否为昨天 |
| | | boolean isYesterday = tsDate.equals(yesterday); |
| | | if (isYesterday) { |
| | | return realtime; |
| | | } |
| | | boolean isYesterday = tsDate.equals(yesterday); |
| | | if (isYesterday) { |
| | | return realtime; |
| | | } |
| | | } |
| | | // 没缓存重新保存 |
| | | // 计算当天0点的时间戳(毫秒级) |
| | |
| | | |
| | | public BeforeClose getBeforeClose(String symbol, String line, Long ts, Realtime realtime) { |
| | | BeforeClose beforeClose = (BeforeClose) redisTemplate.opsForValue().get(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line); |
| | | //超出时间重新计算 |
| | | if (beforeClose == null || ts > beforeClose.getTs()) { |
| | | long queryTs = normalizeToMillis(ts); |
| | | if (beforeClose == null || queryTs > beforeClose.getTs()) { |
| | | long currentTimeStamp = System.currentTimeMillis(); |
| | | RequestDataHelper.set("symbol", symbol); |
| | | QueryWrapper<Realtime> queryWrapper = new QueryWrapper<Realtime>() |
| | | .eq("symbol", symbol) |
| | | .ge("ts", ts) |
| | | .ge("ts", queryTs) |
| | | .le("ts", currentTimeStamp) |
| | | .select("MAX(close) as maxClose", "MIN(close) as minClose"); |
| | | .select("MAX(CAST(close AS DECIMAL(20,8))) as maxClose", |
| | | "MIN(CAST(close AS DECIMAL(20,8))) as minClose"); |
| | | Map<String, Object> resultMap = realtimeService.getMap(queryWrapper); |
| | | RequestDataHelper.clear(); |
| | | beforeClose = new BeforeClose(); |
| | | BigDecimal maxClose = extractAggregateValue(resultMap, "maxClose"); |
| | | BigDecimal minClose = extractAggregateValue(resultMap, "minClose"); |
| | | mergeRealtimeIntoBeforeClose(beforeClose, maxClose, minClose, realtime); |
| | | beforeClose.setTs(ts); |
| | | beforeClose.setTs(queryTs); |
| | | if (resultMap != null && !resultMap.isEmpty()) { |
| | | beforeClose.setMaxClose(convertToBigDecimal(resultMap.get("maxClose"))); |
| | | beforeClose.setMinClose(convertToBigDecimal(resultMap.get("minClose"))); |
| | | } |
| | | redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose); |
| | | } else if (realtime != null) { |
| | | mergeRealtimeIntoBeforeClose(beforeClose, beforeClose.getMaxClose(), beforeClose.getMinClose(), realtime); |
| | | redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose); |
| | | } |
| | | |
| | | mergeRealtimeIntoBeforeClose(beforeClose, realtime, symbol, line); |
| | | if (!isValidBeforeClose(beforeClose)) { |
| | | return null; |
| | | } |
| | | return beforeClose; |
| | | } |
| | | |
| | | private void mergeRealtimeIntoBeforeClose(BeforeClose beforeClose, BigDecimal maxClose, BigDecimal minClose, Realtime realtime) { |
| | | BigDecimal max = maxClose; |
| | | BigDecimal min = minClose; |
| | | if (realtime != null && realtime.getClose() != null) { |
| | | BigDecimal latest = realtime.getClose(); |
| | | if (max == null || max.compareTo(BigDecimal.ZERO) <= 0) { |
| | | max = latest; |
| | | } else { |
| | | max = max.max(latest); |
| | | private void mergeRealtimeIntoBeforeClose(BeforeClose beforeClose, Realtime realtime, String symbol, String line) { |
| | | if (realtime == null || realtime.getClose() == null || realtime.getClose().compareTo(BigDecimal.ZERO) <= 0) { |
| | | return; |
| | | } |
| | | BigDecimal close = realtime.getClose(); |
| | | if (!isValidBeforeClose(beforeClose)) { |
| | | beforeClose.setMaxClose(close); |
| | | beforeClose.setMinClose(close); |
| | | } else { |
| | | if (close.compareTo(beforeClose.getMaxClose()) > 0) { |
| | | beforeClose.setMaxClose(close); |
| | | } |
| | | if (min == null || min.compareTo(BigDecimal.ZERO) <= 0) { |
| | | min = latest; |
| | | } else { |
| | | min = min.min(latest); |
| | | if (beforeClose.getMinClose().compareTo(BigDecimal.ZERO) <= 0 |
| | | || close.compareTo(beforeClose.getMinClose()) < 0) { |
| | | beforeClose.setMinClose(close); |
| | | } |
| | | } |
| | | beforeClose.setMaxClose(max == null ? BigDecimal.ZERO : max); |
| | | beforeClose.setMinClose(min == null ? BigDecimal.ZERO : min); |
| | | redisTemplate.opsForValue().set(RedisKeys.REAL_TIME_BEFORE_CLOSE + symbol + line, beforeClose); |
| | | } |
| | | |
| | | private BigDecimal extractAggregateValue(Map<String, Object> resultMap, String key) { |
| | | if (resultMap == null || resultMap.isEmpty()) { |
| | | return null; |
| | | private boolean isValidBeforeClose(BeforeClose beforeClose) { |
| | | return beforeClose != null |
| | | && beforeClose.getMaxClose() != null && beforeClose.getMaxClose().compareTo(BigDecimal.ZERO) > 0 |
| | | && beforeClose.getMinClose() != null && beforeClose.getMinClose().compareTo(BigDecimal.ZERO) > 0; |
| | | } |
| | | |
| | | private long normalizeToMillis(Long ts) { |
| | | if (ts == null) { |
| | | return System.currentTimeMillis(); |
| | | } |
| | | if (resultMap.containsKey(key)) { |
| | | return convertToBigDecimal(resultMap.get(key)); |
| | | } |
| | | for (Map.Entry<String, Object> entry : resultMap.entrySet()) { |
| | | if (entry.getKey() != null && entry.getKey().equalsIgnoreCase(key)) { |
| | | return convertToBigDecimal(entry.getValue()); |
| | | } |
| | | } |
| | | return null; |
| | | return String.valueOf(ts).length() <= 10 ? ts * 1000 : ts; |
| | | } |
| | | |
| | | // 辅助方法:统一转换为BigDecimal,避免类型错误 |