Browse Source

feat:大赛榜单等结果的输出

mozuwen 5 months ago
parent
commit
c2f62a55a0
63 changed files with 2729 additions and 443 deletions
  1. 97 0
      service-base/src/main/java/com/simuwang/base/cache/TrendDateTask.java
  2. 32 0
      service-base/src/main/java/com/simuwang/base/common/util/NavDataUtil.java
  3. 18 0
      service-base/src/main/java/com/simuwang/base/event/CalcFundRankEvent.java
  4. 22 0
      service-base/src/main/java/com/simuwang/base/event/CalcFundRankEventDO.java
  5. 20 0
      service-base/src/main/java/com/simuwang/base/event/CalcFundRankPublisher.java
  6. 2 0
      service-base/src/main/java/com/simuwang/base/mapper/AssetMapper.java
  7. 2 1
      service-base/src/main/java/com/simuwang/base/mapper/DeletionInfoMapper.java
  8. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/DepositNavMapper.java
  9. 15 0
      service-base/src/main/java/com/simuwang/base/mapper/FundIndicatorMapper.java
  10. 2 2
      service-base/src/main/java/com/simuwang/base/mapper/FundInfoMapper.java
  11. 13 0
      service-base/src/main/java/com/simuwang/base/mapper/FundRatingRuleMapper.java
  12. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/MarketIndexesMapper.java
  13. 1 1
      service-base/src/main/java/com/simuwang/base/mapper/NavMapper.java
  14. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionApplyMapper.java
  15. 15 0
      service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionResultMapper.java
  16. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionStrategyMapper.java
  17. 3 0
      service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionTaskDateMapper.java
  18. 5 0
      service-base/src/main/java/com/simuwang/base/mapper/TradeDateMapper.java
  19. 19 0
      service-base/src/main/java/com/simuwang/base/pojo/FundInitAndEndNavDTO.java
  20. 17 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/DepositNavDO.java
  21. 5 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundAndCompanyInfoDO.java
  22. 137 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundIndicatorDO.java
  23. 6 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundInfoDO.java
  24. 74 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundRatingRuleDO.java
  25. 121 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/IndexesTradeDateDo.java
  26. 17 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionApplyDO.java
  27. 224 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionResultDO.java
  28. 14 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionStrategyDO.java
  29. 27 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionTaskDateDO.java
  30. 39 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/FundCompanyInfoDTO.java
  31. 0 6
      service-base/src/main/java/com/simuwang/base/pojo/dto/FundNavDataDTO.java
  32. 0 5
      service-base/src/main/java/com/simuwang/base/pojo/dto/FundNavDeletionDTO.java
  33. 22 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/FundScoreRankDTO.java
  34. 25 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/MarketIndexesDTO.java
  35. 196 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/competition/XnzqCompetitionResultDTO.java
  36. 13 0
      service-base/src/main/resources/mapper/AssetMapper.xml
  37. 2 1
      service-base/src/main/resources/mapper/DeletionInfoMapper.xml
  38. 12 0
      service-base/src/main/resources/mapper/DepositeNavMapper.xml
  39. 72 0
      service-base/src/main/resources/mapper/FundIndicatorMapper.xml
  40. 12 3
      service-base/src/main/resources/mapper/FundInfoMapper.xml
  41. 15 0
      service-base/src/main/resources/mapper/FundRatingRuleMapper.xml
  42. 17 0
      service-base/src/main/resources/mapper/MarketIndexesMapper.xml
  43. 7 5
      service-base/src/main/resources/mapper/NavMapper.xml
  44. 17 0
      service-base/src/main/resources/mapper/RcCompetitionApplyMapper.xml
  45. 107 0
      service-base/src/main/resources/mapper/RcCompetitionResultMapper.xml
  46. 12 0
      service-base/src/main/resources/mapper/RcCompetitionStrategyMapper.xml
  47. 4 2
      service-base/src/main/resources/mapper/RzCompetitionCalcDateMapper.xml
  48. 18 2
      service-base/src/main/resources/mapper/RzCompetitionTaskDateMapper.xml
  49. 18 0
      service-base/src/main/resources/mapper/TradeDateMapper.xml
  50. 83 0
      service-calc/src/main/java/com/simuwang/calc/CompetitionIndicatorCalcService.java
  51. 0 1
      service-calc/src/main/java/com/simuwang/calc/package-info.java
  52. 342 0
      service-calc/src/main/java/com/simuwang/task/CompetitionIndicatorCalcTask.java
  53. 1 1
      service-deploy/src/main/resources/application.yml
  54. 1 1
      service-manage/src/main/java/com/simuwang/manage/service/competition/AbstractCompetitionResultService.java
  55. 23 0
      service-manage/src/main/java/com/simuwang/manage/service/competition/CalcFundRankListener.java
  56. 250 0
      service-manage/src/main/java/com/simuwang/manage/service/competition/CalcFundRankService.java
  57. 168 25
      service-manage/src/main/java/com/simuwang/manage/service/competition/FundNavService.java
  58. 0 227
      service-manage/src/main/java/com/simuwang/manage/service/competition/FundNavServiceImpl.java
  59. 30 0
      service-manage/src/main/java/com/simuwang/manage/service/competition/FundStrategyService.java
  60. 40 46
      service-manage/src/main/java/com/simuwang/manage/service/competition/FzzqCompetitionResultServiceService.java
  61. 84 0
      service-manage/src/main/java/com/simuwang/manage/service/competition/XnzqCompetitionResultServiceService.java
  62. 42 70
      service-manage/src/main/java/com/simuwang/manage/service/competition/ZhzqCompetitionResultServiceService.java
  63. 93 44
      service-manage/src/main/java/com/simuwang/manage/task/CompetitionTask.java

+ 97 - 0
service-base/src/main/java/com/simuwang/base/cache/TrendDateTask.java

@@ -0,0 +1,97 @@
+package com.simuwang.base.cache;
+
+import com.simuwang.base.mapper.TradeDateMapper;
+import com.smppw.common.cache.CaffeineLocalCache;
+import com.smppw.common.pojo.IndexesTradeDate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Repository
+public class TrendDateTask {
+    private final static Logger logger = LoggerFactory.getLogger(TrendDateTask.class);
+
+    @Autowired
+    private TradeDateMapper indexesTradeDateMapper;
+
+    //刷期对应的年周, 月周 进缓存
+    @Scheduled(initialDelay = 1000, fixedRate = 24 * 3600 * 1000)
+    public void refreshData() {
+        long start = System.currentTimeMillis();
+        List<IndexesTradeDate> indexesTradeDateDoList = indexesTradeDateMapper.listAllNatureDays();
+        refreshYearWeekAndWeekOfMonth(indexesTradeDateDoList);
+        // refreshYearMonth(indexesTradeDateDoList);
+        long end = System.currentTimeMillis();
+        if (logger.isDebugEnabled()) {
+            logger.debug("TrendDateTask execute cost: " + (end - start) + "s");
+        }
+    }
+
+    //刷期对应的年周, 月周 进缓存
+    private void refreshYearWeekAndWeekOfMonth(List<IndexesTradeDate> indexesTradeDateDoList) {
+        CaffeineLocalCache.cleanDateYearWeek();
+        CaffeineLocalCache.addDateYearWeek(indexesTradeDateDoList);
+
+        CaffeineLocalCache.cleanListInfoTrendDate();
+        CaffeineLocalCache.addListInfoTrendDate(indexesTradeDateDoList);
+
+//        Map<String, String> dateCateMap = new HashMap<>();
+//        List<IndexesTradeDate> yearWeekLastTradeDateList = new ArrayList<>();
+//        Integer weekOfYear = null;
+//        String yearmonth = null;
+//        int weekOfMonth = 1;
+//        for (IndexesTradeDate indexesTradeDateDo : indexesTradeDateDoList) {
+//            Integer theWeekOfYear = indexesTradeDateDo.getWeekOfYear();
+//            String theYearmonth = indexesTradeDateDo.getYearmonth();
+//            if (weekOfYear == null) {
+//                weekOfYear = theWeekOfYear;
+//            }
+//            if (yearmonth == null) {
+//                yearmonth = theYearmonth;
+//            }
+//
+//            if (!weekOfYear.equals(theWeekOfYear)) {
+//                if (!yearmonth.equals(theYearmonth)) {
+//                    weekOfMonth = 1;
+//                    yearmonth = theYearmonth;
+//                } else {
+//                    weekOfMonth++;
+//                }
+//                weekOfYear = theWeekOfYear;
+//            }
+//            dateCateMap.put(indexesTradeDateDo.getTradeDate(), yearmonth + "-" + weekOfMonth);
+//
+//            if (indexesTradeDateDo.getIsWeekend().compareTo(1) == 0) {
+//                yearWeekLastTradeDateList.add(indexesTradeDateDo);
+//            }
+//        }
+//        CaffeineLocalCache.cleanDateMonthWeek();
+//        CaffeineLocalCache.addDateMonthWeek(dateCateMap);
+//
+//        CaffeineLocalCache.cleanYearWeekLastTradeDate();
+//        CaffeineLocalCache.addYearWeekLastTradeDate(yearWeekLastTradeDateList);
+    }
+
+    // 刷新年月数据
+    private void refreshYearMonth(List<IndexesTradeDate> indexesTradeDateDoList) {
+        CaffeineLocalCache.cleanDateYearMonth();
+        CaffeineLocalCache.addDateYearMonth(indexesTradeDateDoList);
+        List<IndexesTradeDate> yearMonthLastTradeDateList = new ArrayList<>();
+        for (IndexesTradeDate indexesTradeDateDo : indexesTradeDateDoList) {
+            if (indexesTradeDateDo.getIsMonthend().compareTo(1) == 0) {
+                yearMonthLastTradeDateList.add(indexesTradeDateDo);
+            }
+        }
+
+        CaffeineLocalCache.cleanYearMonthLastTradeDate();
+        CaffeineLocalCache.addYearMonthLastTradeDate(yearMonthLastTradeDateList);
+    }
+
+}

+ 32 - 0
service-base/src/main/java/com/simuwang/base/common/util/NavDataUtil.java

@@ -1,10 +1,19 @@
 package com.simuwang.base.common.util;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.pojo.dos.NavDO;
+import com.simuwang.base.pojo.dos.TradeDateDO;
 import com.simuwang.base.pojo.dto.EmailFundNavDTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 public class NavDataUtil {
 
     private static final Logger log = LoggerFactory.getLogger(NavDataUtil.class);
@@ -61,4 +70,27 @@ public class NavDataUtil {
         }
         return null;
     }
+
+    public static List<NavDO> filterWeekFrequencyNav(List<NavDO> navDOList, List<TradeDateDO> tradeDateDOList) {
+        List<NavDO> dataList = CollUtil.newArrayList();
+        if (CollUtil.isEmpty(navDOList)) {
+            return dataList;
+        }
+        Map<Integer, List<TradeDateDO>> yearWeekTradeDateMap = tradeDateDOList.stream().collect(Collectors.groupingBy(TradeDateDO::getYearWeek));
+
+        Map<String, List<NavDO>> fundIdNavDoMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
+        for (Map.Entry<String, List<NavDO>> fundIdNavDoEntry : fundIdNavDoMap.entrySet()) {
+            List<NavDO> navDoList = fundIdNavDoEntry.getValue();
+            for (Map.Entry<Integer, List<TradeDateDO>> yearWeekTradeDateEntry : yearWeekTradeDateMap.entrySet()) {
+                List<Date> tradeDateList = yearWeekTradeDateEntry.getValue().stream().map(TradeDateDO::getTradeDate).toList();
+                List<NavDO> collect = navDoList.stream().filter(e -> tradeDateList.contains(e.getPriceDate())).toList();
+                if (CollUtil.isEmpty(collect)) {
+                    continue;
+                }
+                NavDO navDO = collect.stream().max(Comparator.comparing(NavDO::getPriceDate)).orElse(null);
+                dataList.add(navDO);
+            }
+        }
+        return dataList;
+    }
 }

+ 18 - 0
service-base/src/main/java/com/simuwang/base/event/CalcFundRankEvent.java

@@ -0,0 +1,18 @@
+package com.simuwang.base.event;
+
+import org.springframework.context.ApplicationEvent;
+
+public class CalcFundRankEvent extends ApplicationEvent {
+
+    private CalcFundRankEventDO calcFundRankEventDO;
+
+    public CalcFundRankEvent(Object source, CalcFundRankEventDO calcFundRankEventDO) {
+        super(source);
+        this.calcFundRankEventDO = calcFundRankEventDO;
+    }
+
+    public CalcFundRankEventDO getEventObject() {
+        return this.calcFundRankEventDO;
+    }
+
+}

+ 22 - 0
service-base/src/main/java/com/simuwang/base/event/CalcFundRankEventDO.java

@@ -0,0 +1,22 @@
+package com.simuwang.base.event;
+
+import com.smppw.common.pojo.dto.DateValue;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CalcFundRankEventDO {
+
+    private Integer competitionId;
+
+    private String period;
+
+    Map<String, List<DateValue>> fundIdNavMap;
+
+}

+ 20 - 0
service-base/src/main/java/com/simuwang/base/event/CalcFundRankPublisher.java

@@ -0,0 +1,20 @@
+package com.simuwang.base.event;
+
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CalcFundRankPublisher {
+
+    private final ApplicationEventPublisher applicationEventPublisher;
+
+    public CalcFundRankPublisher(ApplicationEventPublisher applicationEventPublisher) {
+        this.applicationEventPublisher = applicationEventPublisher;
+    }
+
+    public void publishEvent(CalcFundRankEventDO calcFundRankEventDO) {
+        CalcFundRankEvent calcFundRankEvent = new CalcFundRankEvent(this, calcFundRankEventDO);
+        applicationEventPublisher.publishEvent(calcFundRankEvent);
+    }
+
+}

+ 2 - 0
service-base/src/main/java/com/simuwang/base/mapper/AssetMapper.java

@@ -27,4 +27,6 @@ public interface AssetMapper {
     Long countAssetTotal();
 
     List<AssetDO> queryAssetByFundId(@Param("fundIdList") List<String> fundIdList);
+
+    List<AssetDO> queryByFundId(@Param("fundIdList") List<String> fundIdList, @Param("beginDate") String beginDate, @Param("endDate") String endDate);
 }

+ 2 - 1
service-base/src/main/java/com/simuwang/base/mapper/DeletionInfoMapper.java

@@ -53,5 +53,6 @@ public interface DeletionInfoMapper {
 
     void updateDeletionInfoDO(DeletionInfoDO oldDeletionDO);
 
-    List<FundDeletionInfoDO> getFundNavDeletion(@Param("deletionType") Integer deletionType,@Param("startDate") String startDate,@Param("endDate") String endDate);
+    List<FundDeletionInfoDO> getFundNavDeletion(@Param("deletionType") Integer deletionType, @Param("competitionId") Integer competitionId,
+                                                @Param("startDate") String startDate, @Param("endDate") String endDate);
 }

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/DepositNavMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.DepositNavDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface DepositNavMapper {
+
+    List<DepositNavDO> queryByFundId(@Param("fundId") String fundId, @Param("startDate") String startDate, @Param("endDate") String endDate);
+
+}

+ 15 - 0
service-base/src/main/java/com/simuwang/base/mapper/FundIndicatorMapper.java

@@ -0,0 +1,15 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.FundIndicatorDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface FundIndicatorMapper {
+
+    void batchInsertOrUpdate(@Param("itemDoList") List<FundIndicatorDO> fundIndicatorDOList);
+
+    List<FundIndicatorDO> queryByPeriod(@Param("competitionId")Integer competitionId, @Param("period")String period);
+}

+ 2 - 2
service-base/src/main/java/com/simuwang/base/mapper/FundInfoMapper.java

@@ -5,7 +5,6 @@ import com.simuwang.base.pojo.dos.FundInfoDO;
 import com.simuwang.base.pojo.dos.FundInformationDO;
 import com.simuwang.base.pojo.dto.query.FundInfoPageQuery;
 import com.simuwang.base.pojo.dto.query.FundInputPageQuery;
-import com.simuwang.base.pojo.vo.FundInformationVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -54,5 +53,6 @@ public interface FundInfoMapper {
 
     List<FundInfoDO> queryFundInfoByFundId(@Param("fundIdList") List<String> fundIdList);
 
-    List<FundAndCompanyInfoDO> queryFundAndTrustByFundId(@Param("fundIdList")List<String> fundIdList);
+    List<FundAndCompanyInfoDO> queryFundAndTrustByFundId(@Param("competitionId")Integer competitionId, @Param("fundIdList")List<String> fundIdList);
+
 }

+ 13 - 0
service-base/src/main/java/com/simuwang/base/mapper/FundRatingRuleMapper.java

@@ -0,0 +1,13 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.FundRatingRuleDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface FundRatingRuleMapper {
+
+    List<FundRatingRuleDO> queryByCompetitionId(@Param("competitionId") Integer competitionId);
+}

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/MarketIndexesMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dto.MarketIndexesDTO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface MarketIndexesMapper {
+
+    List<MarketIndexesDTO> queryByIndexId(@Param("indexIdList") List<String> indexIdList, @Param("startDate") String startDate, @Param("endDate") String endDate);
+
+}

+ 1 - 1
service-base/src/main/java/com/simuwang/base/mapper/NavMapper.java

@@ -31,5 +31,5 @@ public interface NavMapper {
 
     Long countNavTotal();
 
-    List<NavDO> queryAllNav(@Param("startDate") String startDate,@Param("endDate") String endDate);
+    List<NavDO> queryAllNav(@Param("competitionId")Integer competitionId, @Param("startDate") String startDate,@Param("endDate") String endDate);
 }

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionApplyMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.RcCompetitionApplyDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface RcCompetitionApplyMapper {
+
+    List<RcCompetitionApplyDO> queryByCompetitionId(@Param("competitionId") Integer competitionId);
+
+}

+ 15 - 0
service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionResultMapper.java

@@ -0,0 +1,15 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.RcCompetitionResultDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface RcCompetitionResultMapper {
+
+    void batchInsertOrUpdate(@Param("itemDoList") List<RcCompetitionResultDO> competitionResultDOList);
+
+    List<RcCompetitionResultDO> queryCompetitionResult(@Param("competitionId") Integer competitionId, @Param("period") String period);
+}

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionStrategyMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.RcCompetitionStrategyDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface RcCompetitionStrategyMapper {
+
+    List<RcCompetitionStrategyDO> queryByCompetitionId(@Param("competitionId") Integer competitionId);
+
+}

+ 3 - 0
service-base/src/main/java/com/simuwang/base/mapper/RcCompetitionTaskDateMapper.java

@@ -13,4 +13,7 @@ public interface RcCompetitionTaskDateMapper {
 
     List<RcCompetitionTaskDateDO> queryByNavDeletionDate(@Param("date") String date, @Param("competitionId") Integer competitionId);
 
+    List<RcCompetitionTaskDateDO> queryByIndicatorCalcDate(@Param("date") String date, @Param("competitionId") Integer competitionId);
+
+    List<RcCompetitionTaskDateDO> queryByPriodDate(@Param("date") String date, @Param("competitionId") Integer competitionId);
 }

+ 5 - 0
service-base/src/main/java/com/simuwang/base/mapper/TradeDateMapper.java

@@ -1,6 +1,7 @@
 package com.simuwang.base.mapper;
 
 import com.simuwang.base.pojo.dos.TradeDateDO;
+import com.smppw.common.pojo.IndexesTradeDate;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -17,4 +18,8 @@ public interface TradeDateMapper {
     List<TradeDateDO> selectTradeDate(@Param("startDate") String inceptionDate,@Param("endDate")  String today);
 
     List<TradeDateDO> queryByDate(@Param("dateList") List<String> dateList);
+
+    List<TradeDateDO> listNatureDays();
+
+    List<IndexesTradeDate> listAllNatureDays();
 }

+ 19 - 0
service-base/src/main/java/com/simuwang/base/pojo/FundInitAndEndNavDTO.java

@@ -0,0 +1,19 @@
+package com.simuwang.base.pojo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class FundInitAndEndNavDTO {
+
+    private String fundId;
+
+    private String startDate;
+
+    private BigDecimal startCumulativeNavWithdrawal;
+
+    private String endDate;
+
+    private BigDecimal endCumulativeNavWithdrawal;
+}

+ 17 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/DepositNavDO.java

@@ -0,0 +1,17 @@
+package com.simuwang.base.pojo.dos;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class DepositNavDO {
+
+    private String fundId;
+
+    private Date priceDate;
+
+    private BigDecimal nav;
+
+}

+ 5 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundAndCompanyInfoDO.java

@@ -10,7 +10,12 @@ public class FundAndCompanyInfoDO {
     private String fundName;
     private String fundShortName;
     private String registerNumber;
+    private Integer strategyId;
     private String companyId;
     private String companyName;
+    private String companyShortName;
     private String companyRegisterNumber;
+    private Integer companyScale;
+    private Integer isOpenAccount;
+    private Integer isOpenAccount2;
 }

+ 137 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundIndicatorDO.java

@@ -0,0 +1,137 @@
+package com.simuwang.base.pojo.dos;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("fund_indicator")
+public class FundIndicatorDO{
+   /**
+   *主键ID
+   */
+   @TableId(value="id")
+   private Integer id;
+   /**
+    *大赛ID
+    */
+   @TableId(value="competition_id")
+   private Integer competitionId;
+   /**
+   *基金id
+   */
+   @TableField(value="fund_id")
+   private String fundId;
+   /**
+   *计算时段,年份-月份:月度,年份季度:季度,all:总榜单,2years:两年榜,fir_halfyear:上半年,sec_halfyear:下半年
+   */
+   @TableField(value="priod")
+   private String priod;
+   /**
+   *区间收益率
+   */
+   @TableField(value="ret")
+   private BigDecimal ret;
+   /**
+   *年化收益率
+   */
+   @TableField(value="ret_a")
+   private BigDecimal retA;
+   /**
+   *最大回撤
+   */
+   @TableField(value="maxdrawdown")
+   private BigDecimal maxdrawdown;
+   /**
+   *胜率
+   */
+   @TableField(value="winrate")
+   private BigDecimal winrate;
+   /**
+   *阿尔法
+   */
+   @TableField(value="alpha")
+   private BigDecimal alpha;
+   /**
+   *信息比率
+   */
+   @TableField(value="info_ratio")
+   private BigDecimal infoRatio;
+   /**
+   *夏普比率
+   */
+   @TableField(value="sharperatio")
+   private BigDecimal sharperatio;
+   /**
+   *索提诺比率
+   */
+   @TableField(value="sortinoratio")
+   private BigDecimal sortinoratio;
+   /**
+   *卡玛比率
+   */
+   @TableField(value="calmarratio")
+   private BigDecimal calmarratio;
+   /**
+   *超额区间收益
+   */
+   @TableField(value="excess_geometry")
+   private BigDecimal excessGeometry;
+   /**
+   *超额年化标准差
+   */
+   @TableField(value="excess_stddev")
+   private BigDecimal excessStddev;
+   /**
+   *超额最大回撤
+   */
+   @TableField(value="excess_maxdrawdown")
+   private BigDecimal excessMaxdrawdown;
+   /**
+   *超额胜率
+   */
+   @TableField(value="excess_winrate")
+   private BigDecimal excessWinrate;
+   /**
+   *超额夏普比率
+   */
+   @TableField(value="excess_sharperatio")
+   private BigDecimal excessSharperatio;
+   /**
+   *超额卡玛比率
+   */
+   @TableField(value="excess_calmarratio")
+   private BigDecimal excessCalmarratio;
+   /**
+   *产品规模
+   */
+   @TableField(value="product_scale")
+   private BigDecimal productScale;
+   /**
+   *记录的有效性;1-有效;0-无效; 
+   */
+   @TableField(value="isvalid")
+   private Integer isvalid;
+   /**
+   *创建者Id,默认第一次创建者名称,创建后不变更
+   */
+   @TableField(value="creatorid")
+   private Integer creatorId;
+   /**
+   *创建时间,默认第一次创建的getdate()时间
+   */
+   @TableField(value="createtime")
+   private Date createTime;
+   /**
+   *修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+   */
+   @TableField(value="updaterid")
+   private Integer updaterId;
+   /**
+   *修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+   */
+   @TableField(value="updatetime")
+   private Date updateTime;
+}

+ 6 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundInfoDO.java

@@ -160,6 +160,12 @@ public class FundInfoDO {
      */
     private String issuerCompanyName;
 
+    /**
+     * 基准Id
+     */
+    private String primaryBenchmarkId;
+
+
     public FundInfoVO toVO() {
         FundInfoVO vo = new FundInfoVO();
         vo.setId(this.id);

+ 74 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundRatingRuleDO.java

@@ -0,0 +1,74 @@
+package com.simuwang.base.pojo.dos;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("fund_rating_rule")
+public class FundRatingRuleDO {
+    /**
+     * 主键Id
+     */
+    @TableId(value = "id")
+    private Integer id;
+    /**
+     * 大赛Id
+     */
+    @TableField(value = "competition_id")
+    private Integer competitionId;
+    /**
+     * 策略Id
+     */
+    @TableField(value = "strategy_id")
+    private Integer strategyId;
+    /**
+     * 指标Id
+     */
+    @TableField(value = "indicator_id")
+    private String indicatorId;
+    /**
+     * 权重
+     */
+    @TableField(value = "weight")
+    private BigDecimal weight;
+    /**
+     * 指标排名结果:1-asc,2-desc
+     */
+    @TableField(value = "rating_type")
+    private Integer ratingType;
+    /**
+     * 指标排序id
+     */
+    @TableField(value = "sort_id")
+    private Integer sortId;
+    /**
+     * 记录的有效性;1-有效;0-无效;
+     */
+    @TableField(value = "isvalid")
+    private Integer isvalid;
+    /**
+     * 创建者Id,默认第一次创建者名称,创建后不变更
+     */
+    @TableField(value = "creatorid")
+    private Integer creatorId;
+    /**
+     * 创建时间,默认第一次创建的getdate()时间
+     */
+    @TableField(value = "createtime")
+    private Date createTime;
+    /**
+     * 修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+     */
+    @TableField(value = "updaterid")
+    private Integer updaterId;
+    /**
+     * 修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+     */
+    @TableField(value = "updatetime")
+    private Date updateTime;
+}

+ 121 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/IndexesTradeDateDo.java

@@ -0,0 +1,121 @@
+package com.simuwang.base.pojo.dos;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+    * 交易日
+    */
+@Data
+public class IndexesTradeDateDo {
+    /**
+    * 主键ID
+    */
+    private Integer id;
+
+    /**
+    * 指数代码
+    */
+    private String indexCode;
+
+    /**
+    * 日期
+    */
+    private String tradeDate;
+
+    /**
+    * 截止年份
+    */
+    private String endYear;
+
+    /**
+    * 全年的第几周
+    */
+    private Integer weekOfYear;
+
+    /**
+    * 年周
+    */
+    private String yearWeek;
+
+    /**
+    * 星期,周一为1
+    */
+    private Integer dayOfWeek;
+
+    /**
+    * 周的开始日期
+    */
+    private Date weekBegin;
+
+    /**
+    * 周的结束日期
+    */
+    private Date weekEnd;
+
+    /**
+    * 上一周所在的年
+    */
+    private String preYear;
+
+    /**
+    * 上一周
+    */
+    private Byte preWeek;
+
+    /**
+    * 是否为节假日 0 工作日 1 节假日
+    */
+    private Integer isholiday;
+
+    /**
+    * 是否周最后交易日:1-是,2-否
+    */
+    private Integer isWeekend;
+
+    /**
+    * 是否月最后交易日:1-是,2-否
+    */
+    private Integer isMonthend;
+
+    /**
+    * 是否季最后交易日:1-是,2-否
+    */
+    private Integer isQuarterend;
+
+    /**
+    * 是否年最后交易日:1-是,2-否
+    */
+    private Integer isYearend;
+
+    /**
+    * 记录有效性 1 有效 0 无效
+    */
+    private Integer isvalid;
+
+    /**
+    * 创建人id
+    */
+    private Integer creatorid;
+
+    /**
+    * 创建时间
+    */
+    private Date createtime;
+
+    /**
+    * 更新人id
+    */
+    private Integer updaterid;
+
+    /**
+    * 更新时间
+    */
+    private Date updatetime;
+
+    /**
+    * 年月
+    */
+    private String yearmonth;
+}

+ 17 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionApplyDO.java

@@ -0,0 +1,17 @@
+package com.simuwang.base.pojo.dos;
+
+import lombok.Data;
+
+@Data
+public class RcCompetitionApplyDO {
+
+    private Integer competitionId;
+
+    private String fundId;
+
+    private Integer strategy;
+
+    private Integer openAccount;
+
+    private Integer openAccount2;
+}

+ 224 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionResultDO.java

@@ -0,0 +1,224 @@
+package com.simuwang.base.pojo.dos;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("rc_competition_result")
+public class RcCompetitionResultDO {
+    /**
+     * 主键Id
+     */
+    @TableId(value = "id")
+    private Integer id;
+    /**
+     * 大赛Id
+     */
+    @TableField(value = "competition_id")
+    private Integer competitionId;
+    /**
+     * 榜单周期:年份-月份:月度,年份季度:季度,all:总榜单,2years:两年榜,fir_halfyear:上半年,sec_halfyear:下半年
+     */
+    @TableField(value = "priod")
+    private String priod;
+    /**
+     * 策略id
+     */
+    @TableField(value = "strategy")
+    private Integer strategy;
+    /**
+     * 得分排名
+     */
+    @TableField(value = "rank")
+    private Integer rank;
+    /**
+     * 综合得分
+     */
+    @TableField(value = "score")
+    private BigDecimal score;
+    /**
+     * 基金id
+     */
+    @TableField(value = "fund_id")
+    private String fundId;
+    /**
+     * 基金备案编号
+     */
+    @TableField(value = "fund_register_number")
+    private String fundRegisterNumber;
+    /**
+     * 基金名称
+     */
+    @TableField(value = "fund_name")
+    private String fundName;
+    /**
+     * 基金简称
+     */
+    @TableField(value = "fund_short_name")
+    private String fundShortName;
+    /**
+     * 公司id
+     */
+    @TableField(value = "company_id")
+    private String companyId;
+    /**
+     * 公司备案编号
+     */
+    @TableField(value = "company_register_number")
+    private String companyRegisterNumber;
+    /**
+     * 公司名称
+     */
+    @TableField(value = "company_name")
+    private String companyName;
+    /**
+     * 公司简称
+     */
+    @TableField(value = "company_short_name")
+    private String companyShortName;
+    /**
+     * 期末净值日期
+     */
+    @TableField(value = "price_date")
+    private Date priceDate;
+    /**
+     * 期末累计净值
+     */
+    @TableField(value = "cumulative_nav_withdrawal")
+    private BigDecimal cumulativeNavWithdrawal;
+    /**
+     * 期初净值日期
+     */
+    @TableField(value = "pre_price_date")
+    private Date prePriceDate;
+    /**
+     * 期初累计净值
+     */
+    @TableField(value = "pre_cumulative_nav_withdrawal")
+    private BigDecimal preCumulativeNavWithdrawal;
+    /**
+     * 产品规模
+     */
+    @TableField(value = "product_scale")
+    private BigDecimal productScale;
+    /**
+     * 区间收益率
+     */
+    @TableField(value = "ret")
+    private BigDecimal ret;
+    /**
+     * 年化收益率
+     */
+    @TableField(value = "ret_a")
+    private BigDecimal retA;
+    /**
+     * 最大回撤
+     */
+    @TableField(value = "maxdrawdown")
+    private BigDecimal maxdrawdown;
+    /**
+     * 卡玛比率
+     */
+    @TableField(value = "calmarratio")
+    private BigDecimal calmarratio;
+    /**
+     * 夏普比率
+     */
+    @TableField(value = "sharperatio")
+    private BigDecimal sharperatio;
+    /**
+     * 索提诺比率
+     */
+    @TableField(value = "sortinoratio")
+    private BigDecimal sortinoratio;
+    /**
+     * 阿尔法比率
+     */
+    @TableField(value = "alpha")
+    private BigDecimal alpha;
+    /**
+     * 周胜率
+     */
+    @TableField(value = "winrate")
+    private BigDecimal winrate;
+    /**
+     * 信息比率
+     */
+    @TableField(value = "info_ratio")
+    private BigDecimal infoRatio;
+    /**
+     * 超额区间收益
+     */
+    @TableField(value = "excess_ret")
+    private BigDecimal excessRet;
+    /**
+     * 超额最大回撤
+     */
+    @TableField(value = "excess_maxdown")
+    private BigDecimal excessMaxdown;
+    /**
+     * 超额周胜率
+     */
+    @TableField(value = "excess_winrate")
+    private BigDecimal excessWinrate;
+    /**
+     * 超额卡玛比率
+     */
+    @TableField(value = "excess_calmarratio")
+    private BigDecimal excessCalmarratio;
+    /**
+     * 超额夏普比率
+     */
+    @TableField(value = "excess_sharperatio")
+    private BigDecimal excessSharperatio;
+    /**
+     * 超额波动率
+     */
+    @TableField(value = "excess_stddev")
+    private BigDecimal excessStddev;
+    /**
+     * 公司规模
+     */
+    @TableField(value = "company_scale")
+    private Integer companyScale;
+    /**
+     * 是否开户:0-否,1-是
+     */
+    @TableField(value = "is_open_account")
+    private Integer isOpenAccount;
+    /**
+     * 是否开户:0-否,1-是
+     */
+    @TableField(value = "is_open_account2")
+    private Integer isOpenAccount2;
+    /**
+     * 记录的有效性;1-有效;0-无效;
+     */
+    @TableField(value = "isvalid")
+    private Integer isvalid;
+    /**
+     * 创建者Id,默认第一次创建者名称,创建后不变更
+     */
+    @TableField(value = "creatorid")
+    private Integer creatorId;
+    /**
+     * 创建时间,默认第一次创建的getdate()时间
+     */
+    @TableField(value = "createtime")
+    private Date createTime;
+    /**
+     * 修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+     */
+    @TableField(value = "updaterid")
+    private Integer updaterId;
+    /**
+     * 修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+     */
+    @TableField(value = "updatetime")
+    private Date updateTime;
+}

+ 14 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionStrategyDO.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.pojo.dos;
+
+import lombok.Data;
+
+@Data
+public class RcCompetitionStrategyDO {
+
+    private Integer competitionId;
+
+    private Integer strategyId;
+
+    private String strategyName;
+
+}

+ 27 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/RcCompetitionTaskDateDO.java

@@ -2,6 +2,9 @@ package com.simuwang.base.pojo.dos;
 
 import lombok.Data;
 
+import java.math.BigDecimal;
+import java.util.Date;
+
 @Data
 public class RcCompetitionTaskDateDO {
     /**
@@ -15,6 +18,11 @@ public class RcCompetitionTaskDateDO {
     private Integer competitionId;
 
     /**
+     * 基金指标计算
+     */
+    private String indicatorCalcDate;
+
+    /**
      * 基金净值明细输出日期
      */
     private String navDetailDate;
@@ -33,4 +41,23 @@ public class RcCompetitionTaskDateDO {
      * 输出榜单:年份-月份:月度,年份季度:季度,all:总榜单,2years:两年榜,fir_halfyear:上半年,sec_halfyear:下半年
      */
     private String priod;
+
+    @Data
+    public static class DepositeNavDO {
+
+        /**
+         * 指数Id
+         */
+        private String indexId;
+
+        /**
+         * 指数日期
+         */
+        private Date priceDate;
+
+        /**
+         * 收盘价
+         */
+        private BigDecimal close;
+    }
 }

+ 39 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/FundCompanyInfoDTO.java

@@ -0,0 +1,39 @@
+package com.simuwang.base.pojo.dto;
+
+import lombok.Data;
+
+@Data
+public class FundCompanyInfoDTO {
+    /**
+     * 基金ID
+     */
+    private String fundId;
+    /**
+     * 基金全称
+     */
+    private String fundName;
+    /**
+     * 基金简称
+     */
+    private String fundShortName;
+    /**
+     * 基金备案编码
+     */
+    private String fundRegisterNumber;
+    /**
+     * 机构ID
+     */
+    private String companyId;
+    /**
+     * 机构全称
+     */
+    private String companyName;
+    /**
+     * 机构简称
+     */
+    private String companyShortName;
+    /**
+     * 机构备案编码
+     */
+    private String companyRegisterNumber;
+}

+ 0 - 6
service-base/src/main/java/com/simuwang/base/pojo/dto/FundNavDataDTO.java

@@ -72,10 +72,4 @@ public class FundNavDataDTO {
     @ColumnWidth(15)
     @ExcelProperty("资产净值")
     private String asset;
-
-    /**
-     * 榜单周期
-     */
-    @ExcelIgnore
-    private String priod;
 }

+ 0 - 5
service-base/src/main/java/com/simuwang/base/pojo/dto/FundNavDeletionDTO.java

@@ -66,9 +66,4 @@ public class FundNavDeletionDTO {
     @ExcelProperty("缺失日期")
     private String date;
 
-    /**
-     * 榜单周期
-     */
-    @ExcelIgnore
-    private String priod;
 }

+ 22 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/FundScoreRankDTO.java

@@ -0,0 +1,22 @@
+package com.simuwang.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FundScoreRankDTO {
+
+    private String fundId;
+
+    private Integer strategyId;
+
+    private BigDecimal score;
+
+    private Integer rank;
+
+}

+ 25 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/MarketIndexesDTO.java

@@ -0,0 +1,25 @@
+package com.simuwang.base.pojo.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class MarketIndexesDTO {
+
+    /**
+     * 指数Id
+     */
+    private String indexId;
+
+    /**
+     * 指数日期
+     */
+    private Date priceDate;
+
+    /**
+     * 收盘价
+     */
+    private BigDecimal close;
+}

+ 196 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/competition/XnzqCompetitionResultDTO.java

@@ -0,0 +1,196 @@
+package com.simuwang.base.pojo.dto.competition;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author mozuwen
+ * @date 2024-11-12
+ * @description 西南证券大赛排名榜单模板
+ */
+@Data
+@HeadFontStyle(fontHeightInPoints = 10)
+@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
+public class XnzqCompetitionResultDTO extends CompetitionBaseResultDTO {
+
+    /**
+     * 策略
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "策略")
+    private String strategyName;
+
+    /**
+     * 规模分组
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "规模分组")
+    private String assetGroupName;
+
+    /**
+     * 排名
+     */
+    @ColumnWidth(10)
+    @ExcelProperty(value = "排名")
+    private Integer rank;
+
+    /**
+     * 产品ID
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品ID")
+    private String fundId;
+
+    /**
+     * 产品备案编码
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品备案编码")
+    private String registerNumber;
+
+    /**
+     * 产品全称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品全称")
+    private String fundName;
+
+    /**
+     * 产品简称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品简称")
+    private String fundShortName;
+
+    /**
+     * 公司ID
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司ID")
+    private String companyId;
+
+    /**
+     * 公司备案编码
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司备案编码")
+    private String companyRegisterNumber;
+
+    /**
+     * 公司全称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司全称")
+    private String companyName;
+
+    /**
+     * 公司简称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司简称")
+    private String companyShortName;
+
+    /**
+     * 期初净值日期
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期初净值日期")
+    private String startPriceDate;
+
+    /**
+     * 期初净值
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期初净值")
+    private BigDecimal startCumulativeNavWithdrawal;
+
+    /**
+     * 期末净值日期
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期末净值日期")
+    private String endPriceDate;
+
+    /**
+     * 期末净值
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期末净值")
+    private BigDecimal endCumulativeNavWithdrawal;
+
+    /**
+     * 综合得分
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "综合得分")
+    private BigDecimal score;
+
+    /**
+     * 收益率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("收益率")
+    private BigDecimal ret;
+
+    /**
+     * 最大回撤
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("最大回撤")
+    private BigDecimal maxdown;
+
+    /**
+     * 夏普比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("夏普比率")
+    private BigDecimal sharpeRatio;
+
+    /**
+     * 卡玛比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("卡玛比率")
+    private BigDecimal calmarRatio;
+
+    /**
+     * 区间超额收益率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("区间超额收益率")
+    private BigDecimal excessRet;
+
+    /**
+     * 周胜率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("周胜率")
+    private BigDecimal winrate;
+
+    /**
+     * 信息比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("信息比率")
+    private BigDecimal infoRatio;
+
+    /**
+     * 索提诺比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("索提诺比率")
+    private BigDecimal sortinoRatio;
+
+    /**
+     * 产品规模
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("产品规模")
+    private BigDecimal productScale;
+}

+ 13 - 0
service-base/src/main/resources/mapper/AssetMapper.xml

@@ -82,4 +82,17 @@
             #{fundId}
         </foreach>
     </select>
+
+    <select id="queryByFundId" resultMap="BaseResultMap">
+        select fund_id, price_date, asset_net
+        from asset
+        where isvalid = 1
+        and price_date >= #{beginDate}
+        and price_date <![CDATA[ <= ]]> #{endDate}
+        and fund_id in
+        <foreach collection="fundIdList" index="index" item="fundId" separator="," open="(" close=")">
+            #{fundId}
+        </foreach>
+    </select>
+
 </mapper>

+ 2 - 1
service-base/src/main/resources/mapper/DeletionInfoMapper.xml

@@ -294,7 +294,8 @@
             join rc_competition_apply t2 on t1.fund_id = t2.product_code and t2.isvalid=1
         where t1.isvalid = 1
           and t1.deletion_type = #{deletionType}
-        and t1.deletion_date >= #{startDate}
+          and t1.deletion_date >= #{startDate}
+          and t2.competition_id = #{competitionId}
           and t1.deletion_date <![CDATA[ <= ]]> #{endDate}
     </select>
 </mapper>

+ 12 - 0
service-base/src/main/resources/mapper/DepositeNavMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.DepositNavMapper">
+    <select id="queryByFundId" resultType="com.simuwang.base.pojo.dos.DepositNavDO">
+        select fund_id    as fundId,
+               price_date as priceDate,
+               nav
+        from deposit_nav
+        where isvalid = 1
+          and fund_id = #{fundId}
+    </select>
+</mapper>

+ 72 - 0
service-base/src/main/resources/mapper/FundIndicatorMapper.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.FundIndicatorMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.FundIndicatorDO">
+        <id column="id" property="id"/>
+        <result column="fund_id" property="fundId"/>
+        <result column="priod" property="priod"/>
+        <result column="ret" property="ret"/>
+        <result column="ret_a" property="retA"/>
+        <result column="maxdrawdown" property="maxdrawdown"/>
+        <result column="winrate" property="winrate"/>
+        <result column="alpha" property="alpha"/>
+        <result column="info_ratio" property="infoRatio"/>
+        <result column="sharperatio" property="sharperatio"/>
+        <result column="sortinoratio" property="sortinoratio"/>
+        <result column="calmarratio" property="calmarratio"/>
+        <result column="excess_geometry" property="excessGeometry"/>
+        <result column="excess_stddev" property="excessStddev"/>
+        <result column="excess_maxdrawdown" property="excessMaxdrawdown"/>
+        <result column="excess_winrate" property="excessWinrate"/>
+        <result column="excess_sharperatio" property="excessSharperatio"/>
+        <result column="excess_calmarratio" property="excessCalmarratio"/>
+        <result column="product_scale" property="productScale"/>
+        <result column="creatorid" property="creatorId"/>
+        <result column="createtime" property="createTime"/>
+        <result column="updaterid" property="updaterId"/>
+        <result column="updatetime" property="updateTime"/>
+        <result column="isvalid" property="isvalid"/>
+    </resultMap>
+
+    <select id="batchInsertOrUpdate">
+        insert into `fund_indicator` (`competition_id`,`fund_id`, `priod`, `ret`, `ret_a`, `maxdrawdown`, `winrate`, `alpha`,
+        `info_ratio`, `sharperatio`, `sortinoratio`, `calmarratio`,
+        `excess_geometry`, `excess_stddev`, `excess_maxdrawdown`, `excess_winrate`,`excess_sharperatio`,`excess_calmarratio`, `product_scale`,
+        `isvalid`, `creatorid`, `createtime`, `updaterid`, `updatetime`)
+        values
+        <foreach collection="itemDoList" index="index" item="itemDo" separator=",">
+            (#{itemDo.competitionId},#{itemDo.fundId}, #{itemDo.priod}, #{itemDo.ret}, #{itemDo.retA}, #{itemDo.maxdrawdown},#{itemDo.winrate}, #{itemDo.alpha},
+            #{itemDo.infoRatio}, #{itemDo.sharperatio}, #{itemDo.sortinoratio}, #{itemDo.calmarratio},
+            #{itemDo.excessGeometry}, #{itemDo.excessStddev}, #{itemDo.excessMaxdrawdown}, #{itemDo.excessWinrate}, #{itemDo.excessSharperatio}, #{itemDo.excessCalmarratio}, #{itemDo.productScale},
+            #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+        on duplicate key update
+        ret = values(ret),
+        ret_a = values(ret_a),
+        winrate = values(winrate),
+        maxdrawdown = values(maxdrawdown),
+        alpha = values(alpha),
+        info_ratio = values(info_ratio),
+        sharperatio = values(sharperatio),
+        sortinoratio = values(sortinoratio),
+        calmarratio = values(calmarratio),
+        excess_geometry = values(excess_geometry),
+        excess_stddev = values(excess_stddev),
+        excess_maxdrawdown = values(excess_maxdrawdown),
+        excess_winrate = values(excess_winrate),
+        excess_sharperatio = values(excess_sharperatio),
+        excess_calmarratio = values(excess_calmarratio),
+        product_scale = values(product_scale),
+        updatetime = values(updatetime)
+    </select>
+
+    <select id="queryByPeriod" resultMap="BaseResultMap">
+        select `competition_id`,`fund_id`, `priod`, `ret`, `ret_a`, `maxdrawdown`, `winrate`, `alpha`,
+               `info_ratio`, `sharperatio`, `sortinoratio`, `calmarratio`,
+               `excess_geometry`, `excess_stddev`, `excess_maxdrawdown`, `excess_winrate`,`excess_sharperatio`,`excess_calmarratio`, `product_scale`
+        from fund_indicator
+        where isvalid = 1
+          and competition_id = #{competitionId}
+          and priod = #{period}
+    </select>
+</mapper>

+ 12 - 3
service-base/src/main/resources/mapper/FundInfoMapper.xml

@@ -222,7 +222,8 @@
     <select id="queryFundInfoByFundId" resultType="com.simuwang.base.pojo.dos.FundInfoDO">
         select t.fund_id as fundId,
                t.fund_name as fundName,
-               t.register_number as registerNumber
+               t.register_number as registerNumber,
+               t.primary_benchmark_id as primaryBenchmarkId
         from pvn_fund_info t
         where t.isvalid = 1
         and t.fund_id in
@@ -234,14 +235,22 @@
     <select id="queryFundAndTrustByFundId" resultType="com.simuwang.base.pojo.dos.FundAndCompanyInfoDO">
         select t.fund_id         as fundId,
                t.fund_name       as fundName,
+               t.fund_short_name       as fundShortName,
                t.register_number as registerNumber,
                t1.company_id as companyId,
                t1.company_name as companyName,
-               t1.register_number as companyRegisterNumber
+               t1.company_short_name as companyShortName,
+               t1.register_number as companyRegisterNumber,
+               t1.company_asset_size as companyScale,
+               t2.product_tactics as strategyId,
+               t2.open_account as isOpenAccount,
+               t2.open_account2 as isOpenAccount2
         from pvn_fund_info t
                  left join pvn_company_info t1 on t1.isvalid = 1 and t1.company_id = t.trust_id
+        join rc_competition_apply t2 on t.fund_id = t2.product_code and t2.isvalid = 1
         where t.isvalid = 1
-              and t.fund_id in
+           and t2.competition_id = #{competitionId}
+           and t.fund_id in
               <foreach collection="fundIdList" item="fundId" index="index" open="(" separator="," close=")">
                  #{fundId}
               </foreach>

+ 15 - 0
service-base/src/main/resources/mapper/FundRatingRuleMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.FundRatingRuleMapper">
+    <select id="queryByCompetitionId" resultType="com.simuwang.base.pojo.dos.FundRatingRuleDO">
+        select competition_id as competitionId,
+               strategy_id as strategyId,
+               indicator_id as indicatorId,
+               weight,
+               rating_type as ratingType,
+               sort_id as sortId
+        from fund_rating_rule
+        where isvalid = 1
+          and competition_id = #{competitionId}
+    </select>
+</mapper>

+ 17 - 0
service-base/src/main/resources/mapper/MarketIndexesMapper.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.MarketIndexesMapper">
+    <select id="queryByIndexId" resultType="com.simuwang.base.pojo.dto.MarketIndexesDTO">
+        select index_id as indexId,
+               price_date as priceDate,
+               close
+        from market_indexes
+        where isvalid = 1
+        and price_date >= #{startDate}
+        and price_date <![CDATA[ <= ]]> #{endDate}
+        and index_id in
+        <foreach collection="indexIdList" index="index" item="indexId" open="(" separator="," close=")">
+            #{indexId}
+        </foreach>
+    </select>
+</mapper>

+ 7 - 5
service-base/src/main/resources/mapper/NavMapper.xml

@@ -103,10 +103,12 @@
     </select>
 
     <select id="queryAllNav" resultMap="BaseResultMap">
-        SELECT fund_id, price_date, nav, cumulative_nav, cumulative_nav_withdrawal
-        from nav
-        where isvalid = 1
-          and price_date >= #{startDate}
-          and price_date <![CDATA[ <= ]]> #{endDate}
+        SELECT t1.fund_id, t1.price_date, t1.nav, t1.cumulative_nav, t1.cumulative_nav_withdrawal
+        from nav t1
+            join rc_competition_apply t2 on t1.fund_id = t2.product_code and t2.isvalid = 1
+        where t1.isvalid = 1
+          and t2.competition_id = #{competitionId}
+          and t1.price_date >= #{startDate}
+          and t1.price_date <![CDATA[ <= ]]> #{endDate}
     </select>
 </mapper>

+ 17 - 0
service-base/src/main/resources/mapper/RcCompetitionApplyMapper.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.RcCompetitionApplyMapper">
+
+    <select id="queryByCompetitionId" resultType="com.simuwang.base.pojo.dos.RcCompetitionApplyDO">
+        select competition_id as competitionId,
+               product_code as fundId,
+               product_tactics as strategy,
+               open_account as openAccount,
+               open_account2 as openAccount2
+        from rc_competition_apply
+        where isvalid = 1
+        and competition_id = #{competitionId}
+
+    </select>
+
+</mapper>

+ 107 - 0
service-base/src/main/resources/mapper/RcCompetitionResultMapper.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.RcCompetitionResultMapper">
+    <insert id="batchInsertOrUpdate">
+        insert into `rc_competition_result` (`competition_id`, `priod`, `strategy`, `rank`, `score`,
+        `fund_id`, `fund_register_number`, `fund_name`, `fund_short_name`,
+        `company_id`, `company_register_number`, `company_name`,
+        `company_short_name`, `price_date`, `cumulative_nav_withdrawal`,
+        `pre_price_date`, `pre_cumulative_nav_withdrawal`, `product_scale`, `ret`,
+        `ret_a`, `maxdrawdown`, `calmarratio`, `sharperatio`, `sortinoratio`,
+        `alpha`, `winrate`, `info_ratio`, `excess_ret`, `excess_maxdown`,
+        `excess_winrate`, `excess_calmarratio`, `excess_sharperatio`,
+        `excess_stddev`, `company_scale`, `is_open_account`,
+        `is_open_account2`, `isvalid`, `createtime`, `creatorid`,`updaterid`, `updatetime`)
+        values
+        <foreach collection="itemDoList" index="index" item="itemDo" separator=",">
+            (#{itemDo.competitionId},#{itemDo.priod},#{itemDo.strategy},#{itemDo.rank},#{itemDo.score},
+            #{itemDo.fundId},#{itemDo.fundRegisterNumber},#{itemDo.fundName},#{itemDo.fundShortName},
+            #{itemDo.companyId},#{itemDo.companyRegisterNumber},#{itemDo.companyName},
+            #{itemDo.companyShortName},#{itemDo.priceDate},#{itemDo.cumulativeNavWithdrawal},
+            #{itemDo.prePriceDate},#{itemDo.preCumulativeNavWithdrawal},#{itemDo.productScale},#{itemDo.ret},
+            #{itemDo.retA},#{itemDo.maxdrawdown},#{itemDo.calmarratio},#{itemDo.sharperatio},#{itemDo.sortinoratio},
+            #{itemDo.alpha},#{itemDo.winrate},#{itemDo.infoRatio},#{itemDo.excessRet},#{itemDo.excessMaxdown},
+            #{itemDo.excessWinrate},#{itemDo.excessCalmarratio},#{itemDo.excessSharperatio},
+            #{itemDo.excessStddev},#{itemDo.companyScale},#{itemDo.isOpenAccount},#{itemDo.isOpenAccount2},
+            #{itemDo.isvalid}, #{itemDo.createTime}, #{itemDo.creatorId}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+        on duplicate key update
+        rank = values(rank),
+        score = values(score),
+        fund_id = values(fund_id),
+        fund_register_number = values(fund_register_number),
+        fund_name = values(fund_name),
+        fund_short_name = values(fund_short_name),
+        company_id = values(company_id),
+        company_register_number = values(company_register_number),
+        company_name = values(company_name),
+        company_short_name = values(company_short_name),
+        price_date = values(price_date),
+        cumulative_nav_withdrawal = values(cumulative_nav_withdrawal),
+        pre_price_date = values(pre_price_date),
+        pre_cumulative_nav_withdrawal = values(pre_cumulative_nav_withdrawal),
+        product_scale = values(product_scale),
+        ret = values(ret),
+        ret_a = values(ret_a),
+        maxdrawdown = values(maxdrawdown),
+        calmarratio = values(calmarratio),
+        sharperatio = values(sharperatio),
+        sortinoratio = values(sortinoratio),
+        alpha = values(alpha),
+        winrate = values(winrate),
+        info_ratio = values(info_ratio),
+        excess_ret = values(excess_ret),
+        excess_maxdown = values(excess_maxdown),
+        excess_winrate = values(excess_winrate),
+        excess_calmarratio = values(excess_calmarratio),
+        excess_sharperatio = values(excess_sharperatio),
+        excess_stddev = values(excess_stddev),
+        company_scale = values(company_scale),
+        is_open_account = values(is_open_account),
+        is_open_account2 = values(is_open_account2),
+        updatetime = values(updatetime)
+    </insert>
+
+    <select id="queryCompetitionResult" resultType="com.simuwang.base.pojo.dos.RcCompetitionResultDO">
+        select `competition_id`                 as competitionId,
+               `priod`,
+               `strategy`,
+               `rank`,
+               `score`,
+               `fund_id`                        as fundId,
+               `fund_register_number`           as fundRegisterNumber,
+               `fund_name`                      as fundName,
+               `fund_short_name`                as fundShortName,
+               `company_id`                     as companyId,
+               `company_register_number`        as companyRegisterNumber,
+               `company_name`                   as companyName,
+               `company_short_name`             as companyShortName,
+               `price_date`                     as priceDate,
+               `cumulative_nav_withdrawal`      as cumulativeNavWithdrawal,
+               `pre_price_date`                 as prePriceDate,
+               `pre_cumulative_nav_withdrawal`  as preCumulativeNavWithdrawal,
+               `product_scale`                  as productScale,
+               `ret`,
+               `ret_a`                          as retA,
+               `maxdrawdown`,
+               `calmarratio`,
+               `sharperatio`,
+               `sortinoratio`,
+               `alpha`,
+               `winrate`,
+               `info_ratio`                     as infoRatio,
+               `excess_ret`                     as excessRet,
+               `excess_maxdown`                 as excessMaxdown,
+               `excess_winrate`                 as excessWinrate,
+               `excess_calmarratio`             as excessCalmarratio,
+               `excess_sharperatio`             as excessSharperatio,
+               `excess_stddev`                  as excessStddev,
+               `company_scale`                  as companyScale,
+               `is_open_account`                as isOpenAccount,
+               `is_open_account2`               as isOpenAccount2
+        from rc_competition_result
+        where isvalid = 1
+          and competition_id = #{competitionId}
+          and priod = #{period}
+    </select>
+</mapper>

+ 12 - 0
service-base/src/main/resources/mapper/RcCompetitionStrategyMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.RcCompetitionStrategyMapper">
+    <select id="queryByCompetitionId" resultType="com.simuwang.base.pojo.dos.RcCompetitionStrategyDO">
+        select competition_id as competitionId,
+               strategy_id    as strategyId,
+               strategy_name  as strategyName
+        from rc_competition_strategy
+        where isvalid = 1
+          and competition_id = #{competitionId}
+    </select>
+</mapper>

+ 4 - 2
service-base/src/main/resources/mapper/RzCompetitionCalcDateMapper.xml

@@ -7,7 +7,7 @@
                calc_date      as calcDate,
                begin_date     as beginDate,
                end_date       as endDate,
-               start_month    as startDate,
+               start_month    as startMonth,
                end_month      as endMonth
         FROM rc_competition_calc_date
         WHERE isvalid = 1
@@ -19,7 +19,9 @@
                priod,
                calc_date      as calcDate,
                begin_date     as beginDate,
-               end_date       as endDate
+               end_date       as endDate,
+               start_month    as startMonth,
+               end_month      as endMonth
         FROM rc_competition_calc_date
         WHERE isvalid = 1
           AND competition_id = #{competitionId}

+ 18 - 2
service-base/src/main/resources/mapper/RzCompetitionTaskDateMapper.xml

@@ -4,6 +4,7 @@
     <resultMap id="baseResultMap" type="com.simuwang.base.pojo.dos.RcCompetitionTaskDateDO">
         <id column="id" property="id"/>
         <result column="competition_id" property="competitionId"/>
+        <result column="indicator_calc_date" property="indicatorCalcDate"/>
         <result column="nav_detail_date" property="navDetailDate"/>
         <result column="nav_deletion_date" property="navDeletionDate"/>
         <result column="priod_date" property="priodDate"/>
@@ -11,7 +12,7 @@
     </resultMap>
 
     <select id="queryByNavDetailDate" resultMap="baseResultMap">
-        SELECT competition_id, nav_detail_date, nav_deletion_date, priod, priod_date
+        SELECT competition_id, indicator_calc_date, nav_detail_date, nav_deletion_date, priod, priod_date
         FROM `rc_competition_task_date`
         WHERE isvalid = 1
           AND competition_id = #{competitionId}
@@ -19,11 +20,26 @@
     </select>
 
     <select id="queryByNavDeletionDate" resultMap="baseResultMap">
-        SELECT competition_id, nav_detail_date, nav_deletion_date, priod, priod_date
+        SELECT competition_id, indicator_calc_date, nav_detail_date, nav_deletion_date, priod, priod_date
         FROM `rc_competition_task_date`
         WHERE isvalid = 1
           AND competition_id = #{competitionId}
           and nav_deletion_date = #{date}
     </select>
 
+    <select id="queryByIndicatorCalcDate" resultMap="baseResultMap">
+        SELECT competition_id, indicator_calc_date, nav_detail_date, nav_deletion_date, priod, priod_date
+        FROM `rc_competition_task_date`
+        WHERE isvalid = 1
+          AND competition_id = #{competitionId}
+          and indicator_calc_date = #{date}
+    </select>
+
+    <select id="queryByPriodDate" resultMap="baseResultMap">
+        SELECT competition_id, indicator_calc_date, nav_detail_date, nav_deletion_date, priod, priod_date
+        FROM `rc_competition_task_date`
+        WHERE isvalid = 1
+          AND competition_id = #{competitionId}
+          and priod_date = #{date}
+    </select>
 </mapper>

+ 18 - 0
service-base/src/main/resources/mapper/TradeDateMapper.xml

@@ -30,4 +30,22 @@
         </foreach>
     </select>
 
+    <select id="listNatureDays" resultMap="BaseResultMap">
+        select trade_date, end_year, week_of_year, year_week,isholiday
+        from pvn_trade_date
+        where isvalid = 1
+        order by trade_date asc
+    </select>
+
+    <select id="listAllNatureDays" resultType="com.smppw.common.pojo.IndexesTradeDate">
+        select trade_date as tradeDate,
+               week_of_year as weekOfYear,
+               year_week as yearWeek,
+               day_of_week as dayOfWeek,
+               isholiday
+        from pvn_trade_date
+        where isvalid = 1
+        order by trade_date asc
+    </select>
+
 </mapper>

+ 83 - 0
service-calc/src/main/java/com/simuwang/calc/CompetitionIndicatorCalcService.java

@@ -0,0 +1,83 @@
+package com.simuwang.calc;
+
+import cn.hutool.core.collection.CollUtil;
+import com.smppw.common.pojo.dto.CompoundRet;
+import com.smppw.utils.BigDecimalUtils;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Service
+public class CompetitionIndicatorCalcService {
+
+    private static final BigDecimal INDICATOR_MAX_VALUE = new BigDecimal(999999999);
+
+    /**
+     * 计算年化收益率
+     * 年化收益是用月年化
+     *
+     * @param intervalReturn 区间收益率
+     * @param monthsBetween  区间内的月份
+     * @return 年化收益率
+     */
+    public BigDecimal calcRetA(BigDecimal intervalReturn, Integer monthsBetween) {
+        if (intervalReturn != null) {
+            double ret = Double.parseDouble(String.valueOf(intervalReturn));
+            double retA = Math.pow(1 + ret, 12.0 / monthsBetween) - 1;
+            return BigDecimal.valueOf(retA);
+        }
+        return null;
+    }
+
+    /**
+     * 计算周胜率
+     * 周收益 > 0 ? 1: 0
+     *
+     * @param fundRetList 基金周收益率
+     * @return 周胜率(平均周胜率)
+     */
+    public BigDecimal calcWinRate(List<CompoundRet> fundRetList) {
+        if (CollUtil.isEmpty(fundRetList) || fundRetList.size() == 1) {
+            return null;
+        }
+        // 第一周的收益率为null
+        double winWeekCount = (double) fundRetList.stream().map(CompoundRet::getRetOfFund).filter(e -> e != null && e.compareTo(0.0) > 0).count();
+        return BigDecimal.valueOf(winWeekCount / (fundRetList.size() - 1));
+    }
+
+    /**
+     * 计算超额胜率
+     * 基金周收益 > 基准周收益 ? 1: 0
+     *
+     * @param fundRetList 基金周收益率和基准的周收益率
+     * @return 超额胜率(平均超额胜率)
+     */
+    public BigDecimal calcExcessWinRate(List<CompoundRet> fundRetList) {
+        if (CollUtil.isEmpty(fundRetList) || fundRetList.size() == 1) {
+            return null;
+        }
+        double winWeekCount = 0d;
+        for (CompoundRet compoundRet : fundRetList) {
+            Double retOfFund = compoundRet.getRetOfFund();
+            Double retOfBmk = compoundRet.getRetOfBmk();
+            if (retOfFund == null || retOfBmk == null) {
+                continue;
+            }
+            if (retOfFund.compareTo(retOfBmk) > 0) {
+                winWeekCount++;
+            }
+        }
+        return BigDecimal.valueOf(winWeekCount / (fundRetList.size() - 1));
+    }
+
+    public BigDecimal calcCalMarRatio(BigDecimal retA, BigDecimal maxDrawDown) {
+        if (retA == null || maxDrawDown == null) {
+            return null;
+        }
+        if (maxDrawDown.compareTo(BigDecimal.ZERO) == 0) {
+            return INDICATOR_MAX_VALUE;
+        }
+        return BigDecimalUtils.divide(retA, maxDrawDown);
+    }
+}

+ 0 - 1
service-calc/src/main/java/com/simuwang/calc/package-info.java

@@ -1 +0,0 @@
-package com.simuwang.calc;

+ 342 - 0
service-calc/src/main/java/com/simuwang/task/CompetitionIndicatorCalcTask.java

@@ -0,0 +1,342 @@
+package com.simuwang.task;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.common.util.NavDataUtil;
+import com.simuwang.base.config.CompetitionConfig;
+import com.simuwang.base.event.CalcFundRankEventDO;
+import com.simuwang.base.event.CalcFundRankPublisher;
+import com.simuwang.base.mapper.*;
+import com.simuwang.base.pojo.dos.*;
+import com.simuwang.base.pojo.dto.MarketIndexesDTO;
+import com.simuwang.calc.CompetitionIndicatorCalcService;
+import com.smppw.common.pojo.IndexesTradeDate;
+import com.smppw.common.pojo.dto.DateValue;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcSecDataDto;
+import com.smppw.common.pojo.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
+import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
+import com.smppw.common.pojo.enums.*;
+import com.smppw.common.pojo.enums.strategy.Strategy;
+import com.smppw.core.IndicatorService;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.time.YearMonth;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+public class CompetitionIndicatorCalcTask {
+
+    private final CompetitionConfig competitionConfig;
+    private final RcCompetitionTaskDateMapper competitionTaskDateMapper;
+    private final RcCompetitionCalcDateMapper competitionCalcDateMapper;
+    private final NavMapper navMapper;
+    private final TradeDateMapper tradeDateMapper;
+    private final FundInfoMapper fundInfoMapper;
+    private final MarketIndexesMapper marketIndexesMapper;
+    private final DepositNavMapper depositNavMapper;
+    private final FundIndicatorMapper fundIndicatorMapper;
+    private final AssetMapper assetMapper;
+    private final CalcFundRankPublisher calcFundRankPublisher;
+    private final DeletionInfoMapper deletionInfoMapper;
+    private final CompetitionIndicatorCalcService competitionIndicatorCalcService;
+
+    public CompetitionIndicatorCalcTask(CompetitionConfig competitionConfig, RcCompetitionTaskDateMapper competitionTaskDateMapper,
+                                        RcCompetitionCalcDateMapper competitionCalcDateMapper, NavMapper navMapper,
+                                        TradeDateMapper tradeDateMapper, FundInfoMapper fundInfoMapper,
+                                        MarketIndexesMapper marketIndexesMapper, DepositNavMapper depositNavMapper,
+                                        FundIndicatorMapper fundIndicatorMapper, AssetMapper assetMapper,
+                                        CalcFundRankPublisher calcFundRankPublisher, DeletionInfoMapper deletionInfoMapper,
+                                        CompetitionIndicatorCalcService competitionIndicatorCalcService) {
+        this.competitionConfig = competitionConfig;
+        this.competitionTaskDateMapper = competitionTaskDateMapper;
+        this.competitionCalcDateMapper = competitionCalcDateMapper;
+        this.navMapper = navMapper;
+        this.tradeDateMapper = tradeDateMapper;
+        this.fundInfoMapper = fundInfoMapper;
+        this.marketIndexesMapper = marketIndexesMapper;
+        this.depositNavMapper = depositNavMapper;
+        this.fundIndicatorMapper = fundIndicatorMapper;
+        this.assetMapper = assetMapper;
+        this.calcFundRankPublisher = calcFundRankPublisher;
+        this.deletionInfoMapper = deletionInfoMapper;
+        this.competitionIndicatorCalcService = competitionIndicatorCalcService;
+    }
+
+    @Scheduled(cron = "0 0 17 * * ?")
+    //@Scheduled(cron = "0/10 * * * * ?")
+    public void runCalcIndicatorTask() {
+        Integer competitionId = competitionConfig.getId();
+        // 判断是否要计算基金指标
+        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
+        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByIndicatorCalcDate(date, competitionId);
+        if (CollUtil.isEmpty(taskDateDOList)) {
+            return;
+        }
+        List<String> periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().toList();
+        List<RcCompetitionCalcDateDO> calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId);
+        for (RcCompetitionCalcDateDO calcDateDO : calcDateDOList) {
+            String beginDate = calcDateDO.getBeginDate();
+            String endDate = calcDateDO.getEndDate();
+            // 基金净值数据
+            List<NavDO> navDOList = getSevNav(competitionId, beginDate, endDate);
+            if (CollUtil.isEmpty(navDOList)) {
+                continue;
+            }
+            List<String> fundIdList = navDOList.stream().map(NavDO::getFundId).filter(StrUtil::isNotBlank).distinct().toList();
+            Map<String, List<DateValue>> allNavMap = getSecNavMap(navDOList);
+            // 基金-基准映射关系
+            List<FundInfoDO> fundInfoDOList = fundInfoMapper.queryFundInfoByFundId(fundIdList);
+            Map<String, String> secBenchmarkIdMap = fundInfoDOList.stream().collect(Collectors.toMap(FundInfoDO::getFundId, FundInfoDO::getPrimaryBenchmarkId));
+            // 基准净值数据
+            List<String> indexIdList = fundInfoDOList.stream().map(FundInfoDO::getPrimaryBenchmarkId).distinct().toList();
+            Map<String, List<DateValue>> benchmarkIdNavMap = getBenchmarkNavMap(indexIdList, beginDate, endDate);
+            allNavMap.putAll(benchmarkIdNavMap);
+            Map<String, Frequency> secFreqMap = fundIdList.stream().collect(Collectors.toMap(k -> k, v -> Frequency.Weekly));
+            CalcMultipleSecMultipleTimeRangeIndicatorReq req = prepareIndicatorReq(fundIdList, secBenchmarkIdMap, indexIdList, beginDate, endDate);
+
+            // 计算指标
+            IndicatorService indicatorService = IndicatorService.getInstance();
+            Map<String, List<IndicatorCalcPropertyDto>> secMultipleTimeRangeIndicator = indicatorService.calcMultipleSecMultipleTimeRangeIndicator(req, allNavMap, secFreqMap);
+            if (MapUtil.isEmpty(secMultipleTimeRangeIndicator)) {
+                continue;
+            }
+            // 资产规模
+            Map<String, BigDecimal> fundIdAssetMap = getFundAsset(fundIdList, beginDate, endDate, calcDateDO.getEndMonth());
+            // 绘制到指标结果表:fund_indicator
+            List<FundIndicatorDO> fundIndicatorDOList = convertToFundIndicatorDo(competitionId, calcDateDO, fundIdAssetMap, secMultipleTimeRangeIndicator);
+            if (CollUtil.isNotEmpty(fundIndicatorDOList)) {
+                fundIndicatorMapper.batchInsertOrUpdate(fundIndicatorDOList);
+            }
+
+            // 发布计算排名事件
+            calcFundRankPublisher.publishEvent(new CalcFundRankEventDO(competitionId, calcDateDO.getPriod(), allNavMap));
+        }
+    }
+
+    private List<FundIndicatorDO> convertToFundIndicatorDo(Integer competitionId, RcCompetitionCalcDateDO calcDateDO, Map<String, BigDecimal> fundIdAssetMap,
+                                                           Map<String, List<IndicatorCalcPropertyDto>> secMultipleTimeRangeIndicator) {
+        List<FundIndicatorDO> fundIndicatorDOList = CollUtil.newArrayList();
+        if (MapUtil.isEmpty(secMultipleTimeRangeIndicator)) {
+            return fundIndicatorDOList;
+        }
+
+        YearMonth startYearMonth = YearMonth.parse(calcDateDO.getStartMonth());
+        YearMonth endYearMonth = YearMonth.parse(calcDateDO.getEndMonth());
+        int monthsBetween = (int) ChronoUnit.MONTHS.between(startYearMonth, endYearMonth) + 1;
+        BigDecimal maxValue = new BigDecimal(999999999);
+        for (Map.Entry<String, List<IndicatorCalcPropertyDto>> indicatorEntry : secMultipleTimeRangeIndicator.entrySet()) {
+            String fundId = indicatorEntry.getKey();
+            List<IndicatorCalcPropertyDto> indicatorCalcPropertyDtoList = indicatorEntry.getValue();
+            IndicatorCalcSecDataDto indicatorCalcSecDataDto = indicatorCalcPropertyDtoList.get(0).getSecData();
+            if (indicatorCalcSecDataDto != null) {
+                // 常见指标
+                Map<String, String> indicatorValueMap = indicatorCalcSecDataDto.getIndicatorValueMap();
+                // 超额指标
+                Map<String, String> extraGeoIndicatorValueMap = indicatorCalcSecDataDto.getExtraGeoIndicatorValueMap();
+                FundIndicatorDO fundIndicatorDO = new FundIndicatorDO();
+                fundIndicatorDO.setCompetitionId(competitionId);
+                fundIndicatorDO.setFundId(fundId);
+                fundIndicatorDO.setPriod(calcDateDO.getPriod());
+                BigDecimal intervalReturn = MapUtil.get(indicatorValueMap, "IntervalReturn", BigDecimal.class, null);
+                fundIndicatorDO.setRet(intervalReturn);
+                // 计算年化收益率
+                BigDecimal retA = competitionIndicatorCalcService.calcRetA(intervalReturn, monthsBetween);
+                fundIndicatorDO.setRetA(retA);
+                // 计算周胜率
+                BigDecimal winRate = competitionIndicatorCalcService.calcWinRate(indicatorCalcSecDataDto.getRetList());
+                fundIndicatorDO.setWinrate(winRate);
+                // 计算超额胜率
+                BigDecimal excessWinRate = competitionIndicatorCalcService.calcExcessWinRate(indicatorCalcSecDataDto.getRetList());
+                fundIndicatorDO.setExcessWinrate(excessWinRate);
+                fundIndicatorDO.setAlpha(MapUtil.get(indicatorValueMap, "Alpha", BigDecimal.class, null));
+                fundIndicatorDO.setInfoRatio(MapUtil.get(indicatorValueMap, "InformationRatio", BigDecimal.class, null));
+
+                BigDecimal sharpeRatio = MapUtil.get(indicatorValueMap, "SharpeRatio", BigDecimal.class, null);
+                sharpeRatio = sharpeRatio != null && sharpeRatio.compareTo(new BigDecimal(999999)) == 0 ? maxValue : sharpeRatio;
+                fundIndicatorDO.setSharperatio(sharpeRatio);
+
+                BigDecimal sortinoRatio = MapUtil.get(indicatorValueMap, "SortinoRatio", BigDecimal.class, null);
+                sortinoRatio = sortinoRatio != null && sortinoRatio.compareTo(new BigDecimal(999999)) == 0 ? maxValue : sortinoRatio;
+                fundIndicatorDO.setSortinoratio(sortinoRatio);
+
+                BigDecimal maxDrawDown = MapUtil.get(indicatorValueMap, "MaxDrawdown", BigDecimal.class, null);
+                fundIndicatorDO.setMaxdrawdown(maxDrawDown);
+
+                // 计算calmar
+                BigDecimal calmarRatio = competitionIndicatorCalcService.calcCalMarRatio(retA, maxDrawDown);
+                fundIndicatorDO.setCalmarratio(calmarRatio);
+
+                fundIndicatorDO.setExcessGeometry(MapUtil.get(extraGeoIndicatorValueMap, "ExcessReturnRealTimeCalc", BigDecimal.class, null));
+                fundIndicatorDO.setExcessStddev(MapUtil.get(extraGeoIndicatorValueMap, "ExcessReturnAnnualStdDevExtra", BigDecimal.class, null));
+                fundIndicatorDO.setExcessMaxdrawdown(MapUtil.get(extraGeoIndicatorValueMap, "ExcessReturnMaxDrawdown", BigDecimal.class, null));
+
+                BigDecimal excessReturnSharpeRatioExtra = MapUtil.get(extraGeoIndicatorValueMap, "ExcessReturnSharpeRatioExtra", BigDecimal.class, null);
+                excessReturnSharpeRatioExtra = excessReturnSharpeRatioExtra != null && excessReturnSharpeRatioExtra.compareTo(new BigDecimal(999999)) == 0 ? maxValue : excessReturnSharpeRatioExtra;
+                fundIndicatorDO.setExcessSharperatio(excessReturnSharpeRatioExtra);
+
+                BigDecimal excessReturnCalmarRatio = MapUtil.get(extraGeoIndicatorValueMap, "ExcessReturnCalmarRatio", BigDecimal.class, null);
+                excessReturnCalmarRatio = excessReturnCalmarRatio != null && excessReturnCalmarRatio.compareTo(new BigDecimal(999999)) == 0 ? maxValue : excessReturnCalmarRatio;
+                fundIndicatorDO.setExcessCalmarratio(excessReturnCalmarRatio);
+
+                fundIndicatorDO.setProductScale(fundIdAssetMap.get(fundId));
+                fundIndicatorDO.setIsvalid(1);
+                fundIndicatorDO.setCreatorId(999999);
+                fundIndicatorDO.setCreateTime(new Date());
+                fundIndicatorDO.setUpdaterId(999999);
+                fundIndicatorDO.setUpdateTime(new Date());
+                fundIndicatorDOList.add(fundIndicatorDO);
+            }
+        }
+        return fundIndicatorDOList;
+    }
+
+    private CalcMultipleSecMultipleTimeRangeIndicatorReq prepareIndicatorReq(List<String> fundIdList, Map<String, String> secBenchmarkIdMap, List<String> indexIdList, String startDate, String endDate) {
+        // 需要计算的指标,超额指标
+        List<Indicator> indicatorList = ListUtil.of(Indicator.IntervalReturn, Indicator.AnnualReturn, Indicator.MaxDrawdown, Indicator.SharpeRatio,
+                Indicator.SortinoRatio, Indicator.CalmarRatio, Indicator.InformationRatio, Indicator.Alpha);
+        List<Indicator> geoExtraIndicatorList = ListUtil.of(Indicator.ExcessReturnRealTimeCalc, Indicator.ExcessReturnMaxDrawdown, Indicator.ExcessReturnCalmarRatio,
+                Indicator.ExcessReturnSharpeRatioExtra, Indicator.ExcessReturnAnnualStdDevExtra);
+        // 自定义计算时段
+        DateIntervalDto dateIntervalDto = DateIntervalDto.builder()
+                .id(DateIntervalType.CustomInterval.name()).startDate(startDate).endDate(endDate).frequency(Frequency.Weekly)
+                .dateIntervalType(DateIntervalType.CustomInterval).frequency(Frequency.Default).build();
+        Map<String, List<DateIntervalDto>> secDateIntervalDtoListMap = fundIdList.stream().collect(Collectors.toMap(k -> k, v -> ListUtil.toList(dateIntervalDto)));
+        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
+                .mainSecIdList(fundIdList)
+                .secBenchmarkIdMap(secBenchmarkIdMap)
+                .indexIdList(indexIdList)
+                .raiseType(RaiseType.Both)
+                .strategy(Strategy.All)
+                .visibility(Visibility.Both)
+                .dataFrequency(Frequency.Weekly)
+                .navType(NavType.WithdrawalNav)
+                .secDateIntervalDtoListMap(secDateIntervalDtoListMap)
+                .indicatorList(indicatorList)
+                .geoExtraindicatorList(geoExtraIndicatorList)
+                .ifAnnualize(true)
+                .riskOfFreeId(null)
+                .riskOfFreeValue(1.5)
+                .calcIndexRetIndicatorValue(true)
+                .ifConvertPerformanceConsistencyWord(false).build();
+    }
+
+    private Map<String, BigDecimal> getFundAsset(List<String> fundIdList, String beginDate, String endDate, String endMonth) {
+        Map<String, BigDecimal> fundIdAssetMap = MapUtil.newHashMap();
+        if (CollUtil.isEmpty(fundIdList)) {
+            return fundIdAssetMap;
+        }
+        List<AssetDO> assetDOList = assetMapper.queryByFundId(fundIdList, beginDate, endDate);
+        if (CollUtil.isNotEmpty(assetDOList)) {
+            Map<String, List<AssetDO>> fundIdAssetDoMap = assetDOList.stream().collect(Collectors.groupingBy(AssetDO::getFundId));
+            for (Map.Entry<String, List<AssetDO>> fundIdAssetDoEntry : fundIdAssetDoMap.entrySet()) {
+                String fundId = fundIdAssetDoEntry.getKey();
+                // 榜单最后月份的最新一期规模
+                BigDecimal asset = fundIdAssetDoEntry.getValue().stream()
+                        .filter(e -> DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD).contains(endMonth))
+                        .max(Comparator.comparing(AssetDO::getPriceDate)).map(AssetDO::getAssetNet).orElse(null);
+                fundIdAssetMap.put(fundId, asset);
+            }
+        }
+        return fundIdAssetMap;
+    }
+
+    private Map<String, List<DateValue>> getRiskOfFreeNavMap(String riskOfFreeId, String startDate, String endDate) {
+        Map<String, List<DateValue>> riskOfFreeNavMap = MapUtil.newHashMap();
+        if (StrUtil.isBlank(riskOfFreeId)) {
+            return riskOfFreeNavMap;
+        }
+        List<DepositNavDO> depositNavDOList = depositNavMapper.queryByFundId(riskOfFreeId, startDate, endDate);
+        List<DateValue> dateValues = depositNavDOList.stream().map(e -> {
+            DateValue dateValue = new DateValue();
+            dateValue.setDate(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD));
+            dateValue.setValue(e.getNav() != null ? Double.valueOf(String.valueOf(e.getNav())) : null);
+            dateValue.setIsvalid(1);
+            return dateValue;
+        }).sorted(Comparator.comparing(DateValue::getDate)).toList();
+        riskOfFreeNavMap.put(riskOfFreeId, dateValues);
+        return riskOfFreeNavMap;
+    }
+
+
+    private Map<String, List<DateValue>> getBenchmarkNavMap(List<String> indexIdList, String startDate, String endDate) {
+        Map<String, List<DateValue>> benchmarkIdNavMap = MapUtil.newHashMap();
+        if (CollUtil.isEmpty(indexIdList)) {
+            return benchmarkIdNavMap;
+        }
+        List<MarketIndexesDTO> marketIndexesDTOList = marketIndexesMapper.queryByIndexId(indexIdList, startDate, endDate);
+        Map<String, List<MarketIndexesDTO>> indexIdNavMap = marketIndexesDTOList.stream().collect(Collectors.groupingBy(MarketIndexesDTO::getIndexId));
+        for (Map.Entry<String, List<MarketIndexesDTO>> indexIdNavEntry : indexIdNavMap.entrySet()) {
+            String indexId = indexIdNavEntry.getKey();
+            List<MarketIndexesDTO> indexesDTOList = indexIdNavEntry.getValue();
+            List<DateValue> dateValues = indexesDTOList.stream().map(e -> {
+                DateValue dateValue = new DateValue();
+                dateValue.setDate(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD));
+                dateValue.setValue(e.getClose() != null ? Double.valueOf(String.valueOf(e.getClose())) : null);
+                dateValue.setIsvalid(1);
+                return dateValue;
+            }).sorted(Comparator.comparing(DateValue::getDate)).toList();
+            benchmarkIdNavMap.put(indexId, dateValues);
+        }
+        return benchmarkIdNavMap;
+    }
+
+    private Map<String, List<DateValue>> getSecNavMap(List<NavDO> navDOList) {
+        if (CollUtil.isEmpty(navDOList)) {
+            return MapUtil.newHashMap();
+        }
+        Map<String, List<DateValue>> secMap = MapUtil.newHashMap();
+        Map<String, List<NavDO>> fundIdNavDoMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
+        for (Map.Entry<String, List<NavDO>> fundIdNavDoEntry : fundIdNavDoMap.entrySet()) {
+            String fundId = fundIdNavDoEntry.getKey();
+            List<NavDO> navList = fundIdNavDoEntry.getValue();
+            List<DateValue> dateValueList = navList.stream().map(e -> {
+                DateValue dateValue = new DateValue();
+                dateValue.setDate(DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD));
+                // 使用累计净值计算指标
+                dateValue.setValue(e.getCumulativeNavWithdrawal() != null ? Double.valueOf(String.valueOf(e.getCumulativeNavWithdrawal())) : null);
+                dateValue.setOriginalNav(e.getNav());
+                dateValue.setCumulativeNavWithdrawal(e.getCumulativeNavWithdrawal());
+                dateValue.setIsvalid(1);
+                return dateValue;
+            }).sorted(Comparator.comparing(DateValue::getDate)).toList();
+            secMap.put(fundId, dateValueList);
+        }
+        return secMap;
+    }
+
+    private List<IndexesTradeDate> getTradeDates() {
+        List<TradeDateDO> dataList = this.tradeDateMapper.listNatureDays();
+        return dataList.stream().filter(e -> Objects.equals(0, e.getIsholiday())).map(e -> {
+            IndexesTradeDate indexesTradeDate = new IndexesTradeDate();
+            indexesTradeDate.setTradeDate(DateUtil.format(e.getTradeDate(), DateConst.YYYY_MM_DD));
+            indexesTradeDate.setIsholiday(e.getIsholiday());
+            indexesTradeDate.setYearmonth(e.getYearmonth());
+            indexesTradeDate.setYearWeek(e.getYearWeek() != null ? String.valueOf(e.getYearWeek()) : null);
+            indexesTradeDate.setDayOfWeek(e.getDayOfWeek());
+
+            return indexesTradeDate;
+        }).collect(Collectors.toList());
+    }
+
+    private List<NavDO> getSevNav(Integer competitionId, String beginDate, String endDate) {
+        List<NavDO> navDOList = navMapper.queryAllNav(competitionId, beginDate, endDate);
+        // 过滤掉净值缺失的基金
+        List<FundDeletionInfoDO> fundNavDeletionList = deletionInfoMapper.getFundNavDeletion(1, competitionId, beginDate, endDate);
+        if (CollUtil.isNotEmpty(fundNavDeletionList)) {
+            List<String> fundIdList = fundNavDeletionList.stream().map(FundDeletionInfoDO::getFundId).toList();
+            navDOList = navDOList.stream().filter(e -> !fundIdList.contains(e.getFundId())).toList();
+        }
+        List<TradeDateDO> tradeDateDOList = tradeDateMapper.selectTradeDate(beginDate, endDate);
+        return NavDataUtil.filterWeekFrequencyNav(navDOList, tradeDateDOList);
+    }
+
+}

+ 1 - 1
service-deploy/src/main/resources/application.yml

@@ -63,7 +63,7 @@ email:
 competition:
   # 大赛id
   id: 48
-  name: 方正证券_方华杯私募成长计划(第三届)
+  name: 方华杯私募成长计划(第三届)
   # 输出方式:1-邮箱,2-指定目录.默认1
   method: 1
   # 输出目录(仅当 method 为 2 时有效)

+ 1 - 1
service-manage/src/main/java/com/simuwang/manage/service/competition/AbstractCompetitionResultService.java

@@ -11,7 +11,7 @@ public abstract class AbstractCompetitionResultService {
         return false;
     }
 
-    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult(){
+    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId, String period){
         return CollUtil.newArrayList();
     }
 

+ 23 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/CalcFundRankListener.java

@@ -0,0 +1,23 @@
+package com.simuwang.manage.service.competition;
+
+import com.simuwang.base.event.CalcFundRankEvent;
+import com.simuwang.base.event.CalcFundRankEventDO;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CalcFundRankListener implements ApplicationListener<CalcFundRankEvent> {
+
+    private final CalcFundRankService calcFundRankService;
+
+    public CalcFundRankListener(CalcFundRankService calcFundRankService) {
+        this.calcFundRankService = calcFundRankService;
+    }
+
+    @Override
+    public void onApplicationEvent(CalcFundRankEvent event) {
+        CalcFundRankEventDO fundRankEventDO = event.getEventObject();
+        calcFundRankService.calFundRank(fundRankEventDO);
+    }
+
+}

+ 250 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/CalcFundRankService.java

@@ -0,0 +1,250 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.event.CalcFundRankEventDO;
+import com.simuwang.base.mapper.*;
+import com.simuwang.base.pojo.FundInitAndEndNavDTO;
+import com.simuwang.base.pojo.dos.*;
+import com.simuwang.base.pojo.dto.FundScoreRankDTO;
+import com.smppw.common.pojo.dto.DateValue;
+import com.smppw.utils.BigDecimalUtils;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class CalcFundRankService {
+
+    private final FundIndicatorMapper fundIndicatorMapper;
+    private final RcCompetitionApplyMapper competitionApplyMapper;
+    private final FundRatingRuleMapper fundRatingRuleMapper;
+    private final FundInfoMapper fundInfoMapper;
+    private final RcCompetitionResultMapper rcCompetitionResultMapper;
+
+    public CalcFundRankService(FundIndicatorMapper fundIndicatorMapper, RcCompetitionApplyMapper competitionApplyMapper,
+                               FundRatingRuleMapper fundRatingRuleMapper, FundInfoMapper fundInfoMapper,
+                               RcCompetitionResultMapper rcCompetitionResultMapper) {
+        this.fundIndicatorMapper = fundIndicatorMapper;
+        this.competitionApplyMapper = competitionApplyMapper;
+        this.fundRatingRuleMapper = fundRatingRuleMapper;
+        this.fundInfoMapper = fundInfoMapper;
+        this.rcCompetitionResultMapper = rcCompetitionResultMapper;
+    }
+
+    public void calFundRank(CalcFundRankEventDO calcFundRankEventDO) {
+        Integer competitionId = calcFundRankEventDO.getCompetitionId();
+        String period = calcFundRankEventDO.getPeriod();
+        List<FundIndicatorDO> fundIndicatorList = fundIndicatorMapper.queryByPeriod(competitionId, period);
+        if (CollUtil.isEmpty(fundIndicatorList)) {
+            return;
+        }
+        // 基金策略
+        List<RcCompetitionApplyDO> competitionApplyDOList = competitionApplyMapper.queryByCompetitionId(competitionId);
+        Map<String, Integer> fundIdStrategyMap = competitionApplyDOList.stream().collect(Collectors.toMap(RcCompetitionApplyDO::getFundId, RcCompetitionApplyDO::getStrategy));
+        // 排名规则
+        List<FundRatingRuleDO> ratingRuleDOList = fundRatingRuleMapper.queryByCompetitionId(competitionId);
+        Map<Integer, List<FundRatingRuleDO>> strategyRatingRuleMap = ratingRuleDOList.stream().collect(Collectors.groupingBy(FundRatingRuleDO::getStrategyId));
+        // 基金按照策略进行分组
+        Map<Integer, List<FundIndicatorDO>> strategyIndicatorMap = fundIndicatorList.stream().collect(Collectors.groupingBy(k -> fundIdStrategyMap.get(k.getFundId())));
+        List<FundScoreRankDTO> fundScoreRankDTOList = CollUtil.newArrayList();
+        for (Map.Entry<Integer, List<FundIndicatorDO>> strategyIndicatorEntry : strategyIndicatorMap.entrySet()) {
+            List<FundIndicatorDO> indicatorDOList = strategyIndicatorEntry.getValue();
+            Integer strategyId = strategyIndicatorEntry.getKey();
+            List<FundRatingRuleDO> ruleDOList = strategyRatingRuleMap.get(strategyId);
+            // 计算综合得分和排名
+            List<FundScoreRankDTO> scoreRankDTOList = calculateScoreAndRank(indicatorDOList, ruleDOList);
+            scoreRankDTOList.forEach(e -> e.setStrategyId(strategyId));
+            fundScoreRankDTOList.addAll(scoreRankDTOList);
+        }
+        if (CollUtil.isEmpty(fundScoreRankDTOList)) {
+            return;
+        }
+        // 绘制榜单结果表
+        saveCompetitionResult(competitionId, period, fundIndicatorList, fundScoreRankDTOList, competitionApplyDOList, calcFundRankEventDO.getFundIdNavMap());
+    }
+
+    private void saveCompetitionResult(Integer competitionId, String period, List<FundIndicatorDO> fundIndicatorList, List<FundScoreRankDTO> fundScoreRankDTOList,
+                                       List<RcCompetitionApplyDO> competitionApplyDOList, Map<String, List<DateValue>> fundIdNavMap) {
+        // 基金信息和机构信息
+        List<String> fundIdList = competitionApplyDOList.stream().map(RcCompetitionApplyDO::getFundId).toList();
+        List<FundAndCompanyInfoDO> fundCompanyInfoDOList = fundInfoMapper.queryFundAndTrustByFundId(competitionId, fundIdList);
+        Map<String, FundAndCompanyInfoDO> fundIdInfoMap = fundCompanyInfoDOList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
+        // 基金的期初期末净值信息
+        Map<String, FundInitAndEndNavDTO> fundIdInitAndEndNavMap = getFundInitAndEndNav(fundIdNavMap);
+        // 榜单数据
+        Map<String, FundScoreRankDTO> fundIdScoreRankMap = fundScoreRankDTOList.stream().collect(Collectors.toMap(FundScoreRankDTO::getFundId, v -> v));
+        Map<String, FundIndicatorDO> fundIdIndicatorMap = fundIndicatorList.stream().collect(Collectors.toMap(FundIndicatorDO::getFundId, v -> v));
+        List<RcCompetitionResultDO> competitionResultDOList = convertToCompetitionResultDO(competitionId, period, fundIdIndicatorMap, fundIdInfoMap, fundIdInitAndEndNavMap, fundIdScoreRankMap);
+        if (CollUtil.isNotEmpty(competitionResultDOList)) {
+            List<List<RcCompetitionResultDO>> partition = ListUtil.partition(competitionResultDOList, 500);
+            partition.forEach(rcCompetitionResultMapper::batchInsertOrUpdate);
+        }
+    }
+
+    private List<FundScoreRankDTO> calculateScoreAndRank(List<FundIndicatorDO> indicatorDOList, List<FundRatingRuleDO> ruleDOList) {
+        List<FundScoreRankDTO> scoreRankDTOList = CollUtil.newArrayList();
+        if (CollUtil.isEmpty(indicatorDOList) || CollUtil.isEmpty(ruleDOList)) {
+            return scoreRankDTOList;
+        }
+        // 1.按照规则计算综合得分
+        Map<String, BigDecimal> fundIdScoreMap = MapUtil.newHashMap(indicatorDOList.size());
+        List<Map<String, String>> indicatorMapList = indicatorDOList.stream().map(this::convertToMap).toList();
+        for (FundRatingRuleDO ratingRuleDo : ruleDOList) {
+            String indicatorId = ratingRuleDo.getIndicatorId();
+            BigDecimal weight = ratingRuleDo.getWeight();
+            Integer ratingType = ratingRuleDo.getRatingType();
+            // 参与评分的指标总数
+            int total = (int) indicatorMapList.stream().map(e -> e.get(indicatorId)).filter(StrUtil::isNotBlank).count();
+            if (total == 0) {
+                continue;
+            }
+            for (Map<String, String> indicatorMap : indicatorMapList) {
+                String fundId = indicatorMap.get("fundId");
+                String indicatorValue = indicatorMap.get(indicatorId);
+                if (StrUtil.isBlank(indicatorValue)) {
+                    continue;
+                }
+                // 计算单个指标排名(从小到大 或 从大到小 排名)
+                int rank;
+                if (ratingType == 1) {
+                    rank = (int) indicatorMapList.stream().map(e -> e.get(indicatorId))
+                            .filter(StrUtil::isNotBlank).map(Double::valueOf).filter(e -> e.compareTo(Double.valueOf(indicatorValue)) > 0).count() + 1;
+                } else {
+                    rank = (int) indicatorMapList.stream().map(e -> e.get(indicatorId))
+                            .filter(StrUtil::isNotBlank).map(Double::valueOf).filter(e -> e.compareTo(Double.valueOf(indicatorValue)) < 0).count() + 1;
+                }
+                // 排名得分 = [100-100*(绝对排名-1)/(总数-1)] * 权重
+                double indicatorRank = total == 1 ? 100 : 100 - (100.0 * (rank - 1) / (total - 1));
+                BigDecimal score = BigDecimalUtils.multiply(BigDecimal.valueOf(indicatorRank), weight);
+                if (fundIdScoreMap.containsKey(fundId)) {
+                    score = BigDecimalUtils.add(fundIdScoreMap.get(fundId), score);
+                }
+                fundIdScoreMap.put(fundId, score);
+            }
+        }
+
+        // 2.计算排名
+        List<Map.Entry<String, BigDecimal>> list = new ArrayList<>(fundIdScoreMap.entrySet());
+        // 按照BigDecimal值降序排序
+        list.sort((o1, o2) -> o2.getValue().compareTo(o1.getValue()));
+        int rank = 1;
+        for (Map.Entry<String, BigDecimal> entry : list) {
+            FundScoreRankDTO dto = new FundScoreRankDTO(entry.getKey(), null, entry.getValue(), rank++);
+            scoreRankDTOList.add(dto);
+        }
+        return scoreRankDTOList;
+    }
+
+    private Map<String, FundInitAndEndNavDTO> getFundInitAndEndNav(Map<String, List<DateValue>> fundIdNavMap) {
+        Map<String, FundInitAndEndNavDTO> fundIdInitAndEndNavMap = MapUtil.newHashMap();
+        for (Map.Entry<String, List<DateValue>> fundIdNavEntry : fundIdNavMap.entrySet()) {
+            String fundId = fundIdNavEntry.getKey();
+            List<DateValue> dateValueList = fundIdNavEntry.getValue();
+            if (CollUtil.isEmpty(dateValueList) || dateValueList.size() == 1) {
+                continue;
+            }
+            FundInitAndEndNavDTO initAndEndNavDTO = new FundInitAndEndNavDTO();
+            initAndEndNavDTO.setFundId(fundId);
+            DateValue maxNav = dateValueList.stream().max(Comparator.comparing(DateValue::getDate)).orElse(null);
+            DateValue minNav = dateValueList.stream().min(Comparator.comparing(DateValue::getDate)).orElse(null);
+            if (minNav != null) {
+                initAndEndNavDTO.setStartDate(minNav.getDate());
+                initAndEndNavDTO.setStartCumulativeNavWithdrawal(minNav.getCumulativeNavWithdrawal());
+            }
+            if (maxNav != null) {
+                initAndEndNavDTO.setEndDate(maxNav.getDate());
+                initAndEndNavDTO.setEndCumulativeNavWithdrawal(maxNav.getCumulativeNavWithdrawal());
+            }
+            fundIdInitAndEndNavMap.put(fundId, initAndEndNavDTO);
+        }
+        return fundIdInitAndEndNavMap;
+    }
+
+    private List<RcCompetitionResultDO> convertToCompetitionResultDO(Integer competitionId, String period, Map<String, FundIndicatorDO> fundIdIndicatorMap, Map<String, FundAndCompanyInfoDO> fundIdInfoMap,
+                                                                     Map<String, FundInitAndEndNavDTO> fundIdInitAndEndNavMap, Map<String, FundScoreRankDTO> fundIdScoreRankMap) {
+        List<RcCompetitionResultDO> competitionResultDOList = CollUtil.newArrayList();
+        for (Map.Entry<String, FundIndicatorDO> fundIdIndicatorEntry : fundIdIndicatorMap.entrySet()) {
+            String fundId = fundIdIndicatorEntry.getKey();
+            FundIndicatorDO fundIndicatorDO = fundIdIndicatorEntry.getValue();
+            RcCompetitionResultDO resultDO = new RcCompetitionResultDO();
+            resultDO.setCompetitionId(competitionId);
+            resultDO.setPriod(period);
+            FundAndCompanyInfoDO fundAndCompanyInfoDO = fundIdInfoMap.get(fundId);
+            resultDO.setFundId(fundId);
+            resultDO.setStrategy(fundAndCompanyInfoDO.getStrategyId());
+            resultDO.setFundRegisterNumber(fundAndCompanyInfoDO.getRegisterNumber());
+            resultDO.setFundName(fundAndCompanyInfoDO.getFundName());
+            resultDO.setFundShortName(fundAndCompanyInfoDO.getFundShortName());
+            resultDO.setCompanyId(fundAndCompanyInfoDO.getCompanyId());
+            resultDO.setCompanyName(fundAndCompanyInfoDO.getCompanyName());
+            resultDO.setCompanyShortName(fundAndCompanyInfoDO.getCompanyShortName());
+            resultDO.setCompanyRegisterNumber(fundAndCompanyInfoDO.getCompanyRegisterNumber());
+            resultDO.setCompanyScale(fundAndCompanyInfoDO.getCompanyScale());
+            resultDO.setIsOpenAccount(fundAndCompanyInfoDO.getIsOpenAccount());
+            resultDO.setIsOpenAccount2(fundAndCompanyInfoDO.getIsOpenAccount2());
+
+            FundScoreRankDTO fundScoreRankDTO = fundIdScoreRankMap.get(fundId);
+            if (fundScoreRankDTO != null) {
+                resultDO.setRank(fundScoreRankDTO.getRank());
+                resultDO.setScore(fundScoreRankDTO.getScore());
+            }
+            FundInitAndEndNavDTO initAndEndNavDTO = fundIdInitAndEndNavMap.get(fundId);
+            if (initAndEndNavDTO != null) {
+                resultDO.setPrePriceDate(StrUtil.isNotBlank(initAndEndNavDTO.getStartDate()) ? DateUtil.parse(initAndEndNavDTO.getStartDate(), DateConst.YYYY_MM_DD) : null);
+                resultDO.setPreCumulativeNavWithdrawal(initAndEndNavDTO.getStartCumulativeNavWithdrawal());
+                resultDO.setPriceDate(StrUtil.isNotBlank(initAndEndNavDTO.getEndDate()) ? DateUtil.parse(initAndEndNavDTO.getEndDate(), DateConst.YYYY_MM_DD) : null);
+                resultDO.setCumulativeNavWithdrawal(initAndEndNavDTO.getEndCumulativeNavWithdrawal());
+            }
+            if (fundIndicatorDO != null) {
+                resultDO.setRet(fundIndicatorDO.getRet());
+                resultDO.setRetA(fundIndicatorDO.getRetA());
+                resultDO.setMaxdrawdown(fundIndicatorDO.getMaxdrawdown());
+                resultDO.setCalmarratio(fundIndicatorDO.getCalmarratio());
+                resultDO.setSortinoratio(fundIndicatorDO.getSortinoratio());
+                resultDO.setSharperatio(fundIndicatorDO.getSharperatio());
+                resultDO.setAlpha(fundIndicatorDO.getAlpha());
+                resultDO.setWinrate(fundIndicatorDO.getWinrate());
+                resultDO.setInfoRatio(fundIndicatorDO.getInfoRatio());
+                resultDO.setExcessWinrate(fundIndicatorDO.getExcessWinrate());
+                resultDO.setExcessRet(fundIndicatorDO.getExcessGeometry());
+                resultDO.setExcessMaxdown(fundIndicatorDO.getExcessMaxdrawdown());
+                resultDO.setExcessCalmarratio(fundIndicatorDO.getExcessCalmarratio());
+                resultDO.setExcessSharperatio(fundIndicatorDO.getExcessSharperatio());
+                resultDO.setExcessStddev(fundIndicatorDO.getExcessStddev());
+                resultDO.setProductScale(fundIndicatorDO.getProductScale());
+            }
+            resultDO.setIsvalid(1);
+            resultDO.setCreateTime(new Date());
+            resultDO.setCreatorId(999999);
+            resultDO.setUpdaterId(999999);
+            resultDO.setUpdateTime(new Date());
+            competitionResultDOList.add(resultDO);
+        }
+        return competitionResultDOList;
+    }
+
+    public Map<String, String> convertToMap(FundIndicatorDO indicatorDO) {
+        Map<String, String> indicatorMap = MapUtil.newHashMap();
+        Field[] fields = FundIndicatorDO.class.getDeclaredFields();
+        for (Field field : fields) {
+            field.setAccessible(true);
+            Object value = null;
+            try {
+                value = field.get(indicatorDO);
+            } catch (Exception e) {
+                indicatorMap.put(field.getName(), null);
+            }
+            indicatorMap.put(field.getName(), value != null ? value.toString() : null);
+        }
+        return indicatorMap;
+    }
+
+}

+ 168 - 25
service-manage/src/main/java/com/simuwang/manage/service/competition/FundNavService.java

@@ -1,33 +1,176 @@
 package com.simuwang.manage.service.competition;
 
-import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.common.util.NavDataUtil;
+import com.simuwang.base.mapper.*;
+import com.simuwang.base.pojo.dos.*;
 import com.simuwang.base.pojo.dto.FundNavDataDTO;
 import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
+import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
+import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Comparator;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class FundNavService {
+
+    private final NavMapper navMapper;
+    private final FundInfoMapper fundInfoMapper;
+    private final AssetMapper assetMapper;
+    private final DeletionInfoMapper deletionInfoMapper;
+    private final TradeDateMapper tradeDateMapper;
+    private final CompetitionFactory competitionFactory;
+    private final RcCompetitionTaskDateMapper competitionTaskDateMapper;
+    private final RcCompetitionCalcDateMapper competitionCalcDateMapper;
+
+    public FundNavService(NavMapper navMapper, FundInfoMapper fundInfoMapper,
+                          AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper,
+                          TradeDateMapper tradeDateMapper, CompetitionFactory competitionFactory,
+                          RcCompetitionTaskDateMapper competitionTaskDateMapper, RcCompetitionCalcDateMapper competitionCalcDateMapper) {
+        this.navMapper = navMapper;
+        this.fundInfoMapper = fundInfoMapper;
+        this.assetMapper = assetMapper;
+        this.deletionInfoMapper = deletionInfoMapper;
+        this.tradeDateMapper = tradeDateMapper;
+        this.competitionFactory = competitionFactory;
+        this.competitionTaskDateMapper = competitionTaskDateMapper;
+        this.competitionCalcDateMapper = competitionCalcDateMapper;
+    }
+
+
+    public List<FundNavDataDTO> getFungNavData(Integer competitionId, String startDate, String endDate) {
+        List<FundNavDataDTO> navDataDTOList = CollUtil.newArrayList();
+        List<NavDO> navDOList = navMapper.queryAllNav(competitionId, startDate, endDate);
+        if (CollUtil.isEmpty(navDOList)) {
+            return navDataDTOList;
+        }
+        // 过滤出周频的净值点
+        List<TradeDateDO> tradeDateDOList = tradeDateMapper.selectTradeDate(startDate, endDate);
+        navDOList = NavDataUtil.filterWeekFrequencyNav(navDOList, tradeDateDOList);
+
+        List<String> fundIdList = navDOList.stream().map(NavDO::getFundId).distinct().toList();
+        List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId, fundIdList);
+        Map<String, FundAndCompanyInfoDO> fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
+        List<AssetDO> assetDOList = assetMapper.queryAssetByFundId(fundIdList);
+        Map<String, List<AssetDO>> fundIdAssetMap = MapUtil.newHashMap();
+        if (CollUtil.isNotEmpty(assetDOList)) {
+            fundIdAssetMap = assetDOList.stream().collect(Collectors.groupingBy(AssetDO::getFundId));
+        }
+        Map<String, List<NavDO>> fundIdNavMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
+        for (Map.Entry<String, List<NavDO>> fundIdNavEntry : fundIdNavMap.entrySet()) {
+            String fundId = fundIdNavEntry.getKey();
+            List<NavDO> fundNavDoList = fundIdNavEntry.getValue();
+            List<AssetDO> fundAssetDoList = fundIdAssetMap.get(fundId);
+            FundAndCompanyInfoDO fundInfoDO = fundIdCompanyNameMap.get(fundId);
+            List<FundNavDataDTO> fundNavDataDTOList = buildFundNavDataDTO(fundInfoDO, fundNavDoList, fundAssetDoList);
+            navDataDTOList.addAll(fundNavDataDTOList);
+        }
+        return navDataDTOList;
+    }
+
+    public List<FundNavDeletionDTO> getFundNavDeletion(Integer competitionId, String startDate, String endDate) {
+        List<FundNavDeletionDTO> navDeletionDTOList = CollUtil.newArrayList();
+        // 缺失类型-1对应全部,1-净值缺失,2-对应规模缺失,3-对应分红缺失,5-估值缺失
+        List<FundDeletionInfoDO> deletionInfoDOList = deletionInfoMapper.getFundNavDeletion(1, competitionId, startDate, endDate);
+        if (CollUtil.isEmpty(deletionInfoDOList)) {
+            return navDeletionDTOList;
+        }
+        List<String> fundIdList = deletionInfoDOList.stream().map(FundDeletionInfoDO::getFundId).distinct().toList();
+        List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId, fundIdList);
+        Map<String, FundAndCompanyInfoDO> fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
+        // 获取净值日期所在年和所在周
+        List<String> dateList = deletionInfoDOList.stream().map(FundDeletionInfoDO::getDeletionDate).distinct().toList();
+        Map<String, TradeDateDO> tradeDateDoMap = getYearAndWeekOfDate(dateList);
+        Map<String, List<FundDeletionInfoDO>> fundIdDeletionInfoMap = deletionInfoDOList.stream().collect(Collectors.groupingBy(FundDeletionInfoDO::getFundId));
+        for (Map.Entry<String, List<FundDeletionInfoDO>> fundIdDeletionInfoEntry : fundIdDeletionInfoMap.entrySet()) {
+            String fundId = fundIdDeletionInfoEntry.getKey();
+            List<FundDeletionInfoDO> fundDeletionInfoDOList = fundIdDeletionInfoEntry.getValue();
+            FundAndCompanyInfoDO fundAndCompanyInfoDO = fundIdCompanyNameMap.get(fundId);
+            List<FundNavDeletionDTO> fundNavDataDTOList = buildFundNavDeletionDTO(fundAndCompanyInfoDO, fundDeletionInfoDOList, tradeDateDoMap);
+            navDeletionDTOList.addAll(fundNavDataDTOList);
+        }
+
+        return navDeletionDTOList;
+    }
+
+    public List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId, String period) {
+        List<? extends CompetitionBaseResultDTO> dataList = CollUtil.newArrayList();
+        AbstractCompetitionResultService competitionResult = competitionFactory.getInstance(competitionId);
+        if (competitionResult == null) {
+            return dataList;
+        }
+
+        return competitionResult.getCompetitionResult(competitionId, period);
+    }
+
+    private List<FundNavDeletionDTO> buildFundNavDeletionDTO(FundAndCompanyInfoDO fundAndCompanyInfoDO, List<FundDeletionInfoDO> fundDeletionInfoDOList, Map<String, TradeDateDO> tradeDateDoMap) {
+        String fundName = fundAndCompanyInfoDO.getFundName();
+        String trustName = fundAndCompanyInfoDO.getCompanyName();
+        String trustRegisterNumber = fundAndCompanyInfoDO.getCompanyRegisterNumber();
+        String registerNumber = fundAndCompanyInfoDO.getRegisterNumber();
+        return fundDeletionInfoDOList.stream().map(e -> {
+            FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO();
+            fundNavDeletionDTO.setTrustName(trustName);
+            fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber);
+            fundNavDeletionDTO.setFundId(e.getFundId());
+            fundNavDeletionDTO.setFundName(fundName);
+            fundNavDeletionDTO.setRegisterNumber(registerNumber);
+            TradeDateDO tradeDateDO = tradeDateDoMap.get(e.getDeletionDate());
+            fundNavDeletionDTO.setYear(tradeDateDO != null ? tradeDateDO.getEndYear() : null);
+            fundNavDeletionDTO.setWeek(tradeDateDO != null ? String.valueOf(tradeDateDO.getWeekOfYear()) : null);
+            fundNavDeletionDTO.setDate(e.getDeletionDate());
+            return fundNavDeletionDTO;
+        }).sorted(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getDate)).toList();
+    }
+
+    private List<FundNavDataDTO> buildFundNavDataDTO(FundAndCompanyInfoDO fundInfoDO, List<NavDO> fundNavDoList, List<AssetDO> fundAssetDoList) {
+        String fundName = fundInfoDO.getFundName();
+        String registerNumber = fundInfoDO.getRegisterNumber();
+        String trustName = fundInfoDO.getCompanyName();
+        String trustRegisterNumber = fundInfoDO.getCompanyRegisterNumber();
+        Map<String, BigDecimal> priceDateAssetMap = MapUtil.newHashMap();
+        if (CollUtil.isNotEmpty(fundAssetDoList)) {
+            priceDateAssetMap = fundAssetDoList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getPriceDate(), DateConst.YYYY_MM_DD), AssetDO::getAssetNet));
+        }
+        Map<String, BigDecimal> finalPriceDateAssetMap = priceDateAssetMap;
+        return fundNavDoList.stream().map(e -> {
+            FundNavDataDTO fundNavDataDTO = new FundNavDataDTO();
+            fundNavDataDTO.setTrustName(trustName);
+            fundNavDataDTO.setTrustRegisterNumber(trustRegisterNumber);
+            fundNavDataDTO.setFundId(e.getFundId());
+            fundNavDataDTO.setFundName(fundName);
+            fundNavDataDTO.setRegisterNumber(registerNumber);
+            String priceDate = e.getPriceDate() != null ? DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD) : null;
+            fundNavDataDTO.setPriceDate(priceDate);
+            fundNavDataDTO.setNav(e.getNav() != null ? String.valueOf(e.getNav()) : null);
+            fundNavDataDTO.setCumulativeNavWithdrawal(e.getCumulativeNavWithdrawal() != null ? String.valueOf(e.getCumulativeNavWithdrawal()) : null);
+            BigDecimal asset = finalPriceDateAssetMap.get(priceDate) != null ? finalPriceDateAssetMap.get(priceDate).setScale(2, RoundingMode.HALF_UP) : null;
+            fundNavDataDTO.setAsset(asset != null ? String.valueOf(asset) : null);
+            return fundNavDataDTO;
+        }).sorted(Comparator.comparing(FundNavDataDTO::getFundName).thenComparing(FundNavDataDTO::getPriceDate)).toList();
+    }
 
-public interface FundNavService {
-
-    /**
-     * 获取基金净值数据
-     * @param competitionId 大赛id(区分不同大赛)
-     *
-     * @return 基金净值数据
-     */
-    List<FundNavDataDTO> getFungNavData(Integer competitionId);
-
-    /**
-     * 获取基金净值缺失明细数据
-     * @param competitionId 大赛id(区分不同大赛)
-     * @return 基金净值缺失明细数据
-     */
-    List<FundNavDeletionDTO> getFundNavDeletion(Integer competitionId);
-
-    /**
-     * 获取大赛榜单结果
-     *
-     * @param competitionId 大赛id(区分不同大赛)
-     * @return 大赛榜单结果
-     */
-    List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId);
+    private Map<String, TradeDateDO> getYearAndWeekOfDate(List<String> dateList) {
+        Map<String, TradeDateDO> tradeDateDoMap = MapUtil.newHashMap();
+        if (CollUtil.isEmpty(dateList)) {
+            return tradeDateDoMap;
+        }
+        List<TradeDateDO> tradeDateDOList = CollUtil.newArrayList();
+        List<List<String>> partition = ListUtil.partition(dateList, 500);
+        partition.forEach(e -> tradeDateDOList.addAll(tradeDateMapper.queryByDate(dateList)));
+        if (CollUtil.isNotEmpty(tradeDateDOList)) {
+            tradeDateDoMap = tradeDateDOList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getTradeDate(), DateConst.YYYY_MM_DD), v -> v));
+        }
+        return tradeDateDoMap;
+    }
 }

+ 0 - 227
service-manage/src/main/java/com/simuwang/manage/service/competition/FundNavServiceImpl.java

@@ -1,227 +0,0 @@
-package com.simuwang.manage.service.competition;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.map.MapUtil;
-import com.simuwang.base.common.conts.DateConst;
-import com.simuwang.base.mapper.*;
-import com.simuwang.base.pojo.dos.*;
-import com.simuwang.base.pojo.dto.FundNavDataDTO;
-import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
-import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
-import com.simuwang.base.pojo.dto.competition.ZhzqCompetitionResultDTO;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-@Service
-public class FundNavServiceImpl implements FundNavService {
-
-    private final NavMapper navMapper;
-    private final FundInfoMapper fundInfoMapper;
-    private final AssetMapper assetMapper;
-    private final DeletionInfoMapper deletionInfoMapper;
-    private final TradeDateMapper tradeDateMapper;
-    private final CompetitionFactory competitionFactory;
-    private final RcCompetitionTaskDateMapper competitionTaskDateMapper;
-    private final RcCompetitionCalcDateMapper competitionCalcDateMapper;
-
-    public FundNavServiceImpl(NavMapper navMapper, FundInfoMapper fundInfoMapper,
-                              AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper,
-                              TradeDateMapper tradeDateMapper, CompetitionFactory competitionFactory,
-                              RcCompetitionTaskDateMapper competitionTaskDateMapper, RcCompetitionCalcDateMapper competitionCalcDateMapper) {
-        this.navMapper = navMapper;
-        this.fundInfoMapper = fundInfoMapper;
-        this.assetMapper = assetMapper;
-        this.deletionInfoMapper = deletionInfoMapper;
-        this.tradeDateMapper = tradeDateMapper;
-        this.competitionFactory = competitionFactory;
-        this.competitionTaskDateMapper = competitionTaskDateMapper;
-        this.competitionCalcDateMapper = competitionCalcDateMapper;
-    }
-
-    @Override
-    public List<FundNavDataDTO> getFungNavData(Integer competitionId) {
-        List<FundNavDataDTO> navDataDTOList = CollUtil.newArrayList();
-        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
-        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByNavDetailDate(date, competitionId);
-        if (CollUtil.isEmpty(taskDateDOList)) {
-            return navDataDTOList;
-        }
-        List<String> periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().toList();
-        List<RcCompetitionCalcDateDO> calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId);
-        for (RcCompetitionCalcDateDO calcDateDO : calcDateDOList) {
-            String period = calcDateDO.getPriod();
-            String beginDate = calcDateDO.getBeginDate();
-            String endDate = calcDateDO.getEndDate();
-            List<NavDO> navDOList = navMapper.queryAllNav(beginDate, endDate);
-            if (CollUtil.isEmpty(navDOList)) {
-                continue;
-            }
-            // 过滤出周频的净值点
-            List<TradeDateDO> tradeDateDOList = tradeDateMapper.selectTradeDate(beginDate, endDate);
-            navDOList = filterWeekFrequencyNav(navDOList, tradeDateDOList);
-
-            List<String> fundIdList = navDOList.stream().map(NavDO::getFundId).distinct().toList();
-            List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(fundIdList);
-            Map<String, FundAndCompanyInfoDO> fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
-            List<AssetDO> assetDOList = assetMapper.queryAssetByFundId(fundIdList);
-            Map<String, List<AssetDO>> fundIdAssetMap = MapUtil.newHashMap();
-            if (CollUtil.isNotEmpty(assetDOList)) {
-                fundIdAssetMap = assetDOList.stream().collect(Collectors.groupingBy(AssetDO::getFundId));
-            }
-
-            Map<String, List<NavDO>> fundIdNavMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
-            for (Map.Entry<String, List<NavDO>> fundIdNavEntry : fundIdNavMap.entrySet()) {
-                String fundId = fundIdNavEntry.getKey();
-                List<NavDO> fundNavDoList = fundIdNavEntry.getValue();
-                List<AssetDO> fundAssetDoList = fundIdAssetMap.get(fundId);
-                FundAndCompanyInfoDO fundInfoDO = fundIdCompanyNameMap.get(fundId);
-                List<FundNavDataDTO> fundNavDataDTOList = buildFundNavDataDTO(fundInfoDO, fundNavDoList, fundAssetDoList);
-                fundNavDataDTOList.forEach(e -> e.setPriod(period));
-                navDataDTOList.addAll(fundNavDataDTOList);
-            }
-        }
-        return navDataDTOList;
-    }
-
-    @Override
-    public List<FundNavDeletionDTO> getFundNavDeletion(Integer competitionId) {
-        List<FundNavDeletionDTO> navDeletionDTOList = CollUtil.newArrayList();
-        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
-        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByNavDeletionDate(date, competitionId);
-        if (CollUtil.isEmpty(taskDateDOList)) {
-            return navDeletionDTOList;
-        }
-        List<String> periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().toList();
-        List<RcCompetitionCalcDateDO> calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId);
-        for (RcCompetitionCalcDateDO calcDateDO : calcDateDOList) {
-            String period = calcDateDO.getPriod();
-            String beginDate = calcDateDO.getBeginDate();
-            String endDate = calcDateDO.getEndDate();
-            // 缺失类型-1对应全部,1-净值缺失,2-对应规模缺失,3-对应分红缺失,5-估值缺失
-            List<FundDeletionInfoDO> deletionInfoDOList = deletionInfoMapper.getFundNavDeletion(1, beginDate, endDate);
-            if (CollUtil.isEmpty(deletionInfoDOList)) {
-                continue;
-            }
-            List<String> fundIdList = deletionInfoDOList.stream().map(FundDeletionInfoDO::getFundId).distinct().toList();
-            List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(fundIdList);
-            Map<String, FundAndCompanyInfoDO> fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
-            // 获取净值日期所在年和所在周
-            List<String> dateList = deletionInfoDOList.stream().map(FundDeletionInfoDO::getDeletionDate).distinct().toList();
-            Map<String, TradeDateDO> tradeDateDoMap = getYearAndWeekOfDate(dateList);
-            Map<String, List<FundDeletionInfoDO>> fundIdDeletionInfoMap = deletionInfoDOList.stream().collect(Collectors.groupingBy(FundDeletionInfoDO::getFundId));
-            for (Map.Entry<String, List<FundDeletionInfoDO>> fundIdDeletionInfoEntry : fundIdDeletionInfoMap.entrySet()) {
-                String fundId = fundIdDeletionInfoEntry.getKey();
-                List<FundDeletionInfoDO> fundDeletionInfoDOList = fundIdDeletionInfoEntry.getValue();
-                FundAndCompanyInfoDO fundAndCompanyInfoDO = fundIdCompanyNameMap.get(fundId);
-                List<FundNavDeletionDTO> fundNavDataDTOList = buildFundNavDeletionDTO(fundAndCompanyInfoDO, fundDeletionInfoDOList, tradeDateDoMap);
-                fundNavDataDTOList.forEach(e -> e.setPriod(period));
-                navDeletionDTOList.addAll(fundNavDataDTOList);
-            }
-        }
-        return navDeletionDTOList;
-    }
-
-    @Override
-    public List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId) {
-        List<ZhzqCompetitionResultDTO> dataList = CollUtil.newArrayList();
-        AbstractCompetitionResultService competitionResult = competitionFactory.getInstance(competitionId);
-        if (competitionResult == null) {
-            return dataList;
-        }
-        return competitionResult.getCompetitionResult();
-    }
-
-    private List<FundNavDeletionDTO> buildFundNavDeletionDTO(FundAndCompanyInfoDO fundAndCompanyInfoDO, List<FundDeletionInfoDO> fundDeletionInfoDOList, Map<String, TradeDateDO> tradeDateDoMap) {
-        String fundName = fundAndCompanyInfoDO.getFundName();
-        String trustName = fundAndCompanyInfoDO.getCompanyName();
-        String trustRegisterNumber = fundAndCompanyInfoDO.getCompanyRegisterNumber();
-        String registerNumber = fundAndCompanyInfoDO.getRegisterNumber();
-        return fundDeletionInfoDOList.stream().map(e -> {
-            FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO();
-            fundNavDeletionDTO.setTrustName(trustName);
-            fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber);
-            fundNavDeletionDTO.setFundId(e.getFundId());
-            fundNavDeletionDTO.setFundName(fundName);
-            fundNavDeletionDTO.setRegisterNumber(registerNumber);
-            TradeDateDO tradeDateDO = tradeDateDoMap.get(e.getDeletionDate());
-            fundNavDeletionDTO.setYear(tradeDateDO != null ? tradeDateDO.getEndYear() : null);
-            fundNavDeletionDTO.setWeek(tradeDateDO != null ? String.valueOf(tradeDateDO.getWeekOfYear()) : null);
-            fundNavDeletionDTO.setDate(e.getDeletionDate());
-            return fundNavDeletionDTO;
-        }).sorted(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getDate)).toList();
-    }
-
-    private List<FundNavDataDTO> buildFundNavDataDTO(FundAndCompanyInfoDO fundInfoDO, List<NavDO> fundNavDoList, List<AssetDO> fundAssetDoList) {
-        String fundName = fundInfoDO.getFundName();
-        String registerNumber = fundInfoDO.getRegisterNumber();
-        String trustName = fundInfoDO.getCompanyName();
-        String trustRegisterNumber = fundInfoDO.getCompanyRegisterNumber();
-        Map<String, BigDecimal> priceDateAssetMap = MapUtil.newHashMap();
-        if (CollUtil.isNotEmpty(fundAssetDoList)) {
-            priceDateAssetMap = fundAssetDoList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getPriceDate(), DateConst.YYYY_MM_DD), AssetDO::getAssetNet));
-        }
-        Map<String, BigDecimal> finalPriceDateAssetMap = priceDateAssetMap;
-        return fundNavDoList.stream().map(e -> {
-            FundNavDataDTO fundNavDataDTO = new FundNavDataDTO();
-            fundNavDataDTO.setTrustName(trustName);
-            fundNavDataDTO.setTrustRegisterNumber(trustRegisterNumber);
-            fundNavDataDTO.setFundId(e.getFundId());
-            fundNavDataDTO.setFundName(fundName);
-            fundNavDataDTO.setRegisterNumber(registerNumber);
-            String priceDate = e.getPriceDate() != null ? DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD) : null;
-            fundNavDataDTO.setPriceDate(priceDate);
-            fundNavDataDTO.setNav(e.getNav() != null ? String.valueOf(e.getNav()) : null);
-            fundNavDataDTO.setCumulativeNavWithdrawal(e.getCumulativeNavWithdrawal() != null ? String.valueOf(e.getCumulativeNavWithdrawal()) : null);
-            BigDecimal asset = finalPriceDateAssetMap.get(priceDate) != null ? finalPriceDateAssetMap.get(priceDate).setScale(2, RoundingMode.HALF_UP) : null;
-            fundNavDataDTO.setAsset(asset != null ? String.valueOf(asset) : null);
-            return fundNavDataDTO;
-        }).sorted(Comparator.comparing(FundNavDataDTO::getFundName).thenComparing(FundNavDataDTO::getPriceDate)).toList();
-    }
-
-    private Map<String, TradeDateDO> getYearAndWeekOfDate(List<String> dateList) {
-        Map<String, TradeDateDO> tradeDateDoMap = MapUtil.newHashMap();
-        if (CollUtil.isEmpty(dateList)) {
-            return tradeDateDoMap;
-        }
-        List<TradeDateDO> tradeDateDOList = CollUtil.newArrayList();
-        List<List<String>> partition = ListUtil.partition(dateList, 500);
-        partition.forEach(e -> tradeDateDOList.addAll(tradeDateMapper.queryByDate(dateList)));
-        if (CollUtil.isNotEmpty(tradeDateDOList)) {
-            tradeDateDoMap = tradeDateDOList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getTradeDate(), DateConst.YYYY_MM_DD), v -> v));
-        }
-        return tradeDateDoMap;
-    }
-
-    private List<NavDO> filterWeekFrequencyNav(List<NavDO> navDOList, List<TradeDateDO> tradeDateDOList) {
-        List<NavDO> dataList = CollUtil.newArrayList();
-        if(CollUtil.isEmpty(navDOList)){
-          return dataList;
-        }
-        Map<Integer, List<TradeDateDO>> yearWeekTradeDateMap = tradeDateDOList.stream().collect(Collectors.groupingBy(TradeDateDO::getYearWeek));
-
-        Map<String, List<NavDO>> fundIdNavDoMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
-        for (Map.Entry<String, List<NavDO>> fundIdNavDoEntry : fundIdNavDoMap.entrySet()) {
-            List<NavDO> navDoList = fundIdNavDoEntry.getValue();
-            for (Map.Entry<Integer, List<TradeDateDO>> yearWeekTradeDateEntry : yearWeekTradeDateMap.entrySet()) {
-                List<Date> tradeDateList = yearWeekTradeDateEntry.getValue().stream().map(TradeDateDO::getTradeDate).toList();
-                List<NavDO> collect = navDoList.stream().filter(e -> tradeDateList.contains(e.getPriceDate())).toList();
-                if(CollUtil.isEmpty(collect)){
-                    continue;
-                }
-                NavDO navDO = collect.stream().max(Comparator.comparing(NavDO::getPriceDate)).orElse(null);
-                dataList.add(navDO);
-            }
-        }
-        return dataList;
-    }
-
-}

+ 30 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/FundStrategyService.java

@@ -0,0 +1,30 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import com.simuwang.base.mapper.RcCompetitionStrategyMapper;
+import com.simuwang.base.pojo.dos.RcCompetitionStrategyDO;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class FundStrategyService {
+
+    private final RcCompetitionStrategyMapper competitionStrategyMapper;
+
+    public FundStrategyService(RcCompetitionStrategyMapper competitionStrategyMapper) {
+        this.competitionStrategyMapper = competitionStrategyMapper;
+    }
+
+    public Map<Integer, String> getStrategyName(Integer competitionId) {
+        List<RcCompetitionStrategyDO> strategyDOList = competitionStrategyMapper.queryByCompetitionId(competitionId);
+        if (CollUtil.isEmpty(strategyDOList)) {
+            return MapUtil.newHashMap();
+        }
+        return strategyDOList.stream()
+                .collect(Collectors.toMap(RcCompetitionStrategyDO::getStrategyId, RcCompetitionStrategyDO::getStrategyName));
+    }
+}

+ 40 - 46
service-manage/src/main/java/com/simuwang/manage/service/competition/FzzqCompetitionResultServiceService.java

@@ -1,10 +1,11 @@
 package com.simuwang.manage.service.competition;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.map.MapUtil;
-import com.simuwang.base.config.CompetitionConfig;
-import com.simuwang.base.mapper.RzFzzq2ResultMapper;
-import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
+import cn.hutool.core.date.DateUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.mapper.RcCompetitionResultMapper;
+import com.simuwang.base.pojo.dos.RcCompetitionResultDO;
 import com.simuwang.base.pojo.dto.competition.FzzqCompetitionResultDTO;
 import org.springframework.stereotype.Service;
 
@@ -16,22 +17,13 @@ import java.util.stream.Collectors;
 @Service
 public class FzzqCompetitionResultServiceService extends AbstractCompetitionResultService {
 
-    private static final Map<Integer, String> STRATEGY_ID_NAME_MAP = MapUtil.newHashMap();
+    private final RcCompetitionResultMapper rcCompetitionResultMapper;
+    private final FundStrategyService fundStrategyService;
 
-    static {
-        STRATEGY_ID_NAME_MAP.put(1, "主观多头策略");
-        STRATEGY_ID_NAME_MAP.put(2, "量化多头策略");
-        STRATEGY_ID_NAME_MAP.put(3, "相对价值策略");
-        STRATEGY_ID_NAME_MAP.put(4, "CTA策略");
-        STRATEGY_ID_NAME_MAP.put(5, "复合策略");
-    }
-
-    private final CompetitionConfig competitionConfig;
-    private final RzFzzq2ResultMapper fzzq2ResultMapper;
+    public FzzqCompetitionResultServiceService(RcCompetitionResultMapper rcCompetitionResultMapper, FundStrategyService fundStrategyService) {
+        this.rcCompetitionResultMapper = rcCompetitionResultMapper;
 
-    public FzzqCompetitionResultServiceService(CompetitionConfig competitionConfig, RzFzzq2ResultMapper fzzq2ResultMapper) {
-        this.competitionConfig = competitionConfig;
-        this.fzzq2ResultMapper = fzzq2ResultMapper;
+        this.fundStrategyService = fundStrategyService;
     }
 
     @Override
@@ -40,38 +32,40 @@ public class FzzqCompetitionResultServiceService extends AbstractCompetitionResu
     }
 
     @Override
-    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult() {
-        Integer competitionId = competitionConfig.getId();
-        List<FzzqCompetitionResultDTO> competitionResultDTOList = fzzq2ResultMapper.getResult();
-        if (CollUtil.isEmpty(competitionResultDTOList)) {
-            return CollUtil.newArrayList();
+    protected List<FzzqCompetitionResultDTO> getCompetitionResult(Integer competitionId, String period) {
+        List<FzzqCompetitionResultDTO> competitionResultDTOList = CollUtil.newArrayList();
+        List<RcCompetitionResultDO> resultDOList = rcCompetitionResultMapper.queryCompetitionResult(competitionId, period);
+        if (CollUtil.isEmpty(resultDOList)) {
+            return competitionResultDTOList;
         }
-        // 策略名称和排名
-        Map<Integer, List<FzzqCompetitionResultDTO>> strategyResultDTOList = competitionResultDTOList.stream().collect(Collectors.groupingBy(FzzqCompetitionResultDTO::getStrategy));
-        for (Map.Entry<Integer, List<FzzqCompetitionResultDTO>> resultEntry : strategyResultDTOList.entrySet()) {
-            Integer strategy = resultEntry.getKey();
-            String strategyName = STRATEGY_ID_NAME_MAP.get(strategy);
-            List<FzzqCompetitionResultDTO> resultDTOList = resultEntry.getValue();
+        // 策略名称
+        Map<Integer, String> strategyNameMap = fundStrategyService.getStrategyName(competitionId);
+        competitionResultDTOList = resultDOList.stream().map(e -> convertToResultDTO(e, strategyNameMap.get(e.getStrategy()))).toList();
 
-            // 按照分数降序排序
-            resultDTOList.sort(Comparator.comparing(FzzqCompetitionResultDTO::getScore, Comparator.nullsFirst(Comparator.naturalOrder())).reversed());
-            // 计算排名并设置
-            int rank = 1;
-            for (int i = 0; i < resultDTOList.size(); i++) {
-                FzzqCompetitionResultDTO dto = resultDTOList.get(i);
-                dto.setStrategyName(strategyName);
-                if (dto.getScore() != null) {
-                    dto.setRank(rank);
-                    rank = i + 1;
-                } else {
-                    // 没有分数的基金排名为:999999
-                    dto.setRank(999999);
-                }
-            }
-        }
         // 策略分组和排名降序输出
         return competitionResultDTOList.stream()
-                .sorted(Comparator.comparing(FzzqCompetitionResultDTO::getStrategyName).reversed().thenComparing(FzzqCompetitionResultDTO::getRank))
+                .sorted(Comparator.comparing(FzzqCompetitionResultDTO::getStrategyName).reversed()
+                        .thenComparing(FzzqCompetitionResultDTO::getRank))
                 .collect(Collectors.toList());
     }
+
+    private FzzqCompetitionResultDTO convertToResultDTO(RcCompetitionResultDO resultDO, String strategyName) {
+        FzzqCompetitionResultDTO resultDTO = BeanUtil.copyProperties(resultDO, FzzqCompetitionResultDTO.class);
+        resultDTO.setStrategyName(strategyName);
+        resultDTO.setRegisterNumber(resultDO.getFundRegisterNumber());
+        resultDTO.setStartPriceDate(DateUtil.format(resultDO.getPrePriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setStartCumulativeNavWithdrawal(resultDO.getPreCumulativeNavWithdrawal() != null ? String.valueOf(resultDO.getPreCumulativeNavWithdrawal()) : null);
+        resultDTO.setEndPriceDate(DateUtil.format(resultDO.getPriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setEndCumulativeNavWithdrawal(resultDO.getCumulativeNavWithdrawal() != null ? String.valueOf(resultDO.getCumulativeNavWithdrawal()) : null);
+        resultDTO.setMaxdown(resultDO.getMaxdrawdown());
+        resultDTO.setSharpeRatio(resultDO.getSharperatio());
+        resultDTO.setCalmarRatio(resultDO.getCalmarratio());
+        resultDTO.setSortinoRatio(resultDO.getSortinoratio());
+        resultDTO.setProductScale(resultDO.getProductScale());
+        if (resultDO.getRank() == null) {
+            resultDTO.setRank(999999);
+        }
+        return resultDTO;
+    }
+
 }

+ 84 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/XnzqCompetitionResultServiceService.java

@@ -0,0 +1,84 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.mapper.RcCompetitionResultMapper;
+import com.simuwang.base.pojo.dos.RcCompetitionResultDO;
+import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
+import com.simuwang.base.pojo.dto.competition.XnzqCompetitionResultDTO;
+import org.springframework.stereotype.Service;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class XnzqCompetitionResultServiceService extends AbstractCompetitionResultService {
+
+    private static final String FIRST_GROUP = "轻量组";
+    private static final String SECOND_GROUP = "重量组";
+    private static final List<Integer> STRATEGY_LIST = ListUtil.toList(1, 2, 3, 4, 5, 6);
+    private final RcCompetitionResultMapper rcCompetitionResultMapper;
+    private final FundStrategyService fundStrategyService;
+
+    public XnzqCompetitionResultServiceService(RcCompetitionResultMapper rcCompetitionResultMapper, FundStrategyService fundStrategyService) {
+        this.rcCompetitionResultMapper = rcCompetitionResultMapper;
+        this.fundStrategyService = fundStrategyService;
+    }
+
+    @Override
+    public boolean isSupport(Integer competitionId) {
+        return competitionId != null && competitionId == 51;
+    }
+
+    @Override
+    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId, String period) {
+        List<XnzqCompetitionResultDTO> competitionResultDTOList = CollUtil.newArrayList();
+        List<RcCompetitionResultDO> resultDOList = rcCompetitionResultMapper.queryCompetitionResult(competitionId, period);
+        if (CollUtil.isEmpty(resultDOList)) {
+            return competitionResultDTOList;
+        }
+
+        // 策略名称
+        Map<Integer, String> strategyNameMap = fundStrategyService.getStrategyName(competitionId);
+        competitionResultDTOList = resultDOList.stream().map(e -> convertToResultDTO(e, strategyNameMap.get(e.getStrategy()))).toList();
+
+        // 策略分组和排名降序输出
+        return competitionResultDTOList.stream()
+                .sorted(Comparator.comparing(XnzqCompetitionResultDTO::getStrategyName).reversed().thenComparing(XnzqCompetitionResultDTO::getRank))
+                .collect(Collectors.toList());
+    }
+
+    private XnzqCompetitionResultDTO convertToResultDTO(RcCompetitionResultDO resultDO, String strategyName) {
+        XnzqCompetitionResultDTO resultDTO = BeanUtil.copyProperties(resultDO, XnzqCompetitionResultDTO.class);
+        resultDTO.setStrategyName(strategyName);
+        resultDTO.setRegisterNumber(resultDO.getFundRegisterNumber());
+        resultDTO.setStartPriceDate(DateUtil.format(resultDO.getPrePriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setStartCumulativeNavWithdrawal(resultDO.getPreCumulativeNavWithdrawal());
+        resultDTO.setEndPriceDate(DateUtil.format(resultDO.getPriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setEndCumulativeNavWithdrawal(resultDO.getCumulativeNavWithdrawal());
+        resultDTO.setMaxdown(resultDO.getMaxdrawdown());
+        resultDTO.setSharpeRatio(resultDO.getSharperatio());
+        resultDTO.setCalmarRatio(resultDO.getCalmarratio());
+        resultDTO.setProductScale(resultDO.getProductScale());
+        resultDTO.setSortinoRatio(resultDO.getSortinoratio());
+        resultDTO.setAssetGroupName(getAssetGroupName(resultDO.getCompanyScale(), resultDO.getStrategy()));
+        if (resultDO.getRank() == null) {
+            resultDTO.setRank(999999);
+        }
+        return resultDTO;
+    }
+
+    private String getAssetGroupName(Integer companyAssetSize, Integer strategyId) {
+        // 1:0-5亿 2:5-10亿 3:10-20亿 4:20-50亿 5:50-100亿 6:100亿以上
+        if (STRATEGY_LIST.contains(strategyId)) {
+            return companyAssetSize != null && companyAssetSize >= 4 ? FIRST_GROUP : SECOND_GROUP;
+        } else {
+            return companyAssetSize != null && companyAssetSize >= 3 ? FIRST_GROUP : SECOND_GROUP;
+        }
+    }
+}

+ 42 - 70
service-manage/src/main/java/com/simuwang/manage/service/competition/ZhzqCompetitionResultServiceService.java

@@ -1,12 +1,12 @@
 package com.simuwang.manage.service.competition;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import com.simuwang.base.mapper.CompanyInformationMapper;
-import com.simuwang.base.mapper.RzZhzq2ResultMapper;
-import com.simuwang.base.pojo.dos.CompanyInformationDO;
+import cn.hutool.core.date.DateUtil;
+import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.mapper.RcCompetitionResultMapper;
+import com.simuwang.base.pojo.dos.RcCompetitionResultDO;
 import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
 import com.simuwang.base.pojo.dto.competition.ZhzqCompetitionResultDTO;
 import org.springframework.stereotype.Service;
@@ -19,29 +19,16 @@ import java.util.stream.Collectors;
 @Service
 public class ZhzqCompetitionResultServiceService extends AbstractCompetitionResultService {
 
-    private static final String GROWTH_PARTNERSHIP_GROUP = "成长伙伴组";
+    private static final String FIRST_GROUP = "成长伙伴组";
+    private static final String SECOND_GROUP = "战略伙伴组";
+    private static final List<Integer> STRATEGY_LIST = ListUtil.toList(1, 2, 3, 4);
 
-    private static final String STRATEGIC_PARTNERSHIP_GROUP = "战略伙伴组";
+    private final RcCompetitionResultMapper rcCompetitionResultMapper;
+    private final FundStrategyService fundStrategyService;
 
-    private static final List<Integer> GROWTH_PARTNERSHIP_STRATEGY_LIST = ListUtil.toList(1, 2, 3, 4);
-
-    private static final Map<Integer, String> STRATEGY_ID_NAME_MAP = MapUtil.newHashMap();
-
-    static {
-        STRATEGY_ID_NAME_MAP.put(1, "主观多头策略");
-        STRATEGY_ID_NAME_MAP.put(2, "股票量化策略");
-        STRATEGY_ID_NAME_MAP.put(3, "相对价值策略");
-        STRATEGY_ID_NAME_MAP.put(4, "CTA策略");
-        STRATEGY_ID_NAME_MAP.put(5, "复合策略");
-    }
-
-    private final RzZhzq2ResultMapper zhzqResultMapper;
-
-    private final CompanyInformationMapper companyInformationMapper;
-
-    public ZhzqCompetitionResultServiceService(RzZhzq2ResultMapper zhzqResultMapper, CompanyInformationMapper companyInformationMapper) {
-        this.zhzqResultMapper = zhzqResultMapper;
-        this.companyInformationMapper = companyInformationMapper;
+    public ZhzqCompetitionResultServiceService(RcCompetitionResultMapper rcCompetitionResultMapper, FundStrategyService fundStrategyService) {
+        this.rcCompetitionResultMapper = rcCompetitionResultMapper;
+        this.fundStrategyService = fundStrategyService;
     }
 
     @Override
@@ -50,37 +37,16 @@ public class ZhzqCompetitionResultServiceService extends AbstractCompetitionResu
     }
 
     @Override
-    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult() {
-        List<ZhzqCompetitionResultDTO> competitionResultDTOList = zhzqResultMapper.getResult();
-        if (CollUtil.isEmpty(competitionResultDTOList)) {
-            return CollUtil.newArrayList();
+    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId, String period) {
+        List<ZhzqCompetitionResultDTO> competitionResultDTOList = CollUtil.newArrayList();
+        List<RcCompetitionResultDO> resultDOList = rcCompetitionResultMapper.queryCompetitionResult(competitionId, period);
+        if (CollUtil.isEmpty(resultDOList)) {
+            return competitionResultDTOList;
         }
-        // 策略名称和排名
-        Map<Integer, List<ZhzqCompetitionResultDTO>> strategyResultDTOList = competitionResultDTOList.stream().collect(Collectors.groupingBy(ZhzqCompetitionResultDTO::getStrategy));
-        for (Map.Entry<Integer, List<ZhzqCompetitionResultDTO>> resultEntry : strategyResultDTOList.entrySet()) {
-            Integer strategy = resultEntry.getKey();
-            String strategyName = STRATEGY_ID_NAME_MAP.get(strategy);
-            List<ZhzqCompetitionResultDTO> resultDTOList = resultEntry.getValue();
 
-            // 按照分数降序排序
-            resultDTOList.sort(Comparator.comparing(ZhzqCompetitionResultDTO::getScore, Comparator.nullsFirst(Comparator.naturalOrder())).reversed());
-            // 计算排名并设置
-            int rank = 1;
-            for (int i = 0; i < resultDTOList.size(); i++) {
-                ZhzqCompetitionResultDTO dto = resultDTOList.get(i);
-                dto.setStrategyName(strategyName);
-                if (dto.getScore() != null) {
-                    dto.setRank(rank);
-                    rank = i + 1;
-                } else {
-                    // 没有分数的基金排名为:999999
-                    dto.setRank(999999);
-                }
-            }
-        }
-
-        // 设置规模分组
-        settingAssetGroupName(competitionResultDTOList);
+        // 策略名称
+        Map<Integer, String> strategyNameMap = fundStrategyService.getStrategyName(competitionId);
+        competitionResultDTOList = resultDOList.stream().map(e -> convertToResultDTO(e, strategyNameMap.get(e.getStrategy()))).toList();
 
         // 策略分组和排名降序输出
         return competitionResultDTOList.stream()
@@ -88,27 +54,33 @@ public class ZhzqCompetitionResultServiceService extends AbstractCompetitionResu
                 .collect(Collectors.toList());
     }
 
-    private void settingAssetGroupName(List<ZhzqCompetitionResultDTO> competitionResultDTOList) {
-        if (CollUtil.isEmpty(competitionResultDTOList)) {
-            return;
-        }
-        List<String> companyIdList = competitionResultDTOList.stream().map(ZhzqCompetitionResultDTO::getCompanyId).filter(StrUtil::isNotBlank).distinct().toList();
-        if (CollUtil.isEmpty(companyIdList)) {
-            return;
+    private ZhzqCompetitionResultDTO convertToResultDTO(RcCompetitionResultDO resultDO, String strategyName) {
+        ZhzqCompetitionResultDTO resultDTO = BeanUtil.copyProperties(resultDO, ZhzqCompetitionResultDTO.class);
+        resultDTO.setStrategyName(strategyName);
+        resultDTO.setRegisterNumber(resultDO.getFundRegisterNumber());
+        resultDTO.setStartPriceDate(DateUtil.format(resultDO.getPrePriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setStartCumulativeNavWithdrawal(resultDO.getPreCumulativeNavWithdrawal() != null ? String.valueOf(resultDO.getPreCumulativeNavWithdrawal()) : null);
+        resultDTO.setEndPriceDate(DateUtil.format(resultDO.getPriceDate(), DateConst.YYYY_MM_DD));
+        resultDTO.setEndCumulativeNavWithdrawal(resultDO.getCumulativeNavWithdrawal() != null ? String.valueOf(resultDO.getCumulativeNavWithdrawal()) : null);
+        resultDTO.setMaxdown(resultDO.getMaxdrawdown());
+        resultDTO.setSharpeRatio(resultDO.getSharperatio());
+        resultDTO.setCalmarRatio(resultDO.getCalmarratio());
+        resultDTO.setExcessCalmarRatio(resultDO.getExcessCalmarratio());
+        resultDTO.setProductScale(resultDO.getProductScale());
+        resultDTO.setAssetGroupName(getAssetGroupName(resultDO.getCompanyScale(), resultDO.getStrategy()));
+        if (resultDO.getRank() == null) {
+            resultDTO.setRank(999999);
         }
-        // 获取公司规模 -> 1:0-5亿 2:5-10亿 3:10-20亿 4:20-50亿 5:50-100亿 6:100亿以上
-        List<CompanyInformationDO> companyInfoDOList = companyInformationMapper.quertAssetByCompanyId(companyIdList);
-        Map<String, Integer> companyIdAssetMap = companyInfoDOList.stream().collect(Collectors.toMap(CompanyInformationDO::getCompanyId, CompanyInformationDO::getCompanyAssetSize));
-
-        competitionResultDTOList.forEach(e -> e.setAssetGroupName(getAssetGroupName(companyIdAssetMap.get(e.getCompanyId()), e.getStrategy())));
+        return resultDTO;
     }
 
+
     private String getAssetGroupName(Integer companyAssetSize, Integer strategyId) {
         // 1:0-5亿 2:5-10亿 3:10-20亿 4:20-50亿 5:50-100亿 6:100亿以上
-        if (GROWTH_PARTNERSHIP_STRATEGY_LIST.contains(strategyId)) {
-            return companyAssetSize != null && companyAssetSize >= 4 ? STRATEGIC_PARTNERSHIP_GROUP : GROWTH_PARTNERSHIP_GROUP;
+        if (STRATEGY_LIST.contains(strategyId)) {
+            return companyAssetSize != null && companyAssetSize >= 4 ? SECOND_GROUP : FIRST_GROUP;
         } else {
-            return companyAssetSize != null && companyAssetSize >= 3 ? STRATEGIC_PARTNERSHIP_GROUP : GROWTH_PARTNERSHIP_GROUP;
+            return companyAssetSize != null && companyAssetSize >= 3 ? SECOND_GROUP : FIRST_GROUP;
         }
     }
 }

+ 93 - 44
service-manage/src/main/java/com/simuwang/manage/task/CompetitionTask.java

@@ -3,10 +3,15 @@ package com.simuwang.manage.task;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.excel.EasyExcel;
 import com.simuwang.base.common.conts.DateConst;
 import com.simuwang.base.common.util.EmailUtil;
 import com.simuwang.base.config.CompetitionConfig;
+import com.simuwang.base.mapper.RcCompetitionCalcDateMapper;
+import com.simuwang.base.mapper.RcCompetitionTaskDateMapper;
+import com.simuwang.base.pojo.dos.RcCompetitionCalcDateDO;
+import com.simuwang.base.pojo.dos.RcCompetitionTaskDateDO;
 import com.simuwang.base.pojo.dto.FundNavDataDTO;
 import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
 import com.simuwang.base.pojo.dto.MailboxInfoDTO;
@@ -31,40 +36,56 @@ public class CompetitionTask {
 
     private final FundNavService fundNavService;
     private final CompetitionConfig competitionConfig;
-
     private final EmailSystemConfigService emailSystemConfigService;
+    private final RcCompetitionTaskDateMapper competitionTaskDateMapper;
+    private final RcCompetitionCalcDateMapper competitionCalcDateMapper;
 
-    public CompetitionTask(FundNavService fundNavService, CompetitionConfig competitionConfig, EmailSystemConfigService emailSystemConfigService) {
+    public CompetitionTask(FundNavService fundNavService, CompetitionConfig competitionConfig,
+                           EmailSystemConfigService emailSystemConfigService, RcCompetitionTaskDateMapper competitionTaskDateMapper,
+                           RcCompetitionCalcDateMapper competitionCalcDateMapper) {
         this.fundNavService = fundNavService;
         this.competitionConfig = competitionConfig;
         this.emailSystemConfigService = emailSystemConfigService;
+        this.competitionTaskDateMapper = competitionTaskDateMapper;
+        this.competitionCalcDateMapper = competitionCalcDateMapper;
     }
 
     /**
      * 输出基金净值采集结果明细任务
      * 每天10:00,15:00执行任务
      */
-    // @Scheduled(cron = "0/10 * * * * ?")
+    @Scheduled(cron = "0 0 10,15 * * ?")
     public void fundNavDataTask() {
-        List<FundNavDataDTO> navDataDTOList = fundNavService.getFungNavData(competitionConfig.getId());
-        if (CollUtil.isEmpty(navDataDTOList)) {
+        Integer competitionId = competitionConfig.getId();
+        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
+        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByNavDetailDate(date, competitionId);
+        if (CollUtil.isEmpty(taskDateDOList)) {
             return;
         }
-        Map<String, List<FundNavDataDTO>> periodNavDataMap = navDataDTOList.stream().collect(Collectors.groupingBy(FundNavDataDTO::getPriod));
-        for (Map.Entry<String, List<FundNavDataDTO>> periodNavDataEntry : periodNavDataMap.entrySet()) {
-            String period = periodNavDataEntry.getKey();
-            List<FundNavDataDTO> fundNavDataDTOList = periodNavDataEntry.getValue();
-            String filePath = competitionConfig.getDirectory() + period + "_榜单_基金净值采集结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx";
+        List<String> periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().toList();
+        List<RcCompetitionCalcDateDO> calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId);
+        Map<String, RcCompetitionCalcDateDO> periodCalcDataDoMap = calcDateDOList.stream().collect(Collectors.toMap(RcCompetitionCalcDateDO::getPriod, v -> v));
+
+        for (RcCompetitionTaskDateDO taskDateDO : taskDateDOList) {
+            String period = taskDateDO.getPriod();
+            RcCompetitionCalcDateDO calcDateDO = periodCalcDataDoMap.get(period);
+            List<FundNavDataDTO> navDataDTOList = fundNavService.getFungNavData(competitionId, calcDateDO.getBeginDate(), calcDateDO.getEndDate());
+            if (CollUtil.isEmpty(navDataDTOList)) {
+                return;
+            }
+            String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_" + period + "_榜单_基金净值采集结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx";
             EasyExcel.write(filePath, FundNavDataDTO.class)
                     .sheet("基金净值采集结果明细")
-                    .doWrite(fundNavDataDTOList);
+                    .doWrite(navDataDTOList);
             log.info("基金净值采集结果明细表格已输出 -> 文件:{}", filePath);
 
-            Integer method = competitionConfig.getMethod();
             // 通过邮件发送"基金净值采集结果明细表格"
-            if (method == 2) {
+            if (competitionConfig.getMethod() == 2) {
                 MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo();
                 String receivingMailbox = emailSystemConfigService.getRecipientEmail();
+                if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) {
+                    continue;
+                }
                 try {
                     EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), "基金净值采集结果明细", "", period + "基金净值采集结果明细");
                     log.info("基金净值采集结果明细表 -> 邮件已发送");
@@ -79,26 +100,37 @@ public class CompetitionTask {
      * 输出基金净值缺失明细任务
      * 每天10:00,15:00执行任务
      */
-    // @Scheduled(cron = "0 0 10,15 * * ?")
+    @Scheduled(cron = "0 0 10,15 * * ?")
     public void navDeletionTask() {
-        List<FundNavDeletionDTO> navDeletionDTOList = fundNavService.getFundNavDeletion(competitionConfig.getId());
-        if (CollUtil.isEmpty(navDeletionDTOList)) {
+        Integer competitionId = competitionConfig.getId();
+        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
+        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByNavDetailDate(date, competitionId);
+        if (CollUtil.isEmpty(taskDateDOList)) {
             return;
         }
-        Map<String, List<FundNavDeletionDTO>> periodNavDeletionMap = navDeletionDTOList.stream().collect(Collectors.groupingBy(FundNavDeletionDTO::getPriod));
-        for (Map.Entry<String, List<FundNavDeletionDTO>> periodNavDeletionEntry : periodNavDeletionMap.entrySet()) {
-            String period = periodNavDeletionEntry.getKey();
-            List<FundNavDeletionDTO> fundNavDeletionDTOList = periodNavDeletionEntry.getValue();
+        List<String> periodList = taskDateDOList.stream().map(RcCompetitionTaskDateDO::getPriod).distinct().toList();
+        List<RcCompetitionCalcDateDO> calcDateDOList = competitionCalcDateMapper.queryByPriod(periodList, competitionId);
+        Map<String, RcCompetitionCalcDateDO> periodCalcDataDoMap = calcDateDOList.stream().collect(Collectors.toMap(RcCompetitionCalcDateDO::getPriod, v -> v));
+        for (RcCompetitionTaskDateDO taskDateDO : taskDateDOList) {
+            String period = taskDateDO.getPriod();
+            RcCompetitionCalcDateDO calcDateDO = periodCalcDataDoMap.get(period);
+            List<FundNavDeletionDTO> navDeletionDTOList = fundNavService.getFundNavDeletion(competitionId, calcDateDO.getBeginDate(), calcDateDO.getEndDate());
+            if (CollUtil.isEmpty(navDeletionDTOList)) {
+                return;
+            }
             String filePath = competitionConfig.getDirectory() + period + "_榜单_基金净值缺失明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx";
             EasyExcel.write(filePath, FundNavDeletionDTO.class)
                     .sheet("基金净值缺失明细")
-                    .doWrite(fundNavDeletionDTOList);
+                    .doWrite(navDeletionDTOList);
             // 通过邮件发送"基金净值采集结果明细表格"
-            if (competitionConfig.getMethod() == 2) {
+            if (competitionConfig.getMethod() == 1) {
                 MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo();
-                String recipientEmail = emailSystemConfigService.getRecipientEmail();
+                String receivingMailbox = emailSystemConfigService.getRecipientEmail();
+                if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) {
+                    continue;
+                }
                 try {
-                    EmailUtil.senEmail(mailboxInfoDTO, recipientEmail, new File(filePath), "基金净值缺失明细", "", period + "_榜单_基金净值缺失明细");
+                    EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), "基金净值缺失明细", "", period + "_榜单_基金净值缺失明细");
                     log.info("基金净值缺失明细表 -> 邮件已发送");
                 } catch (Exception e) {
                     log.error("邮件发送基金净值缺失明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
@@ -107,31 +139,48 @@ public class CompetitionTask {
         }
     }
 
-    // @Scheduled(cron = "0 0 10,15 * * ?")
+    /**
+     * 输出基金净值衍生指标及排名结果明细任务
+     * 每天10:00,15:00执行任务
+     */
+    @Scheduled(cron = "0 0 10,15 * * ?")
     public void competitionResultTask() {
-        List<? extends CompetitionBaseResultDTO> competitionResultDTOList = fundNavService.getCompetitionResult(competitionConfig.getId());
-        if (CollUtil.isEmpty(competitionResultDTOList)) {
+        Integer competitionId = competitionConfig.getId();
+        String date = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
+        List<RcCompetitionTaskDateDO> taskDateDOList = competitionTaskDateMapper.queryByPriodDate(date, competitionId);
+        if (CollUtil.isEmpty(taskDateDOList)) {
             return;
         }
-        Class<? extends CompetitionBaseResultDTO> aClass = competitionResultDTOList.get(0).getClass();
-        String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_基金净值衍生指标及排名结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx";
-        EasyExcel.write(filePath, aClass)
-                .sheet("基金净值衍生指标及排名结果明细")
-                .doWrite(competitionResultDTOList);
-        log.info("基金净值衍生指标及排名结果明细表已输出 -> 文件:{}", filePath);
+        for (RcCompetitionTaskDateDO taskDateDO : taskDateDOList) {
+            String period = taskDateDO.getPriod();
+            List<? extends CompetitionBaseResultDTO> competitionResultDTOList = fundNavService.getCompetitionResult(competitionId, period);
+            if (CollUtil.isEmpty(competitionResultDTOList)) {
+                return;
+            }
+            Class<? extends CompetitionBaseResultDTO> aClass = competitionResultDTOList.get(0).getClass();
+            String filePath = competitionConfig.getDirectory() + competitionConfig.getName() + "_" + period + "_榜单_基金净值衍生指标及排名结果明细_" + DateUtil.format(new Date(), DateConst.YYYYMMDD) + ".xlsx";
+            EasyExcel.write(filePath, aClass)
+                    .sheet("基金净值衍生指标及排名结果明细")
+                    .doWrite(competitionResultDTOList);
+            log.info("基金净值衍生指标及排名结果明细表已输出 -> 文件:{}", filePath);
 
-        Integer method = competitionConfig.getMethod();
-        // 通过邮件发送"基金净值采集结果明细表格"
-        if (method == 2) {
-            MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo();
-            String recipientEmail = emailSystemConfigService.getRecipientEmail();
-            try {
-                EmailUtil.senEmail(mailboxInfoDTO, recipientEmail, new File(filePath), "基金净值衍生指标及排名结果明细", "", "基金净值衍生指标及排名结果明细");
-                log.info("基金净值衍生指标及排名结果明细表 -> 邮件已发送");
-            } catch (Exception e) {
-                log.error("邮件发送基金净值衍生指标及排名结果明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
+            Integer method = competitionConfig.getMethod();
+            // 通过邮件发送"基金净值采集结果明细表格"
+            if (method == 2) {
+                MailboxInfoDTO mailboxInfoDTO = emailSystemConfigService.getFromEmailInfo();
+                String receivingMailbox = emailSystemConfigService.getRecipientEmail();
+                if (mailboxInfoDTO == null || StrUtil.isBlank(receivingMailbox)) {
+                    continue;
+                }
+                try {
+                    String emailTitle = period + "_榜单_基金净值衍生指标及排名结果明细";
+                    EmailUtil.senEmail(mailboxInfoDTO, receivingMailbox, new File(filePath), emailTitle, "", emailTitle);
+                    log.info("基金净值衍生指标及排名结果明细表 -> 邮件已发送");
+                } catch (Exception e) {
+                    log.error("邮件发送基金净值衍生指标及排名结果明细表异常 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
+                }
             }
         }
-    }
 
+    }
 }