|
@@ -74,59 +74,116 @@ public class StockPoolServiceImpl implements IStockPoolService {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public Boolean insertByBo(StockPoolBo bo) {
|
|
public Boolean insertByBo(StockPoolBo bo) {
|
|
|
- // 先检查是否已存在(不限制status,因为唯一索引包含status)
|
|
|
|
|
- LambdaQueryWrapper<StockPool> checkWrapper = Wrappers.lambdaQuery();
|
|
|
|
|
- checkWrapper.eq(StockPool::getStockCode, bo.getStockCode())
|
|
|
|
|
|
|
+ LocalDate addDate = bo.getAddDate() != null ? bo.getAddDate() : LocalDate.now();
|
|
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
|
|
+
|
|
|
|
|
+ // 根据日期确定状态:当天=2(当前有效),历史=1(历史有效)
|
|
|
|
|
+ Integer targetStatus = addDate.equals(today) ? 2 : 1;
|
|
|
|
|
+
|
|
|
|
|
+ log.info("[添加股票到池] stockCode={}, poolType={}, addDate={}, status={}",
|
|
|
|
|
+ bo.getStockCode(), bo.getPoolType(), addDate, targetStatus);
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 先检查是否已存在当前有效的记录(status=2)
|
|
|
|
|
+ LambdaQueryWrapper<StockPool> activeWrapper = Wrappers.lambdaQuery();
|
|
|
|
|
+ activeWrapper.eq(StockPool::getStockCode, bo.getStockCode())
|
|
|
.eq(StockPool::getPoolType, bo.getPoolType())
|
|
.eq(StockPool::getPoolType, bo.getPoolType())
|
|
|
- .orderByDesc(StockPool::getId)
|
|
|
|
|
- .last("LIMIT 1");
|
|
|
|
|
- StockPool existing = baseMapper.selectOne(checkWrapper);
|
|
|
|
|
|
|
+ .eq(StockPool::getStatus, 2);
|
|
|
|
|
+ if (baseMapper.selectCount(activeWrapper) > 0) {
|
|
|
|
|
+ log.warn("[添加股票到池] 股票已存在: {}", bo.getStockCode());
|
|
|
|
|
+ throw new RuntimeException("该股票已在池中");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- LocalDate today = LocalDate.now();
|
|
|
|
|
|
|
+ // 2. 检查指定日期是否已有记录(任何状态),如果有则修改状态
|
|
|
|
|
+ LambdaQueryWrapper<StockPool> dateWrapper = Wrappers.lambdaQuery();
|
|
|
|
|
+ dateWrapper.eq(StockPool::getStockCode, bo.getStockCode())
|
|
|
|
|
+ .eq(StockPool::getPoolType, bo.getPoolType())
|
|
|
|
|
+ .eq(StockPool::getAddDate, addDate);
|
|
|
|
|
+ StockPool existing = baseMapper.selectOne(dateWrapper);
|
|
|
|
|
|
|
|
if (existing != null) {
|
|
if (existing != null) {
|
|
|
- if (existing.getStatus() == 2) {
|
|
|
|
|
- // 已经在池中,无需操作
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- // 已移除的记录,恢复状态
|
|
|
|
|
- existing.setStatus(2);
|
|
|
|
|
|
|
+ // 指定日期已有记录,修改状态
|
|
|
|
|
+ existing.setStatus(targetStatus);
|
|
|
existing.setAdminId(LoginHelper.getUserId());
|
|
existing.setAdminId(LoginHelper.getUserId());
|
|
|
existing.setUpdateTime(LocalDateTime.now());
|
|
existing.setUpdateTime(LocalDateTime.now());
|
|
|
- existing.setAddDate(today);
|
|
|
|
|
- // 更新入池价格
|
|
|
|
|
- BigDecimal price = fetchCurrentPrice(bo.getStockCode());
|
|
|
|
|
- existing.setAddPrice(price != null ? price : BigDecimal.ZERO);
|
|
|
|
|
- // 从历史信息中查询当天的收盘价
|
|
|
|
|
- existing.setClosePrice(fetchClosePriceFromHistory(bo.getStockCode(), today));
|
|
|
|
|
- return baseMapper.updateById(existing) > 0;
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- // 不存在,新增
|
|
|
|
|
- StockPool entity = BeanUtil.toBean(bo, StockPool.class);
|
|
|
|
|
- entity.setStatus(2);
|
|
|
|
|
- entity.setAdminId(LoginHelper.getUserId());
|
|
|
|
|
- entity.setCreateTime(LocalDateTime.now());
|
|
|
|
|
- entity.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
|
|
+ // 从历史信息中查询收盘价
|
|
|
|
|
+ BigDecimal closePrice = fetchClosePriceFromHistory(bo.getStockCode(), addDate);
|
|
|
|
|
+ existing.setClosePrice(closePrice);
|
|
|
|
|
|
|
|
- if (entity.getAddDate() == null) {
|
|
|
|
|
- entity.setAddDate(today);
|
|
|
|
|
|
|
+ // 如果不是今天,尝试计算隔日数据
|
|
|
|
|
+ if (!addDate.equals(today)) {
|
|
|
|
|
+ calculateNextDayData(existing, addDate);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return baseMapper.updateById(existing) > 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 如果没有传入价格,尝试获取实时价格
|
|
|
|
|
- if (entity.getAddPrice() == null) {
|
|
|
|
|
- BigDecimal price = fetchCurrentPrice(entity.getStockCode());
|
|
|
|
|
- entity.setAddPrice(price != null ? price : BigDecimal.ZERO);
|
|
|
|
|
|
|
+ // 3. 插入新记录
|
|
|
|
|
+ StockPool pool = new StockPool();
|
|
|
|
|
+ pool.setStockCode(bo.getStockCode());
|
|
|
|
|
+ pool.setStockName(bo.getStockName());
|
|
|
|
|
+ pool.setPoolType(bo.getPoolType());
|
|
|
|
|
+ pool.setAddDate(addDate);
|
|
|
|
|
+ pool.setStatus(targetStatus); // 使用计算出的状态
|
|
|
|
|
+ pool.setAdminId(LoginHelper.getUserId());
|
|
|
|
|
+ pool.setCreateTime(LocalDateTime.now());
|
|
|
|
|
+ pool.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
+
|
|
|
|
|
+ // 从历史信息中查询收盘价
|
|
|
|
|
+ BigDecimal closePrice = fetchClosePriceFromHistory(bo.getStockCode(), addDate);
|
|
|
|
|
+ pool.setClosePrice(closePrice);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是今天,获取实时价格作为入池价
|
|
|
|
|
+ if (addDate.equals(today)) {
|
|
|
|
|
+ BigDecimal currentPrice = fetchCurrentPrice(bo.getStockCode());
|
|
|
|
|
+ pool.setAddPrice(currentPrice != null ? currentPrice : BigDecimal.ZERO);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果是历史日期,使用收盘价作为入池价
|
|
|
|
|
+ pool.setAddPrice(closePrice != null ? closePrice : BigDecimal.ZERO);
|
|
|
|
|
+ // 计算隔日数据
|
|
|
|
|
+ calculateNextDayData(pool, addDate);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 从历史信息中查询当天的收盘价
|
|
|
|
|
- entity.setClosePrice(fetchClosePriceFromHistory(entity.getStockCode(), today));
|
|
|
|
|
|
|
+ return baseMapper.insert(pool) > 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- boolean flag = baseMapper.insert(entity) > 0;
|
|
|
|
|
- if (flag) {
|
|
|
|
|
- bo.setId(entity.getId());
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 计算隔日最高价和隔日涨幅
|
|
|
|
|
+ */
|
|
|
|
|
+ private void calculateNextDayData(StockPool pool, LocalDate addDate) {
|
|
|
|
|
+ // 查询下一个交易日的历史数据(向后查找最多7天)
|
|
|
|
|
+ for (int i = 1; i <= 7; i++) {
|
|
|
|
|
+ LocalDate nextDate = addDate.plusDays(i);
|
|
|
|
|
+ LambdaQueryWrapper<StockPoolHistory> wrapper = Wrappers.lambdaQuery();
|
|
|
|
|
+ wrapper.eq(StockPoolHistory::getStockCode, pool.getStockCode())
|
|
|
|
|
+ .eq(StockPoolHistory::getRecordDate, nextDate)
|
|
|
|
|
+ .last("LIMIT 1");
|
|
|
|
|
+ StockPoolHistory nextDayHistory = stockPoolHistoryMapper.selectOne(wrapper);
|
|
|
|
|
+
|
|
|
|
|
+ if (nextDayHistory != null) {
|
|
|
|
|
+ // 找到下一个交易日的数据
|
|
|
|
|
+ BigDecimal nextDayHigh = nextDayHistory.getDayHighestPrice();
|
|
|
|
|
+ if (nextDayHigh == null) {
|
|
|
|
|
+ nextDayHigh = nextDayHistory.getClosePrice();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (nextDayHigh != null && pool.getClosePrice() != null &&
|
|
|
|
|
+ pool.getClosePrice().compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
+ // 计算隔日涨幅
|
|
|
|
|
+ BigDecimal nextDayGain = nextDayHigh.subtract(pool.getClosePrice())
|
|
|
|
|
+ .divide(pool.getClosePrice(), 4, RoundingMode.HALF_UP)
|
|
|
|
|
+ .multiply(new BigDecimal("100"))
|
|
|
|
|
+ .setScale(2, RoundingMode.HALF_UP);
|
|
|
|
|
+
|
|
|
|
|
+ pool.setNextDayHigh(nextDayHigh);
|
|
|
|
|
+ pool.setNextDayGain(nextDayGain);
|
|
|
|
|
+
|
|
|
|
|
+ log.info("[计算隔日数据] 股票={}, 加入日期={}, 下一交易日={}, 隔日最高={}, 隔日涨幅={}%",
|
|
|
|
|
+ pool.getStockCode(), addDate, nextDate, nextDayHigh, nextDayGain);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- return flag;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -167,6 +224,17 @@ public class StockPoolServiceImpl implements IStockPoolService {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Boolean updateStatus(Long id, Integer status) {
|
|
|
|
|
+ StockPool pool = baseMapper.selectById(id);
|
|
|
|
|
+ if (pool == null) {
|
|
|
|
|
+ throw new RuntimeException("记录不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ pool.setStatus(status);
|
|
|
|
|
+ pool.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
+ return baseMapper.updateById(pool) > 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 构建查询条件
|
|
* 构建查询条件
|
|
|
*/
|
|
*/
|