111
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存(币种数据变更时调用)
|
||||
*/
|
||||
|
||||
@@ -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("交易价格已变化,请刷新后重试");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user