Browse Source

feat:中航证券基金净值衍生指标及排名结果明细表

mozuwen 5 tháng trước cách đây
mục cha
commit
4ab9626108

+ 11 - 1
service-base/src/main/java/com/simuwang/base/config/CompetitionConfig.java

@@ -4,13 +4,23 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
 @Component
-@ConfigurationProperties(prefix = "competition.output")
+@ConfigurationProperties(prefix = "competition")
 public class CompetitionConfig {
 
+    private Integer id;
+
     private Integer method;
 
     private String  directory;
 
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
     public Integer getMethod() {
         return method;
     }

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

@@ -0,0 +1,13 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dto.ZhzqCompetitionResultDTO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface RzZhzq2ResultMapper {
+
+    List<ZhzqCompetitionResultDTO> getResult();
+
+}

+ 324 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/RzZhzq2ResDO.java

@@ -0,0 +1,324 @@
+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("rz_zhzq2_res")
+public class RzZhzq2ResDO {
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Integer id;
+    /**
+     * 排名期,周频为yyyy-mm-dd,月频为yyyy-mm
+     */
+    @TableField(value = "end_date")
+    private String endDate;
+    /**
+     * 排名区间 1m-月 3m-季度,6m-半年度, race-年度,race2-两年度
+     */
+    @TableField(value = "rank_range")
+    private String rankRange;
+    /**
+     * 排名分组ID
+     */
+    @TableField(value = "rank_group_id")
+    private Integer rankGroupId;
+    /**
+     * 策略
+     */
+    @TableField(value = "strategy")
+    private Integer strategy;
+    /**
+     * 基金id
+     */
+    @TableField(value = "fund_id")
+    private String fundId;
+    /**
+     * 基金备案编号
+     */
+    @TableField(value = "product_register_number")
+    private String productRegisterNumber;
+    /**
+     * 基金全称
+     */
+    @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 = "register_number")
+    private String registerNumber;
+    /**
+     * 公司名称
+     */
+    @TableField(value = "company_name")
+    private String companyName;
+    /**
+     * 公司名称
+     */
+    @TableField(value = "company_short_name")
+    private String companyShortName;
+    /**
+     * 净值日期
+     */
+    @TableField(value = "price_date")
+    private Date priceDate;
+    /**
+     * 单位净值
+     */
+    @TableField(value = "nav")
+    private BigDecimal nav;
+    /**
+     * 考虑分红再投资的单位累计净值
+     */
+    @TableField(value = "cumulative_nav")
+    private BigDecimal cumulativeNav;
+    /**
+     * 分红不投资的单位累计净值
+     */
+    @TableField(value = "cumulative_nav_withdrawal")
+    private BigDecimal cumulativeNavWithdrawal;
+    /**
+     * 区间收益计算用的起始净值日期
+     */
+    @TableField(value = "pre_price_date")
+    private Date prePriceDate;
+    /**
+     * 区间收益计算用的起始累计净值
+     */
+    @TableField(value = "pre_cumulative_nav")
+    private BigDecimal preCumulativeNav;
+    /**
+     * 得分
+     */
+    @TableField(value = "score")
+    private BigDecimal score;
+    /**
+     * 定量得分
+     */
+    @TableField(value = "quantitative_score")
+    private BigDecimal quantitativeScore;
+    /**
+     * 定性得分
+     */
+    @TableField(value = "qualitative_score")
+    private BigDecimal qualitativeScore;
+    /**
+     * 产品规模
+     */
+    @TableField(value = "product_scale")
+    private BigDecimal productScale;
+    /**
+     * 收益
+     */
+    @TableField(value = "ret")
+    private BigDecimal ret;
+    /**
+     * 近6个月收益
+     */
+    @TableField(value = "ret_6m")
+    private BigDecimal ret6m;
+    /**
+     * 年化收益
+     */
+    @TableField(value = "ret_a")
+    private BigDecimal retA;
+    /**
+     * 回撤
+     */
+    @TableField(value = "maxdown")
+    private BigDecimal maxdown;
+    /**
+     * 卡玛比率
+     */
+    @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 = "company_asset_size")
+    private Integer companyAssetSize;
+    /**
+     * 分组
+     */
+    @TableField(value = "scale_group")
+    private Integer scaleGroup;
+    /**
+     * 得分排名
+     */
+    @TableField(value = "rank_score")
+    private Integer rankScore;
+    /**
+     * 产品规模排名
+     */
+    @TableField(value = "rank_product_scale")
+    private Integer rankProductScale;
+    /**
+     * 最近一周收益排名
+     */
+    @TableField(value = "rank_ret")
+    private Integer rankRet;
+    /**
+     * 近6个月收益排名
+     */
+    @TableField(value = "rank_ret_6m")
+    private Integer rankRet6m;
+    /**
+     * 年化收益排名
+     */
+    @TableField(value = "rank_ret_a")
+    private Integer rankRetA;
+    /**
+     * 最近一周回撤排名
+     */
+    @TableField(value = "rank_maxdown")
+    private Integer rankMaxdown;
+    /**
+     * 卡玛比率排名
+     */
+    @TableField(value = "rank_calmarratio")
+    private Integer rankCalmarratio;
+    /**
+     * 夏普排名
+     */
+    @TableField(value = "rank_sharperatio")
+    private Integer rankSharperatio;
+    /**
+     * 索提诺排名
+     */
+    @TableField(value = "rank_sortinoratio")
+    private Integer rankSortinoratio;
+    /**
+     * 阿尔法排名
+     */
+    @TableField(value = "rank_alpha")
+    private Integer rankAlpha;
+    /**
+     * 胜率排名
+     */
+    @TableField(value = "rank_winrate")
+    private Integer rankWinrate;
+    /**
+     * 信息比率排名
+     */
+    @TableField(value = "rank_info_ratio")
+    private Integer rankInfoRatio;
+    /**
+     * 区间超额收益排名
+     */
+    @TableField(value = "rank_excess_ret")
+    private Integer rankExcessRet;
+    /**
+     * 超额回撤排名
+     */
+    @TableField(value = "rank_excess_maxdown")
+    private Integer rankExcessMaxdown;
+    /**
+     * 超额周胜率排名
+     */
+    @TableField(value = "rank_excess_winrate")
+    private Integer rankExcessWinrate;
+    /**
+     * 超额卡玛排名
+     */
+    @TableField(value = "rank_excess_calmarratio")
+    private Integer rankExcessCalmarratio;
+    /**
+     * 创建者Id,默认第一次创建者名称,创建后不变更
+     */
+    @TableField(value = "creatorid")
+    private Integer creatorId;
+    /**
+     * 创建时间,默认第一次创建的CreatTime时间
+     */
+    @TableField(value = "createtime")
+    private Date createTime;
+    /**
+     * 修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+     */
+    @TableField(value = "updaterid")
+    private Integer updaterId;
+    /**
+     * 修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+     */
+    @TableField(value = "updatetime")
+    private Date updateTime;
+    /**
+     * 记录的有效性;1-有效;0-无效;
+     */
+    @TableField(value = "isvalid")
+    private Integer isvalid;
+    /**
+     * 是否在中信开户
+     */
+    @TableField(value = "is_open_account")
+    private String isOpenAccount;
+    /**
+     * 是否在中航中期期货开户
+     */
+    @TableField(value = "is_open_account2")
+    private String isOpenAccount2;
+}

+ 129 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/CompetitionBaseResultDTO.java

@@ -0,0 +1,129 @@
+package com.simuwang.base.pojo.dto;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author mozuwen
+ * @date 2024-11-01
+ * @description 大赛排名结果明细基本字段
+ */
+@Data
+public class CompetitionBaseResultDTO {
+
+    /**
+     * 策略
+     */
+    @HeadFontStyle(fontHeightInPoints = 10)
+    @ColumnWidth(15)
+    @ExcelProperty(value = "策略", index = 0)
+    private String strategyName;
+
+    /**
+     * 排名
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "排名", index = 1)
+    private Integer rank;
+
+    /**
+     * 综合得分
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "综合得分", index = 2)
+    private BigDecimal score;
+    /**
+     * 策略
+     */
+    @ExcelIgnore
+    private Integer strategy;
+
+    /**
+     * 产品
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品", index = 3)
+    private String fundId;
+
+    /**
+     * 产品备案编码
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品备案编码", index = 4)
+    private String registerNumber;
+
+    /**
+     * 产品全称
+     */
+    @ColumnWidth(25)
+    @ExcelProperty(value = "产品全称", index = 5)
+    private String fundName;
+
+    /**
+     * 产品简称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "产品简称", index = 6)
+    private String fundShortName;
+
+    /**
+     * 公司
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司", index = 7)
+    private String companyId;
+
+    /**
+     * 公司备案编码
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司备案编码", index = 8)
+    private String companyRegisterNumber;
+
+    /**
+     * 公司全称
+     */
+    @ColumnWidth(25)
+    @ExcelProperty(value = "公司全称", index = 9)
+    private String companyName;
+
+    /**
+     * 公司简称
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "公司简称", index = 10)
+    private String companyShortName;
+
+    /**
+     * 期初净值日期
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期初净值日期", index = 11)
+    private String startPriceDate;
+
+    /**
+     * 期初净值
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期初净值", index = 12)
+    private String startCumulativeNavWithdrawal;
+
+    /**
+     * 期末净值日期
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期末净值日期", index = 13)
+    private String endPriceDate;
+
+    /**
+     * 期末净值
+     */
+    @ColumnWidth(15)
+    @ExcelProperty(value = "期末净值", index = 14)
+    private String endCumulativeNavWithdrawal;
+}

+ 83 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/ZhzqCompetitionResultDTO.java

@@ -0,0 +1,83 @@
+package com.simuwang.base.pojo.dto;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.HeadFontStyle;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author mozuwen
+ * @date 2024-11-01
+ * @description 中航证券大赛排名榜单模板
+ */
+@Data
+public class ZhzqCompetitionResultDTO extends CompetitionBaseResultDTO {
+
+    /**
+     * 收益率
+     */
+    @HeadFontStyle(fontHeightInPoints = 10)
+    @ColumnWidth(15)
+    @ExcelProperty("收益率")
+    private BigDecimal ret;
+
+    /**
+     * 回撤
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("回撤")
+    private BigDecimal maxdown;
+
+    /**
+     * 夏普比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("夏普比率")
+    private BigDecimal sharpeRatio;
+
+    /**
+     * 信息比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("信息比率")
+    private BigDecimal infoRatio;
+
+    /**
+     * 卡玛比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("卡玛比率")
+    private BigDecimal calmarRatio;
+
+    /**
+     * 产品规模
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("产品规模")
+    private BigDecimal productScale;
+
+    /**
+     * 区间超额收益
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("区间超额收益")
+    private BigDecimal excessRet;
+
+    /**
+     * 超额回撤
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("超额回撤")
+    private BigDecimal excessMaxdown;
+
+    /**
+     * 超额卡玛比率
+     */
+    @ColumnWidth(15)
+    @ExcelProperty("超额卡玛比率")
+    private BigDecimal excessCalmarRatio;
+
+}

+ 31 - 0
service-base/src/main/resources/mapper/RzZhzq2ResultMapper.xml

@@ -0,0 +1,31 @@
+<?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.RzZhzq2ResultMapper">
+    <select id="getResult" resultType="com.simuwang.base.pojo.dto.ZhzqCompetitionResultDTO">
+        select strategy                  as strategy,
+               fund_id                   as fundId,
+               product_register_number   as registerNumber,
+               fund_name                 as fundName,
+               fund_short_name           as fundShortName,
+               company_id                as companyId,
+               register_number           as companyRegisterNumber,
+               company_name              as companyName,
+               company_short_name        as companyShortName,
+               pre_price_date            as startPriceDate,
+               pre_cumulative_nav        as startCumulativeNavWithdrawal,
+               price_date                as endPriceDate,
+               cumulative_nav_withdrawal as endCumulativeNavWithdrawal,
+               score                     as score,
+               product_scale             as productScale,
+               ret,
+               maxdown,
+               calmarratio               as calmarRatio,
+               sharperatio               as sharpeRatio,
+               info_ratio                as infoRation,
+               excess_ret                as excessRet,
+               excess_maxdown            as excessMaxdown,
+               excess_calmarratio        as excessCalmarratio
+        from rz_zhzq2_res
+        WHERE isvalid = 1
+    </select>
+</mapper>

+ 6 - 5
service-deploy/src/main/resources/application.yml

@@ -61,11 +61,12 @@ email:
     force-template-enable: false
 
 competition:
-  output:
-    # 输出方式:1-邮箱,2-指定目录.默认1
-    method: 1
-    # 输出目录(仅当 method 为 2 时有效)
-    directory: C:\\Users\\Administrator\\Desktop\\大赛工具需求\\净值采集结果\\
+  # 大赛id
+  id: 49
+  # 输出方式:1-邮箱,2-指定目录.默认1
+  method: 1
+  # 输出目录(仅当 method 为 2 时有效)
+  directory: C:\\Users\\Administrator\\Desktop\\大赛工具需求\\净值采集结果\\
 
 # 配置
 simuwang:

+ 18 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/AbstractCompetitionResult.java

@@ -0,0 +1,18 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.collection.CollUtil;
+import com.simuwang.base.pojo.dto.CompetitionBaseResultDTO;
+
+import java.util.List;
+
+public abstract class AbstractCompetitionResult {
+
+    public boolean isSupport(Integer competitionId){
+        return false;
+    }
+
+    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult(){
+        return CollUtil.newArrayList();
+    }
+
+}

+ 27 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/CompetitionFactory.java

@@ -0,0 +1,27 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.map.MapUtil;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class CompetitionFactory {
+
+    private final Map<String, AbstractCompetitionResult> COMPETITION_RESULT_MAP = MapUtil.newHashMap();
+
+    public CompetitionFactory(Map<String, AbstractCompetitionResult> resultMap) {
+        COMPETITION_RESULT_MAP.putAll(resultMap);
+    }
+
+    public AbstractCompetitionResult getInstance(Integer competitionId) {
+        for (Map.Entry<String, AbstractCompetitionResult> competitionResultEntry : COMPETITION_RESULT_MAP.entrySet()) {
+            AbstractCompetitionResult competitionResult = competitionResultEntry.getValue();
+            if (competitionResult.isSupport(competitionId)) {
+                return competitionResult;
+            }
+        }
+        return null;
+    }
+
+}

+ 10 - 1
service-manage/src/main/java/com/simuwang/manage/service/FundNavService.java

@@ -1,5 +1,6 @@
-package com.simuwang.manage.service;
+package com.simuwang.manage.service.competition;
 
+import com.simuwang.base.pojo.dto.CompetitionBaseResultDTO;
 import com.simuwang.base.pojo.dto.FundNavDataDTO;
 import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
 
@@ -20,4 +21,12 @@ public interface FundNavService {
      * @return 基金净值缺失明细数据
      */
     List<FundNavDeletionDTO> getFundNavDeletion();
+
+    /**
+     * 获取大赛榜单结果
+     *
+     * @param competitionId 大赛id(区分不同大赛)
+     * @return 大赛榜单结果
+     */
+    List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId);
 }

+ 17 - 3
service-manage/src/main/java/com/simuwang/manage/service/impl/FundNavServiceImpl.java

@@ -1,4 +1,4 @@
-package com.simuwang.manage.service.impl;
+package com.simuwang.manage.service.competition;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
@@ -7,9 +7,10 @@ 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.CompetitionBaseResultDTO;
 import com.simuwang.base.pojo.dto.FundNavDataDTO;
 import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
-import com.simuwang.manage.service.FundNavService;
+import com.simuwang.base.pojo.dto.ZhzqCompetitionResultDTO;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -27,14 +28,17 @@ public class FundNavServiceImpl implements FundNavService {
     private final AssetMapper assetMapper;
     private final DeletionInfoMapper deletionInfoMapper;
     private final TradeDateMapper tradeDateMapper;
+    private final CompetitionFactory competitionFactory;
 
     public FundNavServiceImpl(NavMapper navMapper, FundInfoMapper fundInfoMapper,
-                              AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper, TradeDateMapper tradeDateMapper) {
+                              AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper,
+                              TradeDateMapper tradeDateMapper, CompetitionFactory competitionFactory) {
         this.navMapper = navMapper;
         this.fundInfoMapper = fundInfoMapper;
         this.assetMapper = assetMapper;
         this.deletionInfoMapper = deletionInfoMapper;
         this.tradeDateMapper = tradeDateMapper;
+        this.competitionFactory = competitionFactory;
     }
 
     @Override
@@ -93,6 +97,16 @@ public class FundNavServiceImpl implements FundNavService {
         return navDeletionDTOList;
     }
 
+    @Override
+    public List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId) {
+        List<ZhzqCompetitionResultDTO> dataList = CollUtil.newArrayList();
+        AbstractCompetitionResult 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();

+ 69 - 0
service-manage/src/main/java/com/simuwang/manage/service/competition/ZhzqCompetitionResult.java

@@ -0,0 +1,69 @@
+package com.simuwang.manage.service.competition;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import com.simuwang.base.mapper.RzZhzq2ResultMapper;
+import com.simuwang.base.pojo.dto.CompetitionBaseResultDTO;
+import com.simuwang.base.pojo.dto.ZhzqCompetitionResultDTO;
+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 ZhzqCompetitionResult extends AbstractCompetitionResult {
+
+    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;
+
+    public ZhzqCompetitionResult(RzZhzq2ResultMapper zhzqResultMapper) {
+        this.zhzqResultMapper = zhzqResultMapper;
+    }
+
+    @Override
+    public boolean isSupport(Integer competitionId) {
+        return competitionId != null && competitionId == 49;
+    }
+
+    @Override
+    protected List<? extends CompetitionBaseResultDTO> getCompetitionResult() {
+        List<ZhzqCompetitionResultDTO> competitionResultDTOList = zhzqResultMapper.getResult();
+        if (CollUtil.isEmpty(competitionResultDTOList)) {
+            return CollUtil.newArrayList();
+        }
+        // 策略名称排名
+        Map<Integer, List<ZhzqCompetitionResultDTO>> strategyResultDTOList = competitionResultDTOList.stream().collect(Collectors.groupingBy(CompetitionBaseResultDTO::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(CompetitionBaseResultDTO::getScore, Comparator.nullsFirst(Comparator.naturalOrder())).reversed());
+            // 计算排名并设置
+            int rank = 1;
+            for (int i = 0; i < resultDTOList.size(); i++) {
+                CompetitionBaseResultDTO dto = resultDTOList.get(i);
+                dto.setRank(rank);
+                dto.setStrategyName(strategyName);
+                rank = i + 1;
+            }
+        }
+        // 策略分组和排名降序输出
+        return competitionResultDTOList.stream()
+                .sorted(Comparator.comparing(CompetitionBaseResultDTO::getStrategyName).reversed().thenComparing(CompetitionBaseResultDTO::getRank))
+                .collect(Collectors.toList());
+    }
+
+}

+ 30 - 1
service-manage/src/main/java/com/simuwang/manage/task/CompetitionTask.java

@@ -7,11 +7,12 @@ 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.pojo.dto.CompetitionBaseResultDTO;
 import com.simuwang.base.pojo.dto.FundNavDataDTO;
 import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
 import com.simuwang.base.pojo.dto.MailboxInfoDTO;
 import com.simuwang.manage.service.EmailSystemConfigService;
-import com.simuwang.manage.service.FundNavService;
+import com.simuwang.manage.service.competition.FundNavService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -94,4 +95,32 @@ public class CompetitionTask {
         }
     }
 
+    @Scheduled(cron = "0/10 * * * * ?")
+    public void competitionResultTask() {
+        Integer competitionId = competitionConfig.getId();
+        List<? extends CompetitionBaseResultDTO> competitionResultDTOList = fundNavService.getCompetitionResult(competitionId);
+        if (CollUtil.isEmpty(competitionResultDTOList)) {
+            return;
+        }
+        Class<? extends CompetitionBaseResultDTO> aClass = competitionResultDTOList.get(0).getClass();
+        String filePath = competitionConfig.getDirectory() + "基金净值衍生指标及排名结果明细_" + 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));
+            }
+        }
+    }
+
 }