From d4be4cc69f18b01cc39bd3f9dc9497a828848ca8 Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Tue, 30 Sep 2025 11:18:44 +0800
Subject: [PATCH] 1
---
trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java | 38 +
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFResponse.java | 19 +
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeData.java | 35 ++
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java | 8
trading-order-admin/src/main/resources/application-prod.yml | 2
trading-order-admin/src/main/resources/redisson/redisson-dev.yml | 2
trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java | 19
trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java | 2
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeResponse.java | 19 +
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetMarketJob.java | 6
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java | 20
trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XueQiuDataServiceImpl.java | 371 +++++++++++++++++-----
trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java | 5
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiCapitaltWalletWalletController.java | 8
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java | 15
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFData.java | 30 +
trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserStatisticsServiceImpl.java | 6
trading-order-service/src/main/java/com/yami/trading/service/item/ItemService.java | 2
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ETFDataSynchronizationJob.java | 272 +++++++++++++++++
trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetDataJob.java | 25
trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java | 13
trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java | 20
22 files changed, 764 insertions(+), 173 deletions(-)
diff --git a/trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java b/trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java
index 33444ae..65c5759 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/admin/task/InitHandle.java
@@ -112,6 +112,7 @@
// todo 先注释观察报错
// futuresRecomConsumeServer.start();
log.info("开始Data初始化........");
+ stockGetDataJob.start();
List<Item> items = itemService.list();
for (Item item : items) {
AdjustmentValueCache.getCurrentValue().put(item.getSymbol(), item.getAdjustmentValue());
@@ -135,9 +136,9 @@
klineInitService.klineInit(symbols);
// 高低修正
highLowHandleJob.start();
- stockGetMarketJob.start();
+// stockGetMarketJob.start();
// // 获取realtime实时数据
- stockGetDataJob.start();
+
// forexGetDataJob.start(); 外汇
cryptosGetDataJob.start();
fakeSymbolGetDataJob.start();
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiCapitaltWalletWalletController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiCapitaltWalletWalletController.java
index e0811c2..fd404e5 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiCapitaltWalletWalletController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiCapitaltWalletWalletController.java
@@ -92,8 +92,8 @@
// 获取合约账户(contract)
Wallet wallet = walletService.saveWalletByPartyId(partyId);
// 获取资金账户(capital)
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, partyId).last(" limit 1 "));
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, partyId).last(" limit 1 "));
List<WalletExtend> walletExtends = walletExtendService.findByUserId(partyId);
AtomicReference<BigDecimal> walletExtendMoneyRef = new AtomicReference<>(BigDecimal.ZERO);
walletExtends.forEach(f -> {
@@ -107,8 +107,8 @@
Map<String, BigDecimal> assets = new HashMap<>();
assets.put("contract",wallet.getMoney().setScale(2,RoundingMode.DOWN));
- assets.put("capital",capitaltWallet.getMoney().add(walletExtendMoney).setScale(2,RoundingMode.DOWN));
- assets.put("capitalUSDT",capitaltWallet.getMoney());//划转专用
+// assets.put("capital",capitaltWallet.getMoney().add(walletExtendMoney).setScale(2,RoundingMode.DOWN));
+// assets.put("capitalUSDT",capitaltWallet.getMoney());//划转专用
return Result.succeed(assets);
}
}
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
index 75bb105..b90503b 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
@@ -215,13 +215,13 @@
df2.setRoundingMode(RoundingMode.FLOOR);
// String partyId ="dcc0dd35a49c383dadabc4dc030afe70";
String partyId = SecurityUtils.getCurrentUserId();
- CapitaltWallet usdt = null;
+ Wallet usdt = null;
if (StringUtils.isNotEmpty(partyId)) {
-// usdt = this.walletService.saveWalletByPartyId(partyId);
- usdt = capitaltWalletService.getUserIdWallet(partyId);
+ usdt = this.walletService.saveWalletByPartyId(partyId);
+// usdt = capitaltWalletService.getUserIdWallet(partyId);
}
if (null == usdt) {
- usdt = new CapitaltWallet();
+ usdt = new Wallet();
usdt.setMoney(new BigDecimal(0));
usdt.setLockMoney(new BigDecimal(0));
usdt.setFreezeMoney(new BigDecimal(0));
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
index 9b16eb1..15074a2 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.trading.bean.model.CapitaltWallet;
import com.yami.trading.bean.model.User;
+import com.yami.trading.bean.model.Wallet;
import com.yami.trading.bean.model.Withdraw;
import com.yami.trading.common.constants.Constants;
import com.yami.trading.common.domain.Result;
@@ -13,6 +14,7 @@
import com.yami.trading.security.common.util.SecurityUtils;
import com.yami.trading.service.CapitaltWalletService;
import com.yami.trading.service.SessionTokenService;
+import com.yami.trading.service.WalletService;
import com.yami.trading.service.WithdrawService;
import com.yami.trading.service.syspara.SysparaService;
import com.yami.trading.service.user.UserService;
@@ -50,6 +52,8 @@
protected WalletLogService walletLogService;
@Autowired
CapitaltWalletService capitaltWalletService;
+ @Autowired
+ WalletService walletService;
/**
* 首次进入页面,传递session_token
@@ -111,9 +115,14 @@
// 获取资金账户(capital)
if(channel.contains("USDT")){
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, partyId).last(" limit 1 "));
- if(capitaltWallet.getMoney().compareTo(new BigDecimal(amount)) < 0){
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, partyId).last(" limit 1 "));
+// if(capitaltWallet.getMoney().compareTo(new BigDecimal(amount)) < 0){
+// throw new YamiShopBindException("Insufficient available balance for withdrawal!");
+// }
+ Wallet wallet = walletService.getOne(new LambdaQueryWrapper<>(Wallet.class)
+ .eq(Wallet::getUserId, partyId).last(" limit 1 "));
+ if(wallet.getMoney().compareTo(new BigDecimal(amount)) < 0){
throw new YamiShopBindException("Insufficient available balance for withdrawal!");
}
}
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
index bd8f0ac..1e1bcfb 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
@@ -109,13 +109,14 @@
Map<String, Object> parities = parities(symbol, symbol_to, volume_temp);
Object getVolume = parities.get("get_volume");
if(symbol.equals("usdt")){
- CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
+ Wallet userIdWallet = walletService.saveWalletByPartyId(partyId);
+// CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
if(userIdWallet.getMoney().compareTo(new BigDecimal(volume_temp)) < 0){
throw new YamiShopBindException("not sufficient funds");
}
Double value = Double.valueOf(volume_temp);
- capitaltWalletService.update(userIdWallet, -value);
-
+// capitaltWalletService.update(userIdWallet, -value);
+ walletService.update(userIdWallet.getUserId(), -value);
WalletExtend walletExtend = walletExtendService.getOne(new LambdaQueryWrapper<>(WalletExtend.class)
.eq(WalletExtend::getWallettype, symbol_to)
.eq(WalletExtend::getPartyId,partyId)
@@ -147,8 +148,10 @@
walletExtendService.update(walletExtend,new LambdaUpdateWrapper<WalletExtend>().eq(UUIDEntity::getUuid,walletExtend.getUuid()));
- CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
- capitaltWalletService.update(userIdWallet,Double.valueOf(getVolume.toString()));
+// CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
+// capitaltWalletService.update(userIdWallet,Double.valueOf(getVolume.toString()));
+ Wallet userIdWallet = walletService.saveWalletByPartyId(partyId);
+ walletService.update(userIdWallet.getUserId(),Double.valueOf(getVolume.toString()));
}else{
WalletExtend walletExtend = walletExtendService.getOne(new LambdaQueryWrapper<>(WalletExtend.class)
.eq(WalletExtend::getWallettype, symbol)
@@ -374,12 +377,12 @@
public Result openview() {
Map<String, Object> data = new HashMap<String, Object>();
String partyId = SecurityUtils.getUser().getUserId();
-// Wallet wallet = walletService.saveWalletByPartyId(partyId);
- CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
+ Wallet wallet = walletService.saveWalletByPartyId(partyId);
+// CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(partyId);
// 账户剩余资金
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.FLOOR);// 向下取整
- data.put("volume", df.format(userIdWallet.getMoney()));
+ data.put("volume", df.format(wallet.getMoney()));
String session_token = sessionTokenService.savePut(partyId);
data.put("session_token", session_token);
data.put("fee", sysparaService.find("exchange_apply_order_buy_fee").getSvalue());
diff --git a/trading-order-admin/src/main/resources/application-prod.yml b/trading-order-admin/src/main/resources/application-prod.yml
index c292727..783234e 100644
--- a/trading-order-admin/src/main/resources/application-prod.yml
+++ b/trading-order-admin/src/main/resources/application-prod.yml
@@ -49,4 +49,4 @@
maxIdle: 20
maxTotal: 50
host: 127.0.0.1
- port: 6379
+ port: 6380
diff --git a/trading-order-admin/src/main/resources/redisson/redisson-dev.yml b/trading-order-admin/src/main/resources/redisson/redisson-dev.yml
index c76245f..603a29c 100644
--- a/trading-order-admin/src/main/resources/redisson/redisson-dev.yml
+++ b/trading-order-admin/src/main/resources/redisson/redisson-dev.yml
@@ -1,6 +1,6 @@
# 单节点设置
singleServerConfig:
- address: redis://127.0.0.1:6379
+ address: redis://127.0.0.1:6380
database: 0
password:
idleConnectionTimeout: 10000
diff --git a/trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java b/trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java
index b916445..91d75af 100644
--- a/trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java
+++ b/trading-order-bean/src/main/java/com/yami/trading/bean/item/domain/Item.java
@@ -30,7 +30,7 @@
*/
public final static String forex = "forex";
/**
- * 指数
+ * etf
*/
public final static String indices = "indices";
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ETFDataSynchronizationJob.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ETFDataSynchronizationJob.java
new file mode 100644
index 0000000..ee40771
--- /dev/null
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/ETFDataSynchronizationJob.java
@@ -0,0 +1,272 @@
+package com.yami.trading.huobi.data.job;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.yami.trading.bean.item.domain.Item;
+import com.yami.trading.huobi.data.model.ETFData;
+import com.yami.trading.huobi.data.model.ETFResponse;
+import com.yami.trading.huobi.data.model.RealTimeData;
+import com.yami.trading.huobi.data.model.RealTimeResponse;
+import com.yami.trading.service.item.ItemService;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+
+/**
+ * @program: trading-order-master
+ * @description:
+ * @create: 2025-09-28 11:20
+ **/
+@Slf4j
+@Component
+public class ETFDataSynchronizationJob {
+
+ @Autowired
+ private ItemService itemService;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ private static final String LIST_API_URL = "https://www.tsanghi.com/api/fin/etf/XNAS/list?token=9668db3503214cd19a831a9f866923b9";
+ private static final String REALTIME_API_URL = "https://www.tsanghi.com/api/fin/etf/XNAS/realtime?token=9668db3503214cd19a831a9f866923b9&ticker=";
+
+ /**
+ * 同步ETF数据定时任务
+ */
+// @Scheduled(cron = "0 * * * * ?")
+ public void syncETFData() {
+ try {
+ log.info("开始同步ETF数据...");
+
+ // 获取ETF列表
+ List<ETFData> etfList = getETFList();
+ if (etfList == null || etfList.isEmpty()) {
+ log.warn("未获取到ETF列表数据");
+ return;
+ }
+
+ log.info("共获取到{}个ETF数据", etfList.size());
+
+ int successCount = 0;
+ int errorCount = 0;
+
+ // 处理每个ETF
+ for (ETFData etf : etfList) {
+ try {
+ if (processETFItem(etf)) {
+ successCount++;
+ } else {
+ errorCount++;
+ }
+ } catch (Exception e) {
+ log.error("处理ETF {} 时发生错误: {}", etf.getTicker(), e.getMessage());
+ errorCount++;
+ }
+ }
+
+ log.info("ETF数据同步完成: 成功 {}, 失败 {}", successCount, errorCount);
+
+ } catch (Exception e) {
+ log.error("同步ETF数据时发生错误: {}", e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 获取ETF列表
+ */
+ private List<ETFData> getETFList() {
+ try {
+ ResponseEntity<ETFResponse> response = restTemplate.exchange(
+ LIST_API_URL,
+ HttpMethod.GET,
+ null,
+ ETFResponse.class
+ );
+
+ if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
+ ETFResponse apiResponse = response.getBody();
+ if (apiResponse.getCode() == 200) {
+ return apiResponse.getData();
+ } else {
+ log.error("API返回错误: {} - {}", apiResponse.getCode(), apiResponse.getMsg());
+ }
+ }
+ } catch (Exception e) {
+ log.error("获取ETF列表失败: {}", e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * 处理单个ETF项目
+ */
+ private boolean processETFItem(ETFData etf) {
+ // 只处理活跃的ETF
+ if (etf.getIsActive() == null || etf.getIsActive() != 1) {
+ log.info("跳过非活跃ETF: {}", etf.getTicker());
+ return false;
+ }
+
+ // 检查是否已存在
+ Item existingItem = itemService.getOne(new LambdaQueryWrapper<Item>()
+ .eq(Item::getSymbol,etf.getTicker())
+ );
+ if (existingItem != null) {
+ log.info("ETF {} 已存在,跳过", etf.getTicker());
+ return true;
+ }
+
+ // 获取实时数据计算小数位
+ RealTimeData realtimeData = getRealtimeData(etf.getTicker());
+ if (realtimeData == null) {
+ log.warn("无法获取ETF {} 的实时数据", etf.getTicker());
+ return false;
+ }
+
+ // 创建Item对象
+ Item item = createItemFromETFData(etf, realtimeData);
+
+ // 保存到数据库
+ return itemService.save(item);
+ }
+
+ /**
+ * 获取实时数据
+ */
+ private RealTimeData getRealtimeData(String ticker) {
+ try {
+ String url = REALTIME_API_URL + ticker;
+ ResponseEntity<RealTimeResponse> response = restTemplate.exchange(
+ url,
+ HttpMethod.GET,
+ null,
+ RealTimeResponse.class
+ );
+
+ if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
+ RealTimeResponse apiResponse = response.getBody();
+ if (apiResponse.getCode() == 200) {
+ return apiResponse.getData().get(0);
+ }
+ }
+ } catch (Exception e) {
+ log.error("获取ETF {} 实时数据失败: {}", ticker, e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * 根据收盘价计算小数位数和PIPS
+ */
+ private ETFDecimalInfo calculateDecimalInfo(BigDecimal closePrice) {
+ ETFDecimalInfo info = new ETFDecimalInfo();
+
+ if (closePrice == null) {
+ // 默认值
+ info.setDecimals(2);
+ info.setPips(new BigDecimal("0.01"));
+ info.setPipsAmount(new BigDecimal("0.01"));
+ return info;
+ }
+
+ try {
+ String priceStr = closePrice.stripTrailingZeros().toPlainString();
+ int decimalPlaces = 0;
+
+ // 查找小数点位置
+ int dotIndex = priceStr.indexOf('.');
+ if (dotIndex != -1) {
+ // 计算实际的小数位数(去除末尾的0)
+ decimalPlaces = priceStr.length() - dotIndex - 1;
+ }
+
+ // 设置小数位数,至少为2位
+ int decimals = Math.max(decimalPlaces, 2);
+ info.setDecimals(decimals);
+
+ // 计算PIPS(最小价格单位)
+ BigDecimal pips = BigDecimal.ONE.divide(
+ BigDecimal.TEN.pow(decimals),
+ decimals,
+ RoundingMode.HALF_UP
+ );
+
+ info.setPips(pips);
+ info.setPipsAmount(pips);
+
+ } catch (Exception e) {
+ log.error("计算小数位信息失败,使用默认值", e);
+ info.setDecimals(2);
+ info.setPips(new BigDecimal("0.01"));
+ info.setPipsAmount(new BigDecimal("0.01"));
+ }
+
+ return info;
+ }
+
+ /**
+ * 创建Item对象
+ */
+ private Item createItemFromETFData(ETFData etf, RealTimeData realtimeData) {
+ Item item = new Item();
+
+ // 生成UUID
+ String uuid = UUID.randomUUID().toString().replace("-", "");
+ item.setUuid(uuid);
+
+ // 基础信息
+ item.setName(etf.getName());
+ item.setEnName(etf.getName());
+ item.setSymbol(etf.getTicker());
+ item.setSymbolData(etf.getTicker());
+ item.setSymbolFullName(etf.getName());
+
+ // 计算小数位信息
+ item.setDecimals(2);
+ item.setPips(new BigDecimal("0.01"));
+ item.setPipsAmount(new BigDecimal("0.01"));
+
+ // 固定值设置
+ item.setAdjustmentValue(BigDecimal.ZERO);
+ item.setUnitAmount(new BigDecimal("1000"));
+ item.setUnitFee(new BigDecimal("30"));
+ item.setMarket("indices");
+ item.setMultiple(BigDecimal.ZERO);
+ item.setBorrowingRate(BigDecimal.ZERO);
+ item.setType("indices");
+ item.setCategory("Miscellaneous");
+ item.setSorted("100");
+ item.setOpenCloseType("indices");
+ item.setFake("0");
+ item.setShowStatus("1");
+ item.setTradeStatus("1");
+ item.setQuoteCurrency("USDT");
+ item.setFaceValue(0.01);
+
+ // 创建时间和更新时间
+ item.setCreateTime(new Date());
+ item.setUpdateTime(new Date());
+
+ return item;
+ }
+
+ /**
+ * 小数位信息辅助类
+ */
+ @Data
+ private static class ETFDecimalInfo {
+ private Integer decimals;
+ private BigDecimal pips;
+ private BigDecimal pipsAmount;
+ }
+}
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetDataJob.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetDataJob.java
index 5bd7517..8a715f5 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetDataJob.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetDataJob.java
@@ -2,9 +2,11 @@
import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.bean.data.domain.StockMarket;
import com.yami.trading.bean.item.domain.Item;
+import com.yami.trading.common.domain.BaseEntity;
import com.yami.trading.common.util.*;
import com.yami.trading.huobi.data.AdjustmentValueCache;
import com.yami.trading.huobi.data.DataCache;
@@ -64,23 +66,24 @@
}
while (true) {
try {
- List<Item> list = itemService.list().stream().filter(i->"0".equalsIgnoreCase(i.getFake())).collect(Collectors.toList());
+ List<Item> list = itemService.list(new LambdaQueryWrapper<>(Item.class).eq(BaseEntity::getDelFlag,0)).stream().filter(i->"0".equalsIgnoreCase(i.getFake())).collect(Collectors.toList());
// etf 和A股开盘时间是一样的
- String aStocSymbols = list.stream().filter(item ->item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.A_STOCKS))
- .map(Item::getSymbol).collect(Collectors.joining(","));
- String hkStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null &&item.getOpenCloseType().equalsIgnoreCase(Item.HK_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
+// String aStocSymbols = list.stream().filter(item ->item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.A_STOCKS))
+// .map(Item::getSymbol).collect(Collectors.joining(","));
+// String hkStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null &&item.getOpenCloseType().equalsIgnoreCase(Item.HK_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
String usStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null &&item.getOpenCloseType().equalsIgnoreCase(Item.US_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
+ String indicesymbols = list.stream().filter(item -> item.getOpenCloseType() != null &&item.getOpenCloseType().equalsIgnoreCase(Item.indices)).map(Item::getSymbol).collect(Collectors.joining(","));
if(stockFirstFetch){
- this.realtimeHandle(aStocSymbols);
- this.realtimeHandle(hkStocSymbols);
+// this.realtimeHandle(aStocSymbols);
+ this.realtimeHandle(indicesymbols);
this.realtimeHandle(usStocSymbols);
stockFirstFetch = false;
}
- if(MarketOpenChecker.isMarketOpen(Item.A_STOCKS)){
- this.realtimeHandle(aStocSymbols);
- }
- if(MarketOpenChecker.isMarketOpen(Item.HK_STOCKS)){
- this.realtimeHandle(hkStocSymbols);
+// if(MarketOpenChecker.isMarketOpen(Item.A_STOCKS)){
+// this.realtimeHandle(aStocSymbols);
+// }
+ if(MarketOpenChecker.isMarketOpen(Item.indices)){
+ this.realtimeHandle(indicesymbols);
}
if(MarketOpenChecker.isMarketOpen(Item.US_STOCKS)){
this.realtimeHandle(usStocSymbols);
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetMarketJob.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetMarketJob.java
index 5976886..47b198d 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetMarketJob.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/job/StockGetMarketJob.java
@@ -58,10 +58,10 @@
try {
List<Item> list = itemService.list().stream().filter(i -> "0".equalsIgnoreCase(i.getFake())).collect(Collectors.toList());
// etf 和A股开盘时间是一样的
- String aStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.A_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
- String hkStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.HK_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
+// String aStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.A_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
+// String hkStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.HK_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
String usStocSymbols = list.stream().filter(item -> item.getOpenCloseType() != null && item.getOpenCloseType().equalsIgnoreCase(Item.US_STOCKS)).map(Item::getSymbol).collect(Collectors.joining(","));
- String symbols = aStocSymbols + "," + hkStocSymbols + "," + usStocSymbols;
+ String symbols = usStocSymbols;
List<StockMarket> markets = xueQiuDataService.getMarkets(symbols);
markets.forEach(m -> DataCache.putMarket(m.getSymbol(), m));
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFData.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFData.java
new file mode 100644
index 0000000..57c88a3
--- /dev/null
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFData.java
@@ -0,0 +1,30 @@
+package com.yami.trading.huobi.data.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @program: trading-order-master
+ * @description:
+ * @create: 2025-09-28 14:16
+ **/
+@Data
+public class ETFData {
+ @JsonProperty("ticker")
+ private String ticker;
+
+ @JsonProperty("name")
+ private String name;
+
+ @JsonProperty("is_active")
+ private Integer isActive;
+
+ @JsonProperty("exchange_code")
+ private String exchangeCode;
+
+ @JsonProperty("country_code")
+ private String countryCode;
+
+ @JsonProperty("currency_code")
+ private String currencyCode;
+}
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFResponse.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFResponse.java
new file mode 100644
index 0000000..66ca9b1
--- /dev/null
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/ETFResponse.java
@@ -0,0 +1,19 @@
+package com.yami.trading.huobi.data.model;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @program: trading-order-master
+ * @description:
+ * @create: 2025-09-28 14:18
+ **/
+@Data
+public class ETFResponse {
+
+ private String msg;
+ private Integer code;
+ private List<ETFData> data;
+
+}
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeData.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeData.java
new file mode 100644
index 0000000..8efe937
--- /dev/null
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeData.java
@@ -0,0 +1,35 @@
+package com.yami.trading.huobi.data.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * @program: trading-order-master
+ * @description:
+ * @create: 2025-09-28 14:18
+ **/
+@Data
+public class RealTimeData {
+
+ @JsonProperty("ticker")
+ private String ticker;
+
+ @JsonProperty("close")
+ private Double close;
+
+ @JsonProperty("date")
+ private String date;
+
+ @JsonProperty("open")
+ private Double open;
+
+ @JsonProperty("high")
+ private Double high;
+
+ @JsonProperty("low")
+ private Double low;
+
+ @JsonProperty("volume")
+ private Double volume;
+
+}
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeResponse.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeResponse.java
new file mode 100644
index 0000000..4689111
--- /dev/null
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/data/model/RealTimeResponse.java
@@ -0,0 +1,19 @@
+package com.yami.trading.huobi.data.model;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @program: trading-order-master
+ * @description:
+ * @create: 2025-09-28 14:19
+ **/
+@Data
+public class RealTimeResponse {
+
+ private String msg;
+ private Integer code;
+ private List<RealTimeData> data;
+
+}
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java
index e71ab96..649d4c1 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XinLangDataServiceImpl.java
@@ -65,17 +65,7 @@
private ItemService itemService;
- public static void main(String[] args) {
- XinLangDataServiceImpl service = new XinLangDataServiceImpl();
- List<Realtime> usdsgd = service.realtimeSingle("USDSGD");
- for (Realtime re : usdsgd) {
- System.out.println(JSONObject.toJSONString(re));
- }
-// List<Kline> sz300750 = service.buildOneYearPeriod("AAPL");
-// System.out.println(sz300750.size());
-// List<Kline> eurusd = service.getTimeseriesByPeriodOneDay("EURUSD");
-// System.out.println(JSONObject.toJSONString(eurusd));
- }
+
/**
@@ -142,10 +132,10 @@
return list;
}
- public List<Realtime> realtime(String symbols) {
- List<Realtime> realtimeList = realtimeSingle(symbols);
- return realtimeList;
- }
+// public List<Realtime> realtime(String symbols) {
+// List<Realtime> realtimeList = realtimeSingle(symbols);
+// return realtimeList;
+// }
/**
* 1day 历史数据 : 周期 1年
diff --git a/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XueQiuDataServiceImpl.java b/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XueQiuDataServiceImpl.java
index aed4a9c..029c123 100644
--- a/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XueQiuDataServiceImpl.java
+++ b/trading-order-huobi/src/main/java/com.yami.trading.huobi/hobi/internal/XueQiuDataServiceImpl.java
@@ -7,6 +7,7 @@
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.item.domain.Item;
import com.yami.trading.common.util.RedisUtil;
import com.yami.trading.huobi.data.DataCache;
import com.yami.trading.huobi.data.internal.DepthTimeObject;
@@ -16,6 +17,7 @@
import com.yami.trading.huobi.hobi.http.HttpMethodType;
import com.yami.trading.service.cms.InfomationService;
import com.yami.trading.service.item.ItemService;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
@@ -27,6 +29,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -36,6 +39,7 @@
* 完成需求k线图采集
*/
@Component
+@Slf4j
public class XueQiuDataServiceImpl {
// https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol=TSLA&begin=1682695800000&period=120m&type=before&count=-500&indicator=kline";
public final static String klineUrl = "https://stock.xueqiu.com/v5/stock/chart/kline.json?symbol={}&begin={}&period={}&type=before&count=-500&indicator=kline";
@@ -45,7 +49,7 @@
/**
* live
*/
- public final static String live = "https://stock.xueqiu.com/v5/stock/quote.json";
+ public final static String live = "https://www.tsanghi.com/api/fin/";
public final static String markets = "https://stock.xueqiu.com/v5/stock/quote.json";
public final static String pankou = "https://stock.xueqiu.com/v5/stock/realtime/pankou.json";
@@ -322,55 +326,164 @@
}
public List<Realtime> realtimeSingle(String symbols) {
- List<Realtime> list = new ArrayList<Realtime>();
+ List<Realtime> list = new ArrayList<>();
try {
- List<String> strings = Arrays.asList(symbols.split(","));
- String cookie = HttpHelper.getCookie("https://xueqiu.com/");
- for (String symbol: strings) {
- String result = HttpHelper.sendGetHttp(live, "symbol=" + symbol, cookie);
- JSONObject resultJson = JSON.parseObject(result);
- String code = resultJson.getString("error_code");
- if ("0".equals(code)) {
- JSONObject jsonObject = resultJson.getJSONObject("data").getJSONObject("quote");
- Realtime realtime = new Realtime();
- String currency;
- currency = symbol;
- int decimal = itemService.getDecimal(currency);
- realtime.setSymbol(currency);
- realtime.setName(currency);
- Long timestamp = jsonObject.getLong("timestamp");
- if (timestamp.toString().length() > 13) {
- timestamp = timestamp / 1000;
+ List<String> symbolList = Arrays.asList(symbols.split(","));
+
+ for (String symbol : symbolList) {
+ try {
+ Item item = itemService.findBySymbol(symbol);
+ if (item == null) {
+ log.warn("未找到对应的item: {}", symbol);
+ continue;
}
- realtime.setTs(timestamp);
- realtime.setOpen(jsonObject.getBigDecimal("open").setScale(decimal, RoundingMode.HALF_UP));
- realtime.setClose(jsonObject.getBigDecimal("current").setScale(decimal, RoundingMode.HALF_UP));
- realtime.setHigh(jsonObject.getBigDecimal("high").setScale(decimal, RoundingMode.HALF_UP));
- realtime.setLow(jsonObject.getBigDecimal("low").setScale(decimal, RoundingMode.HALF_UP));
- realtime.setMarketCapital(jsonObject.getLong("market_capital"));
- realtime.setFloatMarketCapital(jsonObject.getLong("float_market_capital"));
- realtime.setPeForecast(jsonObject.getBigDecimal("pe_forecast"));
- realtime.setVolumeRatio(jsonObject.getBigDecimal("volume_ratio"));
- realtime.setTurnoverRate(jsonObject.getBigDecimal("turnover_rate"));
- BigDecimal amount = jsonObject.getBigDecimal("amount");
- if (amount == null) {
- amount = BigDecimal.ZERO;
+
+ String type = "";
+ String exchange = "";
+
+ // 根据类型确定API路径和交易所
+ if ("US-stocks".equals(item.getType())) {
+ type = "stock";
+ exchange = "XNAS"; // 美股纳斯达克
+ } else if ("indices".equals(item.getType()) || "ETF".equals(item.getType())) {
+ type = "etf";
+ exchange = "XNAS"; // ETF也在纳斯达克
+ } else {
+ // 其他类型,默认为股票和上交所
+ type = "stock";
+ exchange = "XSHG";
}
- realtime.setAmount(amount.setScale(decimal, RoundingMode.HALF_UP));
- BigDecimal volume = jsonObject.getBigDecimal("volume");
- if (volume == null) {
- volume = BigDecimal.ZERO;
+
+ // 构建API URL
+ String url = String.format("https://www.tsanghi.com/api/fin/%s/%s/realtime?token=9668db3503214cd19a831a9f866923b9&ticker=%s",
+ type, exchange, symbol);
+
+ String result = HttpHelper.sendGetHttp(url, null, null);
+ JSONObject resultJson = JSON.parseObject(result);
+
+ String code = resultJson.getString("code");
+ if ("200".equals(code)) {
+ JSONArray dataArray = resultJson.getJSONArray("data");
+
+ // 检查数据是否为空
+ if (dataArray == null || dataArray.isEmpty()) {
+ log.warn("股票 {} 的实时数据为空", symbol);
+ continue;
+ }
+
+ // 取第一个数据对象
+ JSONObject dataObject = dataArray.getJSONObject(0);
+
+ Realtime realtime = new Realtime();
+ int decimal = itemService.getDecimal(symbol);
+
+ realtime.setSymbol(symbol);
+ realtime.setName(item.getName() != null ? item.getName() : symbol);
+
+ // 处理时间戳
+ String dateStr = dataObject.getString("date");
+ long timestamp = parseDateTimeToTimestamp(dateStr);
+ if (Long.toString(timestamp).length() > 13) {
+ timestamp = timestamp / 1000;
+ }
+ realtime.setTs(timestamp);
+
+ // 设置价格数据
+ realtime.setOpen(getBigDecimalValue(dataObject, "open", decimal));
+ realtime.setClose(getBigDecimalValue(dataObject, "close", decimal));
+ realtime.setHigh(getBigDecimalValue(dataObject, "high", decimal));
+ realtime.setLow(getBigDecimalValue(dataObject, "low", decimal));
+
+ // 设置成交量和成交额
+ realtime.setVolume(getBigDecimalValue(dataObject, "volume", decimal));
+ realtime.setAmount(getBigDecimalValue(dataObject, "amount", decimal));
+
+ // 设置昨收价
+ BigDecimal preClose = getBigDecimalValue(dataObject, "pre_close", decimal);
+ if (preClose != null) {
+ // 如果Realtime类有preClose字段,取消注释
+ // realtime.setPreClose(preClose);
+ }
+
+ // 处理盘口数据(如果存在)
+ JSONArray buyPriceArray = dataObject.getJSONArray("buy_price");
+ JSONArray sellPriceArray = dataObject.getJSONArray("sell_price");
+ JSONArray buyVolumeArray = dataObject.getJSONArray("buy_volume");
+ JSONArray sellVolumeArray = dataObject.getJSONArray("sell_volume");
+
+ if (buyPriceArray != null && !buyPriceArray.isEmpty()) {
+ realtime.setBid(getBigDecimalFromArray(buyPriceArray, 0, decimal));
+ }
+ if (sellPriceArray != null && !sellPriceArray.isEmpty()) {
+ realtime.setAsk(getBigDecimalFromArray(sellPriceArray, 0, decimal));
+ }
+
+ list.add(realtime);
+ } else {
+ log.warn("API返回错误代码: {}, 股票: {}", code, symbol);
}
- realtime.setVolume(volume.setScale(decimal, RoundingMode.HALF_UP));
-// realtime.setAsk(realtimeJson.getBigDecimal("ask").setScale(decimal, RoundingMode.HALF_UP));
-// realtime.setBid(realtimeJson.getBigDecimal("pb").setScale(decimal, RoundingMode.HALF_UP));
- list.add(realtime);
+ } catch (Exception e) {
+ log.error("处理股票 {} 时发生错误", symbol, e);
}
}
} catch (Exception e) {
- logger.error("error", e);
+ log.error("获取实时数据失败", e);
}
return list;
+ }
+
+ /**
+ * 将日期时间字符串转换为时间戳
+ * 格式: "yyyy-mm-dd hh:mm:ss"
+ */
+ private long parseDateTimeToTimestamp(String dateTimeStr) {
+ try {
+ if (dateTimeStr == null || dateTimeStr.isEmpty()) {
+ return System.currentTimeMillis();
+ }
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ Date date = sdf.parse(dateTimeStr);
+ return date.getTime();
+ } catch (Exception e) {
+ log.error("日期时间解析失败: {}", dateTimeStr, e);
+ return System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * 安全获取BigDecimal值
+ */
+ private BigDecimal getBigDecimalValue(JSONObject jsonObject, String key, int decimal) {
+ try {
+ BigDecimal value = jsonObject.getBigDecimal(key);
+ if (value == null) {
+ return BigDecimal.ZERO;
+ }
+ return value.setScale(decimal, RoundingMode.HALF_UP);
+ } catch (Exception e) {
+ log.warn("获取字段 {} 失败", key, e);
+ return BigDecimal.ZERO;
+ }
+ }
+
+ /**
+ * 从JSONArray中获取BigDecimal值
+ */
+ private BigDecimal getBigDecimalFromArray(JSONArray jsonArray, int index, int decimal) {
+ try {
+ if (jsonArray == null || jsonArray.size() <= index) {
+ return BigDecimal.ZERO;
+ }
+ BigDecimal value = jsonArray.getBigDecimal(index);
+ if (value == null) {
+ return BigDecimal.ZERO;
+ }
+ return value.setScale(decimal, RoundingMode.HALF_UP);
+ } catch (Exception e) {
+ log.warn("从数组获取数据失败", e);
+ return BigDecimal.ZERO;
+ }
}
public List<Realtime> realtime(String symbols) {
@@ -389,25 +502,25 @@
map.put(Kline.PERIOD_1MON, buildOneMonthPeriod(symbol));
map.put(Kline.PERIOD_1DAY, buildOneDayPeriod(symbol));
map.put(Kline.PERIOD_5DAY, buildFiveDayPeriod(symbol));
- map.put(Kline.PERIOD_QUARTER, buildOneQuarterPeriod(symbol));
+// map.put(Kline.PERIOD_QUARTER, buildOneQuarterPeriod(symbol));
map.put(Kline.PERIOD_YEAR, buildOneYearPeriod(symbol));
return map;
}
public List<Kline> buildOneDayPeriod(String currency) {
- return getTimeseriesByPeriod(currency, "day", Kline.PERIOD_1DAY, 365);
+ return getTimeseriesByPeriod(currency, "daily", Kline.PERIOD_1DAY, 365);
}
public List<Kline> buildOneWeekPeriod(String currency) {
- return getTimeseriesByPeriod(currency, "week", Kline.PERIOD_1WEEK, 365 * 5);
+ return getTimeseriesByPeriod(currency, "weekly", Kline.PERIOD_1WEEK, 365 * 5);
}
public List<Kline> buildOneMonthPeriod(String currency) {
- return getTimeseriesByPeriod(currency, "month", Kline.PERIOD_1MON, 365 * 5);
+ return getTimeseriesByPeriod(currency, "monthly", Kline.PERIOD_1MON, 365 * 5);
}
public List<Kline> buildOneQuarterPeriod(String currency) {
@@ -415,7 +528,7 @@
}
public List<Kline> buildOneYearPeriod(String currency) {
- return getTimeseriesByPeriod(currency, "year", Kline.PERIOD_YEAR, 365 * 100);
+ return getTimeseriesByPeriod(currency, "yearly", Kline.PERIOD_YEAR, 365 * 100);
}
/**
@@ -588,64 +701,144 @@
public List<Kline> getTimeseriesByPeriod(String currency, String periodXieQiu, String sysPeriod, long limitDays) {
List<Kline> resList = new ArrayList<>();
- long nowTs = System.currentTimeMillis();
- long startTs = System.currentTimeMillis() - limitDays * 24 * 60 * 60 * 1000;
- long begin = nowTs;
- String cookie = HttpHelper.getCookie("https://xueqiu.com/");
- Set<Long> tsSet = new HashSet<>();
- while (begin > startTs) {
- String url = StrUtil.format(klineUrl, currency, begin, periodXieQiu);
- String json = HttpHelper.sendGetHttp(url, null, cookie);
+ try {
+ // 获取商品信息判断类型
+ Item itemData = itemService.findBySymbol(currency);
+ String type = "stock"; // 默认股票
+ String exchange = "XNAS"; // 默认纳斯达克
+
+ if (itemData != null) {
+ if ("ETF".equals(itemData.getType()) || "etf".equals(itemData.getType()) ||
+ "indices".equals(itemData.getType()) || currency.startsWith("51") ||
+ currency.startsWith("15") || currency.startsWith("16")) {
+ type = "etf";
+ // ETF可能在不同的交易所,根据实际情况调整
+ exchange = "XNAS"; // 或者可能是XSHG等其他交易所
+ } else if ("US-stocks".equals(itemData.getType())) {
+ type = "stock";
+ exchange = "XNAS";
+ } else {
+ // 其他类型默认为A股股票
+ type = "stock";
+ exchange = "XSHG";
+ }
+ } else {
+ // 如果没有找到item信息,根据symbol特征猜测类型
+ if (currency.startsWith("51") || currency.startsWith("15") || currency.startsWith("16")) {
+ type = "etf";
+ exchange = "XSHG"; // A股ETF
+ } else if (currency.matches("[A-Z]+")) {
+ type = "stock";
+ exchange = "XNAS"; // 美股
+ } else {
+ type = "stock";
+ exchange = "XSHG"; // 默认A股
+ }
+ }
+
+ log.debug("获取K线数据,symbol: {}, 类型: {}, 交易所: {}, 周期: {}",
+ currency, type, exchange, periodXieQiu);
+
+ // 构建API URL
+ String url = StrUtil.format("https://www.tsanghi.com/api/fin/{}/{}/{}?token=9668db3503214cd19a831a9f866923b9&ticker={}&order=2",
+ type, exchange, periodXieQiu, currency);
+
+ // 发送HTTP请求
+ String json = HttpHelper.sendGetHttp(url, null, null);
JSONObject resultJson = JSON.parseObject(json);
- JSONArray dataArray = resultJson.getJSONObject("data").getJSONArray("item");
- List<List> lists = dataArray.toJavaList(List.class);
- long minTS = begin;
- for (List result : lists) {
+
+ // 检查API响应是否成功
+ if (resultJson == null || !resultJson.containsKey("data")) {
+ log.error("API响应数据格式异常: {}", json);
+ return resList;
+ }
+
+ JSONArray dataArray = resultJson.getJSONArray("data");
+ if (dataArray == null || dataArray.isEmpty()) {
+ log.warn("未获取到K线数据");
+ return resList;
+ }
+
+ // 计算时间范围
+ long endTime = System.currentTimeMillis();
+ long startTime = endTime - limitDays * 24 * 60 * 60 * 1000L;
+
+ Set<String> dateSet = new HashSet<>();
+
+ // 解析数据
+ for (int i = 0; i < dataArray.size(); i++) {
+ JSONObject item = dataArray.getJSONObject(i);
+
+ // 解析日期
+ String dateStr = item.getString("date");
+ if (dateSet.contains(dateStr)) {
+ continue;
+ }
+ dateSet.add(dateStr);
+
+ // 将日期转换为时间戳
+ long ts = parseDateToTimestamp(dateStr);
+
+ // 检查时间范围
+ if (ts < startTime) {
+ continue;
+ }
+
Kline kline = new Kline();
kline.setSymbol(currency);
kline.setPeriod(sysPeriod);
- // 毫秒
- long ts = Long.parseLong(result.get(0).toString());
- if (Long.toString(ts).length() > 13) {
- ts = ts / 1000;
- }
- if (tsSet.contains(ts)) {
- continue;
- } else {
- tsSet.add(ts);
- }
kline.setTs(ts);
- kline.setOpen(new BigDecimal(result.get(2).toString()));
- kline.setClose(new BigDecimal(result.get(5).toString()));
- kline.setHigh(new BigDecimal(result.get(3).toString()));
- kline.setLow(new BigDecimal(result.get(4).toString()));
- kline.setVolume(new BigDecimal(result.get(1).toString()));
- kline.setAmount(new BigDecimal(result.get(9).toString()));
+ kline.setOpen(item.getBigDecimal("open"));
+ kline.setClose(item.getBigDecimal("close"));
+ kline.setHigh(item.getBigDecimal("high"));
+ kline.setLow(item.getBigDecimal("low"));
+ kline.setVolume(item.getBigDecimal("volume"));
+
+ // 如果有amount字段就设置,没有就设为0
+ if (item.containsKey("amount")) {
+ kline.setAmount(item.getBigDecimal("amount"));
+ } else {
+ kline.setAmount(BigDecimal.ZERO);
+ }
+
+ // 修复K线数据(如果有修复逻辑)
if (klineService != null) {
klineService.repairKline(kline);
}
+
resList.add(kline);
- if (ts < minTS) {
- minTS = ts;
- }
+ }
+ // 按时间戳升序排序
+ Collections.sort(resList);
+
+ // 如果需要设置开盘价为前一根的收盘价
+ int len = resList.size();
+ for (int i = 1; i < len; i++) {
+ resList.get(i).setOpen(resList.get(i - 1).getClose());
}
- if (minTS == begin) {
- break;
- }
- begin = minTS;
- if (begin < startTs) {
- break;
- }
+
+ } catch (Exception e) {
+ log.error("获取K线数据失败: {}", currency, e);
}
- Collections.sort(resList);
- int len = resList.size();
- for (int i = 1; i < len; i++) {
- resList.get(i).setOpen(resList.get(i - 1).getClose());
- }
+
return resList;
+ }
+ /**
+ * 将日期字符串转换为时间戳
+ * 格式: "yyyy-mm-dd"
+ */
+ private long parseDateToTimestamp(String dateStr) {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ Date date = sdf.parse(dateStr);
+ return date.getTime();
+ } catch (Exception e) {
+ log.error("日期解析失败: {}", dateStr, e);
+ return System.currentTimeMillis();
+ }
}
public List<Kline> getTimeseriesByMinute(String currency, int minute, long limitDays) {
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java
index 00ea947..635ba0d 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/exchange/impl/ExchangeApplyOrderServiceImpl.java
@@ -111,11 +111,11 @@
double amount = Arith.mul(sub, realtime.getClose().doubleValue());
order.setCloseTime(new Date());
order.setClosePrice(realtime.getClose().doubleValue());
-// Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId());
- CapitaltWallet capitaltWallet = capitaltWalletService.getUserIdWallet(order.getPartyId());
- double amount_before = capitaltWallet.getMoney().doubleValue();
-// this.walletService.update(userIdWallet.getUserId().toString(), amount);
- this.capitaltWalletService.update(capitaltWallet, amount);
+ Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId());
+// CapitaltWallet capitaltWallet = capitaltWalletService.getUserIdWallet(order.getPartyId());
+ double amount_before = wallet.getMoney().doubleValue();
+ this.walletService.update(wallet.getUserId().toString(), amount);
+// this.capitaltWalletService.update(capitaltWallet, amount);
/*
* 保存资金日志
@@ -124,7 +124,7 @@
moneylog_deposit.setCategory(Constants.MONEYLOG_CATEGORY_EXCHANGE);
moneylog_deposit.setAmountBefore(new BigDecimal(amount_before));
moneylog_deposit.setAmount(new BigDecimal(amount));
- moneylog_deposit.setAmountAfter(capitaltWallet.getMoney());
+ moneylog_deposit.setAmountAfter(wallet.getMoney());
moneylog_deposit.setLog("委托单,订单号[" + order.getOrderNo() + "]");
moneylog_deposit.setUserId(order.getPartyId());
moneylog_deposit.setWalletType(Constants.WALLET);
@@ -615,8 +615,8 @@
// 可以买的数量
double amount = Arith.div(sub, order.getClosePrice(), 8);
order.setSymbolValue(amount);
-// Wallet wallet = this.walletService.saveWalletByPartyId(order.getPartyId());
- CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(order.getPartyId());
+ Wallet userIdWallet = this.walletService.saveWalletByPartyId(order.getPartyId());
+// CapitaltWallet userIdWallet = capitaltWalletService.getUserIdWallet(order.getPartyId());
double amount_before = userIdWallet.getMoney().doubleValue();
// 如果是计划委托,则先不扣钱
if (order.isTriggerOrder()) {
@@ -643,8 +643,8 @@
if (userIdWallet.getMoney().doubleValue() < order.getVolume().doubleValue()) {
throw new YamiShopBindException("余额不足");
}
-// this.walletService.update(userIdWallet.getUserId().toString(), Arith.sub(0, order.getVolume()));
- capitaltWalletService.update(userIdWallet, Arith.sub(0, order.getVolume()));
+ this.walletService.update(userIdWallet.getUserId().toString(), Arith.sub(0, order.getVolume()));
+// capitaltWalletService.update(userIdWallet, Arith.sub(0, order.getVolume()));
/*
* 保存资金日志
*/
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
index ee52404..d6c6276 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
@@ -135,10 +135,15 @@
//
// walletService.update(wallet.getUserId(), amount1);
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, recharge.getPartyId()).last(" limit 1 "));
- double amount_before = capitaltWallet.getMoney().doubleValue();
- capitaltWalletService.update(capitaltWallet,amount1);
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, recharge.getPartyId()).last(" limit 1 "));
+// double amount_before = capitaltWallet.getMoney().doubleValue();
+// capitaltWalletService.update(capitaltWallet,amount1);
+
+ Wallet wallet = walletService.getOne(new LambdaQueryWrapper<>(Wallet.class)
+ .eq(Wallet::getUserId, recharge.getPartyId()).last(" limit 1 "));
+ double amount_before = wallet.getMoney().doubleValue();
+ walletService.update(wallet.getUserId(),amount1);
// 保存资金日志
MoneyLog moneyLog = new MoneyLog();
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java
index b132fc4..a883d85 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java
@@ -151,14 +151,24 @@
// walletService.update(wallet.getUserId().toString(),
// Arith.add(withdraw.getAmount(), withdraw.getAmountFee()));
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, wallet.getUserId().toString()).last(" limit 1 "));
- if(ObjectUtil.isEmpty(capitaltWallet)){
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, wallet.getUserId().toString()).last(" limit 1 "));
+// if(ObjectUtil.isEmpty(capitaltWallet)){
+// throw new YamiShopBindException("用户资金账户不存在!");
+// }
+// capitaltWalletService.update(new LambdaUpdateWrapper<CapitaltWallet>()
+// .set(CapitaltWallet::getMoney,new BigDecimal(Arith.add(capitaltWallet.getMoney(), withdraw.getVolume())))
+// .eq(CapitaltWallet::getUserId,wallet.getUserId()));
+
+ Wallet wallet1 = walletService.getOne(new LambdaQueryWrapper<>(Wallet.class)
+ .eq(Wallet::getUserId, wallet.getUserId().toString()).last(" limit 1 "));
+ if(ObjectUtil.isEmpty(wallet1)){
throw new YamiShopBindException("用户资金账户不存在!");
}
- capitaltWalletService.update(new LambdaUpdateWrapper<CapitaltWallet>()
- .set(CapitaltWallet::getMoney,new BigDecimal(Arith.add(capitaltWallet.getMoney(), withdraw.getVolume())))
- .eq(CapitaltWallet::getUserId,wallet.getUserId()));
+ walletService.update(new LambdaUpdateWrapper<Wallet>()
+ .set(Wallet::getMoney,new BigDecimal(Arith.add(wallet1.getMoney(), withdraw.getVolume())))
+ .eq(Wallet::getUserId,wallet.getUserId()));
+
/*
@@ -482,11 +492,11 @@
throw new YamiShopBindException("Your account has been frozen");
}
-// Wallet wallet = walletService.saveWalletByPartyId(withdraw.getUserId());
+ Wallet wallet = walletService.saveWalletByPartyId(withdraw.getUserId());
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, withdraw.getUserId()).last(" limit 1 "));
- if (capitaltWallet.getMoney().doubleValue() < withdraw.getVolume().doubleValue()) {
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, withdraw.getUserId()).last(" limit 1 "));
+ if (wallet.getMoney().doubleValue() < withdraw.getVolume().doubleValue()) {
throw new YamiShopBindException("not sufficient funds");
}
// 手续费(USDT)
@@ -671,17 +681,17 @@
*/
String withdraw_qr = qRGenerateService.generateWithdraw(withdraw.getOrderNo(), withdraw.getAddress());
withdraw.setQdcode(withdraw_qr);
- double amount_before = capitaltWallet.getMoney().doubleValue();
+ double amount_before = wallet.getMoney().doubleValue();
// walletService.update(wallet.getUserId().toString(), Arith.sub(0, withdraw.getVolume().doubleValue()));
- if(ObjectUtil.isEmpty(capitaltWallet)){
+ if(ObjectUtil.isEmpty(wallet)){
throw new YamiShopBindException("The user's funds account does not exist!");
}
- capitaltWalletService.update(capitaltWallet,-withdraw.getVolume().doubleValue());
+ walletService.update(wallet.getUserId(),-withdraw.getVolume().doubleValue());
save(withdraw);
@@ -692,7 +702,7 @@
moneyLog.setCategory(Constants.MONEYLOG_CATEGORY_COIN);
moneyLog.setAmountBefore(new BigDecimal(amount_before));
moneyLog.setAmount(new BigDecimal(Arith.sub(0, withdraw.getVolume().doubleValue())));
- moneyLog.setAmountAfter(capitaltWallet.getMoney());
+ moneyLog.setAmountAfter(wallet.getMoney());
moneyLog.setLog("提现订单[" + withdraw.getOrderNo() + "]");
// moneyLog.setExtra(withdraw.getOrder_no());
moneyLog.setUserId(withdraw.getUserId());
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 5c0e090..6735b3b 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
@@ -162,7 +162,7 @@
@Cached(name = ITEM_CACHE, key = "'all'", expire = 3600)
@Override
public List<Item> list() {
- List<Item> list = super.list(new LambdaQueryWrapper<>(Item.class).eq(Item::getType,Item.cryptos));
+ List<Item> list = super.list(new LambdaQueryWrapper<>(Item.class).eq(Item::getDelFlag,0));
symbolDecimal = list.stream()
.collect(Collectors.toMap(Item::getSymbol, Item::getDecimals, (s1, s2) -> s2));
return list;
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserStatisticsServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserStatisticsServiceImpl.java
index 2274407..cd5de8f 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserStatisticsServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserStatisticsServiceImpl.java
@@ -118,8 +118,10 @@
result.add(0,data);
Map<String,Object> capitaldata = new HashMap<String,Object>();
- CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
- .eq(CapitaltWallet::getUserId, targetPartyId).last(" limit 1 "));
+// CapitaltWallet capitaltWallet = capitaltWalletService.getOne(new LambdaQueryWrapper<>(CapitaltWallet.class)
+// .eq(CapitaltWallet::getUserId, targetPartyId).last(" limit 1 "));
+ Wallet capitaltWallet = walletService.getOne(new LambdaQueryWrapper<>(Wallet.class)
+ .eq(Wallet::getUserId, targetPartyId).last(" limit 1 "));
capitaldata.put("wallettype", "capitalusdt");
capitaldata.put("amount",null==capitaltWallet?0:new BigDecimal(capitaltWallet.getMoney().doubleValue()).setScale(8, RoundingMode.FLOOR).toPlainString() );
capitaldata.put("lock_amount",null==capitaltWallet?0:capitaltWallet.getLockMoney().setScale(8, RoundingMode.FLOOR).toPlainString() );
--
Gitblit v1.9.3