From 91bbc719126310f09031e55967c059c0a01f20b1 Mon Sep 17 00:00:00 2001
From: zyy3 <zyy3@zy.com>
Date: Wed, 05 Nov 2025 18:50:49 +0800
Subject: [PATCH] 1
---
trading-order-admin/src/main/java/com/yami/trading/api/controller/KlineController.java | 16 +++
trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineService.java | 7 +
trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebsocketRunClient.java | 19 +++-
trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineServiceImpl.java | 52 +++++++++++++
trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java | 18 ++++
trading-order-admin/src/main/java/com/yami/trading/admin/task/StockTask.java | 85 +++++++++++----------
trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebSocketClientBeanConfig.java | 13 +++
7 files changed, 160 insertions(+), 50 deletions(-)
diff --git a/trading-order-admin/src/main/java/com/yami/trading/admin/task/StockTask.java b/trading-order-admin/src/main/java/com/yami/trading/admin/task/StockTask.java
index b152b1d..a2959a3 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/admin/task/StockTask.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/admin/task/StockTask.java
@@ -79,6 +79,8 @@
}
}
+
+
/**
* 加载所有股票数据
*/
@@ -111,55 +113,54 @@
.eq("type", Item.indices));
log.info("同步股票 已有数据 {} 获取数据 {}", stockList.size(), list.size());
- System.out.println(stockList);
List<Item> updateStockList = new ArrayList<>();
for (StockRealTimeBean o : list) {
//System.out.println(o);
+ Item indices = indicesList.stream()
+ .filter(x -> x.getSymbol().equals(o.getSymbol()))
+ .findFirst()
+ .orElse(null);
+ if (indices != null) { //指数不添加
+ continue;
+ }
+
+
Item item = stockList.stream()
.filter(x -> x.getSymbol().equals(o.getSymbol()) &&
x.getStockCode().equals(o.getId()))
.findFirst()
.orElse(null);
- if (item != null) { //已有不添加
- continue;
- }
- item = indicesList.stream()
- .filter(x -> x.getSymbol().equals(o.getSymbol()))
- .findFirst()
- .orElse(null);
- if (item != null) { //已有不添加
- continue;
- }
+ if (item == null) {
+ item = new Item();
+ String name = StringUtils.trim(o.getName());
+ item.setEnName(name);
+ item.setName(name);
+ item.setSymbolFullName(name);
+ item.setSymbol(o.getSymbol());
+ item.setSymbolData(o.getSymbol());
+ item.setPips(BigDecimal.valueOf(0.01).doubleValue());
+ item.setPipsAmount(BigDecimal.valueOf(0.02).doubleValue());
+ item.setAdjustmentValue(BigDecimal.ZERO.doubleValue());
+ item.setUnitAmount(BigDecimal.valueOf(1000).doubleValue());
+ item.setUnitFee(BigDecimal.valueOf(30).doubleValue());
+ item.setMarket("FOREVER");
+ item.setDecimals(2);
+ item.setMultiple(BigDecimal.ZERO.doubleValue());
+ item.setBorrowingRate(BigDecimal.ZERO.doubleValue());
+ item.setDelFlag(0);
+ item.setType(Item.US_STOCKS);
+ item.setCategory(Item.US_STOCKS);
+ item.setSorted("100");
+ item.setOpenCloseType(Item.US_STOCKS);
+ item.setFake("0");
+ item.setShowStatus("1");
+ item.setTradeStatus("1");
+ item.setQuoteCurrency("USDT");
+ item.setCrawlStatus("default_active");
+ item.setStockCode(o.getId());
- item = new Item();
- String name = StringUtils.trim(o.getName());
- item.setEnName(name);
- item.setName(name);
- item.setSymbolFullName(name);
- item.setSymbol(o.getSymbol());
- item.setSymbolData(o.getSymbol());
- item.setPips(BigDecimal.valueOf(0.01).doubleValue());
- item.setPipsAmount(BigDecimal.valueOf(0.02).doubleValue());
- item.setAdjustmentValue(BigDecimal.ZERO.doubleValue());
- item.setUnitAmount(BigDecimal.valueOf(1000).doubleValue());
- item.setUnitFee(BigDecimal.valueOf(30).doubleValue());
- item.setMarket("FOREVER");
- item.setDecimals(2);
- item.setMultiple(BigDecimal.ZERO.doubleValue());
- item.setBorrowingRate(BigDecimal.ZERO.doubleValue());
- item.setDelFlag(0);
- item.setType(Item.US_STOCKS);
- item.setCategory(Item.US_STOCKS);
- item.setSorted("100");
- item.setOpenCloseType(Item.US_STOCKS);
- item.setFake("0");
- item.setShowStatus("1");
- item.setTradeStatus("1");
- item.setQuoteCurrency("USDT");
- item.setCrawlStatus("default_active");
- item.setStockCode(o.getId());
-
- updateStockList.add(item);
+ updateStockList.add(item);
+ }
Realtime realtime = new Realtime();
@@ -191,6 +192,10 @@
}
}
+
+
+
+
public static void main(String[] args) {
StockTask task = new StockTask();
task.loadAllStock(EStockType.US);
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 e9e33e8..f1d50ee 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
@@ -8,6 +8,7 @@
import com.yami.trading.common.web.ResultObject;
import com.yami.trading.huobi.constants.KlinePeriodEnum;
import com.yami.trading.huobi.data.TimeZoneConverterService;
+import com.yami.trading.huobi.data.internal.KlineService;
import com.yami.trading.huobi.tradingview.service.TradingViewService;
import com.yami.trading.service.data.DataService;
import com.yami.trading.service.item.ItemService;
@@ -50,6 +51,9 @@
@Autowired
RedisTemplate redisTemplate;
+ @Autowired
+ KlineService klineService;
+
@ApiOperation(value = "行情")
@GetMapping("/api/hobi!getKline.action")
@@ -62,13 +66,21 @@
// Fetch item details based on symbol
Item bySymbol = itemService.findBySymbol(symbol);
+ List<Kline> data;
// Handle non-cryptos separately
if (!Item.cryptos.equals(bySymbol.getType())) {
- return getKlineForNonCryptos(bySymbol, line, symbol);
+ if (bySymbol.getType().equalsIgnoreCase(Item.US_STOCKS)) {
+ data = klineService.getKData(bySymbol, line);
+ formatKlineTimestamps(data, line);
+ return Result.succeed(this.build(data, line, symbol));
+ } else {
+ return getKlineForNonCryptos(bySymbol, line, symbol);
+ }
}
+ data = this.dataService.kline(symbol, line);
// Fetch Kline data from service (for cryptos)
- List<Kline> data = this.dataService.kline(symbol, line);
+
// Return an empty response if no data is found
if (Objects.isNull(data)) {
diff --git a/trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineService.java b/trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineService.java
index dc607f5..c6c0a37 100644
--- a/trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineService.java
+++ b/trading-order-huobi/src/main/java/com/yami/trading/huobi/data/internal/KlineService.java
@@ -2,6 +2,7 @@
import com.yami.trading.bean.data.domain.Kline;
import com.yami.trading.bean.data.domain.Realtime;
+import com.yami.trading.bean.item.domain.Item;
import java.util.List;
import java.util.Map;
@@ -115,4 +116,8 @@
public List<Kline> calculateKline(String symbol, int seq, String period, List<Kline> klineList) ;
- }
+ List<Kline> getKData(Item item, String interval);
+
+}
+
+
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 09ba49d..7a8e13f 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
@@ -1,13 +1,19 @@
package com.yami.trading.huobi.data.internal;
+import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
import com.yami.trading.bean.data.domain.Kline;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.item.domain.Item;
import com.yami.trading.common.config.RequestDataHelper;
import com.yami.trading.common.constants.Constants;
+import com.yami.trading.common.domain.Result;
+import com.yami.trading.common.exception.YamiShopBindException;
import com.yami.trading.common.util.DateUtils;
+import com.yami.trading.huobi.websocket.constant.enums.EStockType;
import com.yami.trading.service.MarketOpenChecker;
import com.yami.trading.common.util.ThreadUtils;
import com.yami.trading.common.util.UTCDateUtils;
@@ -16,6 +22,7 @@
import com.yami.trading.service.data.RealtimeService;
import com.yami.trading.service.item.ItemService;
import com.yami.trading.service.syspara.SysparaService;
+import lombok.Data;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -952,4 +959,49 @@
}
return result;
}
+
+ @Data
+ class kData {
+ long t;
+ String c;
+ String o;
+ String h;
+ String l;
+ String v;
+ String vo;
+ }
+
+ @Override
+ public List<Kline> getKData(Item item, String interval) {
+ try {
+ EStockType eStockType = EStockType.US;
+ Object object = HttpUtil.get(eStockType.stockUrl + "kline?pid=" + item.getStockCode() + "&interval=" + interval + "&key=" + eStockType.stockKey);
+ Gson gson = new Gson();
+ List<kData> dataList = gson.fromJson(object.toString(), new TypeToken<List<kData>>(){}.getType());
+ logger.info("{}获取{}条K线" , item.getSymbol() ,dataList.size());
+ Realtime realtime = DataCache.getRealtime(item.getSymbol());
+ // 修改 List 中的最后一条数据
+ kData lastData = dataList.get(dataList.size() - 1);
+ lastData.setC(String.valueOf(realtime.getClose()));
+ lastData.setO(String.valueOf(realtime.getOpen()));
+ lastData.setH(String.valueOf(realtime.getHigh()));
+ lastData.setL(String.valueOf(realtime.getLow()));
+
+ List<Kline> list = new ArrayList<>();
+ for (int i = 0; i < dataList.size(); i++) {
+ kData kData = dataList.get(i);
+ Kline kline = new Kline();
+ kline.setTs(Long.valueOf(kData.getT() + "000"));
+ kline.setClose(Double.valueOf(kData.getC()));
+ kline.setOpen(Double.valueOf(kData.getO()));
+ kline.setHigh(Double.valueOf(kData.getH()));
+ kline.setLow(Double.valueOf(kData.getL()));
+ list.add(kline);
+ }
+ return list;
+ } catch (Exception e) {
+ logger.error("getKData error", e);
+ }
+ return null;
+ }
}
diff --git a/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebSocketClientBeanConfig.java b/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebSocketClientBeanConfig.java
index c105d73..4319b2a 100644
--- a/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebSocketClientBeanConfig.java
+++ b/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebSocketClientBeanConfig.java
@@ -4,6 +4,8 @@
import com.yami.trading.huobi.websocket.constant.enums.EStockType;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@@ -15,13 +17,22 @@
@Component
public class WebSocketClientBeanConfig {
+ // 注入Spring上下文,用于获取原型Bean
+ @Autowired
+ private ApplicationContext applicationContext;
@Bean
public Map<String, WebSocketClient> websocketRunClientMap() {
Map<String, WebSocketClient> retMap = new HashMap<>(1);
try {
- WebsocketRunClient websocketRunClient = new WebsocketRunClient(new URI(EStockType.US.getWsUrl()), EStockType.US);
+ // 关键:通过Spring上下文获取WebsocketRunClient实例(而非直接new)
+ // 传入参数创建实例(需配合原型作用域)
+ WebsocketRunClient websocketRunClient = applicationContext.getBean(
+ WebsocketRunClient.class,
+ new URI(EStockType.US.getWsUrl()), // 第一个参数:serverUri
+ EStockType.US // 第二个参数:eStockType
+ );
websocketRunClient.connect();
websocketRunClient.setConnectionLostTimeout(0);
startHeartbeatThread(websocketRunClient);
diff --git a/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebsocketRunClient.java b/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebsocketRunClient.java
index 86fc437..e120d1f 100644
--- a/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebsocketRunClient.java
+++ b/trading-order-huobi/src/main/java/com/yami/trading/huobi/jsws/WebsocketRunClient.java
@@ -12,6 +12,8 @@
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
import java.lang.reflect.Type;
import java.math.BigDecimal;
@@ -20,6 +22,8 @@
import java.util.*;
@Slf4j
+@Component
+@Scope("prototype")
public class WebsocketRunClient extends WebSocketClient {
private EStockType eStockType;
@@ -27,16 +31,20 @@
@Autowired
ItemService itemService;
+ public WebsocketRunClient() {
+ super(URI.create("wss://ws.jinmanxuan.com/websocket-server"));
+ }
+
public WebsocketRunClient(URI serverUri, EStockType eStockType) {
// 修改为新的WebSocket服务器地址
- super(URI.create("wss://usws.yanshiz.com/websocket-server"));
+ super(URI.create("wss://ws.jinmanxuan.com/websocket-server"));
this.eStockType = eStockType;
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
- log.info("WebSocket连接已建立,连接到: wss://usws.yanshiz.com/websocket-server");
+ log.info("WebSocket连接已建立,连接到: wss://ws.jinmanxuan.com/websocket-server");
// 发送身份验证消息
send(("key:"+ eStockType.getStockKey()+":"+eStockType.getContryId()).getBytes());
Timer heartbeatTimer;
@@ -58,10 +66,9 @@
if(!s.equals("pong") && !s.equals("身份验证成功")){
try {
Map<String, String> stringObjectMap = jsonToMap(s);
-
- String symbol = stringObjectMap.get("symbol");
- Item item = itemService.findBySymbol(symbol);
- if (!item.getType().equalsIgnoreCase(Item.US_STOCKS)) {
+ String symbol = stringObjectMap.get("symbol").trim();
+ Item item = itemService.findCaCheBySymbol(symbol);
+ if (item == null || !item.getType().equalsIgnoreCase(Item.US_STOCKS)) {
return;
}
Realtime realtime = new Realtime();
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java b/trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java
index c94634b..dbf2ee8 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java
@@ -165,6 +165,24 @@
}
/**
+ * 通过 symbol 找去缓存对象
+ *
+ * @param symbol
+ * @return
+ */
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public Item findCaCheBySymbol(String symbol) {
+ Item item;
+ if (CollectionUtil.isNotEmpty(symbolItem)) {
+ item = symbolItem.get(symbol);
+ if (item != null) {
+ return item;
+ }
+ }
+ return null;
+ }
+
+ /**
* 基于 remarks 字段去缓存提取 item 对象,特性是基于 remarks 映射 symbol,从缓存中提取 item;
* 如果缓存中没有数据,则直接去数据库查询返回。
*
--
Gitblit v1.9.3