This commit is contained in:
sion
2026-04-06 16:33:03 +08:00
parent b9234b1121
commit 71c8689989
19 changed files with 231 additions and 6 deletions

View File

@@ -7,6 +7,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -14,6 +15,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@ServletComponentScan(basePackages ={"com.it.rattan"})
@ComponentScan(basePackages ={"com.it.rattan"})
@EnableTransactionManagement
@EnableScheduling
/*@EnableAsync
@EnableAspectJAutoProxy*/
public class SpcCloudApplication {

View File

@@ -90,6 +90,24 @@ public class Coin implements Serializable {
/** 排序权重(越大越靠前) */
private Integer sort;
/** 交易开始时间 HH:mm */
private String tradeStartTime;
/** 交易结束时间 HH:mm */
private String tradeEndTime;
/** 每日最大涨跌幅(%) */
private BigDecimal maxChangePercent;
/** K线模拟最低价 */
private BigDecimal priceMin;
/** K线模拟最高价 */
private BigDecimal priceMax;
/** 1=启用K线模拟 */
private Integer simulationEnabled;
/** 创建时间 */
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

View File

@@ -25,6 +25,9 @@ public class TokenFilter implements Filter {
"/api/user/register",
"/api/user/login",
"/api/wallet/default",
"/api/wallet/networks",
"/api/kline/",
"/ws/",
"/admin/login",
"/uploads/",
"/swagger-resources",

View File

@@ -92,9 +92,10 @@ public class AssetService {
result.put("tradeBalance", tradeBalance);
BigDecimal totalAsset = fundBalance.add(tradeBalance);
result.put("totalAsset", totalAsset);
// 总盈亏 = 总资产 - 累计充值(用户净投入为累计充值,总资产超出部分即为盈利)
// 总盈亏 = 总资产 + 累计提现 - 累计充值(净投入 = 充值 - 提现,总资产超出净投入即为盈利)
BigDecimal totalDeposit = fund.getTotalDeposit() != null ? fund.getTotalDeposit() : BigDecimal.ZERO;
result.put("totalProfit", totalAsset.subtract(totalDeposit));
BigDecimal totalWithdraw = fund.getTotalWithdraw() != null ? fund.getTotalWithdraw() : BigDecimal.ZERO;
result.put("totalProfit", totalAsset.add(totalWithdraw).subtract(totalDeposit));
return result;
}

View File

@@ -132,6 +132,25 @@ public class CoinService extends ServiceImpl<CoinMapper, Coin> {
return list(wrapper);
}
/**
* 更新缓存中的币种价格K线模拟专用不写DB
*/
public void updateCachedPrice(String code, BigDecimal price) {
String key = code.toUpperCase();
Coin cached = coinCodeCache.get(key);
if (cached != null) {
cached.setPrice(price);
}
if (cachedActiveCoins != null) {
for (Coin coin : cachedActiveCoins) {
if (coin.getCode().equalsIgnoreCase(key)) {
coin.setPrice(price);
break;
}
}
}
}
/**
* 清除所有缓存(币种数据变更时调用)
*/

View File

@@ -14,6 +14,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
@@ -48,6 +50,9 @@ public class TradeService {
throw new RuntimeException("该币种已下架");
}
// 模拟币种交易校验
validateSimulationTrade(coin, price);
// 计算金额
BigDecimal amount = price.multiply(quantity).setScale(8, RoundingMode.DOWN);
@@ -128,6 +133,9 @@ public class TradeService {
throw new RuntimeException("该币种已下架");
}
// 模拟币种交易校验
validateSimulationTrade(coin, price);
// 检查持仓
AccountTrade coinAccount = assetService.getOrCreateTradeAccount(userId, coinCode);
if (coinAccount.getQuantity().compareTo(quantity) < 0) {
@@ -214,4 +222,43 @@ public class TradeService {
.eq(OrderTrade::getOrderNo, orderNo);
return orderTradeMapper.selectOne(wrapper);
}
/**
* 模拟币种交易校验:交易时段 + 价格一致性
*/
private void validateSimulationTrade(Coin coin, BigDecimal tradePrice) {
if (coin.getSimulationEnabled() == null || coin.getSimulationEnabled() != 1) {
return;
}
// 校验交易时段
if (coin.getTradeStartTime() != null && coin.getTradeEndTime() != null) {
try {
LocalTime now = LocalTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm");
LocalTime start = LocalTime.parse(coin.getTradeStartTime(), fmt);
LocalTime end = LocalTime.parse(coin.getTradeEndTime(), fmt);
boolean inRange;
if (end.isAfter(start)) {
inRange = !now.isBefore(start) && !now.isAfter(end);
} else {
inRange = !now.isBefore(start) || !now.isAfter(end);
}
if (!inRange) {
throw new RuntimeException("当前不在交易时段内(" + coin.getTradeStartTime() + " - " + coin.getTradeEndTime() + "");
}
} catch (RuntimeException e) {
throw e;
} catch (Exception ignored) {}
}
// 校验价格一致性(允许 0.1% 滑点)
if (coin.getPrice() != null && coin.getPrice().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal diff = tradePrice.subtract(coin.getPrice()).abs();
BigDecimal threshold = coin.getPrice().multiply(new BigDecimal("0.001"));
if (diff.compareTo(threshold) > 0) {
throw new RuntimeException("交易价格已变化,请刷新后重试");
}
}
}
}

View File

@@ -7,6 +7,17 @@ spring:
enabled: true
max-file-size: 5MB
max-request-size: 10MB
redis:
host: 8.155.172.147
port: 6379
password: sion+Rui!$
database: 1
timeout: 3000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 2
datasource:
username: monisuo
password: JPJ8wYicSGC8aRnk