Преглед на файлове

强势池最高涨幅计算修改

Zhangbw преди 1 месец
родител
ревизия
970c8928ea

+ 16 - 0
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/mapper/StockPoolHistoryMapper.java

@@ -50,4 +50,20 @@ public interface StockPoolHistoryMapper extends BaseMapperPlus<StockPoolHistory,
     BigDecimal selectMaxHighPriceInRange(@Param("stockCode") String stockCode,
                                          @Param("startDate") LocalDate startDate,
                                          @Param("endDate") LocalDate endDate);
+
+    /**
+     * 查询指定股票从指定日期开始向后10天的最高价(用于计算high_trend)
+     * @param stockCode 股票代码
+     * @param startDate 开始日期(记录日期)
+     * @param endDate 结束日期(当前导入日期,限制查询范围)
+     * @return 向后10天内最高价,如果没有则返回null
+     */
+    @Select("SELECT MAX(day_highest_price) FROM stock_pool_history " +
+            "WHERE stock_code = #{stockCode} " +
+            "AND record_date >= #{startDate} " +
+            "AND record_date <= #{endDate} " +
+            "AND record_date <= DATE_ADD(#{startDate}, INTERVAL 10 DAY)")
+    BigDecimal selectForwardTenDaysHighestPrice(@Param("stockCode") String stockCode,
+                                                @Param("startDate") LocalDate startDate,
+                                                @Param("endDate") LocalDate endDate);
 }

+ 96 - 4
ruoyi-modules/yp-stock/src/main/java/com/yingpai/stock/service/impl/StockPoolHistoryServiceImpl.java

@@ -421,13 +421,14 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
             }
         }
 
-        // 批量计算最高涨幅
-        log.info("开始批量计算最高涨幅,待插入: {} 条,待更新: {} 条", toInsertList.size(), toUpdateList.size());
+        // 批量初始化最高涨幅为0(因为导入当天数据时,还没有未来数据)
+        // 后续会通过回溯更新逐步更新这个值
+        log.info("开始批量初始化最高涨幅,待插入: {} 条,待更新: {} 条", toInsertList.size(), toUpdateList.size());
         for (StockPoolHistory entity : toInsertList) {
-            entity.setHighTrend(calculateHighTrend(entity.getStockCode(), parsedRecordDate, entity.getDayClosePrice()));
+            entity.setHighTrend(BigDecimal.ZERO);
         }
         for (StockPoolHistory entity : toUpdateList) {
-            entity.setHighTrend(calculateHighTrend(entity.getStockCode(), parsedRecordDate, entity.getDayClosePrice()));
+            entity.setHighTrend(BigDecimal.ZERO);
         }
 
         // 批量插入
@@ -464,6 +465,15 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
             log.error("[强势池10天涨幅] 更新失败: {}", e.getMessage(), e);
         }
 
+        // 回溯更新过去10天内所有记录的high_trend
+        try {
+            log.info("[回溯更新high_trend] 开始回溯更新,导入日期: {}", parsedRecordDate);
+            String updateResult = updatePastTenDaysHighTrend(parsedRecordDate);
+            log.info("[回溯更新high_trend] 更新结果: {}", updateResult);
+        } catch (Exception e) {
+            log.error("[回溯更新high_trend] 更新失败: {}", e.getMessage(), e);
+        }
+
         if (failureNum > 0) {
             String message = String.format("导入完成!成功 %d 条(其中更新 %d 条),失败 %d 条。详细错误信息请查看服务器日志。",
                 successNum, updateNum, failureNum);
@@ -711,6 +721,88 @@ public class StockPoolHistoryServiceImpl implements IStockPoolHistoryService {
             .setScale(2, RoundingMode.HALF_UP);
     }
 
+    /**
+     * 回溯更新过去10天内所有记录的high_trend
+     * 当导入新的历史数据后,需要更新过去10天内所有记录的high_trend,
+     * 因为这些记录的"未来10天最高价"可能会因为新数据的加入而改变
+     *
+     * @param importDate 当前导入的日期
+     * @return 更新结果信息
+     */
+    private String updatePastTenDaysHighTrend(LocalDate importDate) {
+        log.info("[回溯更新high_trend] 开始更新,导入日期: {}", importDate);
+
+        // 查询过去10天内的所有历史记录(包括今天)
+        LocalDate tenDaysAgo = importDate.minusDays(10);
+        LambdaQueryWrapper<StockPoolHistory> lqw = Wrappers.lambdaQuery();
+        lqw.ge(StockPoolHistory::getRecordDate, tenDaysAgo)
+           .le(StockPoolHistory::getRecordDate, importDate);
+
+        List<StockPoolHistory> recordsToUpdate = baseMapper.selectList(lqw);
+
+        if (recordsToUpdate.isEmpty()) {
+            String message = "没有需要回溯更新的历史记录(过去10天内)";
+            log.info("[回溯更新high_trend] {}", message);
+            return message;
+        }
+
+        log.info("[回溯更新high_trend] 找到 {} 条需要更新的记录", recordsToUpdate.size());
+
+        int updatedCount = 0;
+        int skippedCount = 0;
+
+        for (StockPoolHistory record : recordsToUpdate) {
+            try {
+                String stockCode = record.getStockCode();
+                LocalDate recordDate = record.getRecordDate();
+                BigDecimal dayClosePrice = record.getDayClosePrice();
+
+                if (dayClosePrice == null || dayClosePrice.compareTo(BigDecimal.ZERO) == 0) {
+                    log.warn("[回溯更新high_trend] 股票 {} 日期 {} 收盘价为空或为0,跳过",
+                        stockCode, recordDate);
+                    skippedCount++;
+                    continue;
+                }
+
+                // 查询从记录日期到当前导入日期的最高价(向后查询,最多10天)
+                BigDecimal maxHighPrice = baseMapper.selectForwardTenDaysHighestPrice(
+                    stockCode, recordDate, importDate);
+
+                if (maxHighPrice == null) {
+                    log.warn("[回溯更新high_trend] 股票 {} 在 [{}, {}] 范围内没有最高价数据,跳过",
+                        stockCode, recordDate, importDate);
+                    skippedCount++;
+                    continue;
+                }
+
+                // 计算涨幅:(最高价 - 当天收盘价) / 当天收盘价 * 100
+                BigDecimal highTrend = maxHighPrice.subtract(dayClosePrice)
+                    .divide(dayClosePrice, 4, RoundingMode.HALF_UP)
+                    .multiply(new BigDecimal("100"))
+                    .setScale(2, RoundingMode.HALF_UP);
+
+                // 更新记录
+                record.setHighTrend(highTrend);
+                baseMapper.updateById(record);
+
+                updatedCount++;
+
+                log.debug("[回溯更新high_trend] 股票 {} 日期 {} 更新成功,收盘价: {}, 最高价: {}, 涨幅: {}%",
+                    stockCode, recordDate, dayClosePrice, maxHighPrice, highTrend);
+
+            } catch (Exception e) {
+                log.error("[回溯更新high_trend] 股票 {} 日期 {} 更新失败: {}",
+                    record.getStockCode(), record.getRecordDate(), e.getMessage(), e);
+                skippedCount++;
+            }
+        }
+
+        String message = String.format("回溯更新完成!成功更新 %d 条,跳过 %d 条",
+            updatedCount, skippedCount);
+        log.info("[回溯更新high_trend] {}", message);
+        return message;
+    }
+
     /**
      * 构建查询条件
      */