Selaa lähdekoodia

完成相似产品接口

wangzaijun 1 vuosi sitten
vanhempi
commit
b5d6d9c742

+ 6 - 0
src/main/java/com/smppw/analysis/application/dto/info/FundSimilarReq.java

@@ -21,6 +21,10 @@ public class FundSimilarReq extends BaseReq<FundSimilarParams> {
      */
     private String refId;
     /**
+     * 管理人id
+     */
+    private String trustId;
+    /**
      * 1-市场同策略,2-管理人同策略
      */
     private Integer calcType = 2;
@@ -37,6 +41,8 @@ public class FundSimilarReq extends BaseReq<FundSimilarParams> {
      */
     private String strategy;
 
+    private String benchmarkId;
+
     @Override
     public FundSimilarParams convert() {
         return BeanUtil.copyProperties(this, FundSimilarParams.class);

+ 88 - 19
src/main/java/com/smppw/analysis/application/service/info/FundInfoService.java

@@ -1,5 +1,6 @@
 package com.smppw.analysis.application.service.info;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.map.MapUtil;
@@ -11,22 +12,39 @@ import com.smppw.analysis.domain.dto.performance.IndicatorParams;
 import com.smppw.analysis.domain.manager.performance.Performance;
 import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
 import com.smppw.analysis.domain.manager.performance.PerformanceFactory;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
 import com.smppw.analysis.domain.service.BaseInfoService;
-import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.analysis.domain.service.NavService;
+import com.smppw.common.pojo.IStrategy;
+import com.smppw.common.pojo.NewSubStrategy;
+import com.smppw.common.pojo.dto.DateValue;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcTimeRangeDto;
+import com.smppw.common.pojo.enums.*;
+import com.smppw.core.IndicatorService;
+import com.smppw.utils.CalcUtils;
+import com.smppw.utils.NavUtil;
+import com.smppw.utils.StrategyHandleUtils;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 import java.util.stream.Collectors;
 
 @Service
 public class FundInfoService {
+    private final NavService navService;
     private final PerformanceFactory factory;
     private final BaseInfoService baseInfoService;
+    private final BaseIndicatorServiceV2 baseIndicatorServiceV2;
 
-    public FundInfoService(PerformanceFactory factory, BaseInfoService baseInfoService) {
+    public FundInfoService(NavService navService, PerformanceFactory factory,
+                           BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
         this.factory = factory;
+        this.navService = navService;
         this.baseInfoService = baseInfoService;
+        this.baseIndicatorServiceV2 = baseIndicatorServiceV2;
     }
 
     public PrivatelyFundHeadInfoVO headInfo(HeadInfoReq params) {
@@ -84,30 +102,81 @@ public class FundInfoService {
         return vo;
     }
 
+    /**
+     * 私募基金相似产品,计算相关性时代码可以优化(参考基金相关性)
+     *
+     * @param req /
+     * @return /
+     */
     public List<FundSimilarVO> getFundSimilarList(FundSimilarReq req) {
         List<String> refIds = ListUtil.toLinkedList(req.getRefId());
+        IStrategy strategy = StrategyHandleUtils.getStrategy(req.getStrategy());
+        Map<String, List<DateValue>> secNavMap = this.navService.getSecIdDateValueNavListMapByDb(refIds,
+                null, null, Visibility.Both, NavType.CumulativeNav, MapUtil.empty());
+        List<IndicatorCalcTimeRangeDto> secTimeRanges = IndicatorService.getInstance().getSecTimeRange(req.getRefId(), Frequency.Monthly, secNavMap);
+        String startDate = null;
+        String endDate = null;
+        if (CollUtil.isNotEmpty(secTimeRanges)) {
+            for (IndicatorCalcTimeRangeDto secTimeRange : secTimeRanges) {
+                if (TimeRange.Last1Year == secTimeRange.getTimeRange()) {
+                    startDate = secTimeRange.getStartDate();
+                    endDate = secTimeRange.getEndDate();
+                    break;
+                }
+            }
+        }
         FundSimilarParams params = req.convert();
+        params.setStartDate(startDate);
         List<FundSimilarDo> dataList = this.baseInfoService.getFundSimilarList(params);
         List<String> fundIds = dataList.stream().map(FundSimilarDo::getFundId).collect(Collectors.toList());
         if (CollUtil.isNotEmpty(fundIds)) {
             refIds.addAll(fundIds);
         }
-//        Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew = this.baseIndicatorServiceV2.getMultiSecRetListNew(
-//                secIds, ListUtil.empty(), Frequency.Monthly, Frequency.Daily, startDate, endDate, false, Consts.BENCHMARK,
-//                params.getRaiseType(), Strategy.All, Visibility.Visible, NavType.CumulativeNav);
-//        List<Map<String, Object>> initRetList = NavUtil.handleNextStepNew(secIds, ListUtil.empty(), multiSecRetListNew, false);
-//        Map<String, Map<String, Double>> retMap = RateConvertorUtils.transfer2TwoDimensionMap(initRetList, "fund_id", "end_date", "ret_range");
-//        Double[][] corArr = CalcUtils.getCorrelationMatrix(retMap, ListUtil.toList(params.getRefId()), secIds);
-//        for (FundSimilarDo map : dataList) {
-//            FundSimilarVO similarVO = BeanUtil.copyProperties(map, FundSimilarVO.class);
-//            int i = fundIds.indexOf(map.getFundId()) + 1; // 因为第一个基金是当前基金,所以需要 + 1 来取该基金与当前基金的相关性
-//            similarVO.setSimilar(corArr[0][i]);
-//            similarVO.setStrategy(StrategyHandleUtils.getStrategy(map.getStrategy()).getStrategyNameDesc());
-//            similarVO.setSubStrategy(this.getStrategyName(map.getSubStrategy()));
-//            similarVO.setThirdStrategy(this.getStrategyName(map.getThirdStrategy()));
-//            resultList.add(similarVO);
-//        }
-//        resultList.stream().filter(e -> e.getSimilar() != null && e.getSimilar() >= Double.parseDouble(params.getThreshold())).collect(Collectors.toList());
-        return null;
+        Map<String, List<DateValue>> allNavMap = this.navService.getSecIdDateValueNavListMapByDb(refIds,
+                startDate, endDate, Visibility.Both, NavType.CumulativeNav, MapUtil.empty());
+        Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew = this.baseIndicatorServiceV2.getMultiSecRetListNew(
+                refIds, ListUtil.empty(), Frequency.Monthly, Frequency.Daily, startDate, endDate, false, params.getBenchmarkId(),
+                params.getRaiseType(), strategy, Visibility.Both, NavType.CumulativeNav, allNavMap);
+        List<Map<String, Object>> initRetList = NavUtil.handleNextStepNew(refIds, ListUtil.empty(), multiSecRetListNew, false);
+        Map<String, Map<String, Double>> retMap = this.transfer2TwoDimensionMap(initRetList);
+        Double[][] corArr = CalcUtils.getCorrelationMatrix(retMap, ListUtil.toList(params.getRefId()), refIds);
+        List<FundSimilarVO> resultList = ListUtil.list(true);
+        for (FundSimilarDo map : dataList) {
+            FundSimilarVO similarVO = BeanUtil.copyProperties(map, FundSimilarVO.class);
+            int i = fundIds.indexOf(map.getFundId()) + 1; // 因为第一个基金是当前基金,所以需要 + 1 来取该基金与当前基金的相关性
+            similarVO.setSimilar(corArr[0][i]);
+            similarVO.setStrategy(StrategyHandleUtils.getStrategy(map.getStrategy()).getStrategyNameDesc());
+            similarVO.setSubStrategy(this.getStrategyName(map.getSubStrategy()));
+            similarVO.setThirdStrategy(this.getStrategyName(map.getThirdStrategy()));
+            resultList.add(similarVO);
+        }
+        return resultList.stream().filter(e -> e.getSimilar() != null && e.getSimilar() >= Double.parseDouble(params.getThreshold())).collect(Collectors.toList());
+    }
+
+    private String getStrategyName(String strategyKey) {
+        IStrategy strategy = StrategyHandleUtils.getStrategy(strategyKey);
+        if (strategy == null || strategy == NewSubStrategy.OtherStrategy || strategy.getStrategyId() == -1) {
+            return "--";
+        }
+        return strategy.getStrategyNameDesc();
+    }
+
+    private Map<String, Map<String, Double>> transfer2TwoDimensionMap(List<Map<String, Object>> initRetList) {
+        Map<String, Map<String, Double>> map = new TreeMap<>();
+        for (Map<String, Object> unit : initRetList) {
+            if (unit != null) {
+                String id = unit.get("fund_id").toString();
+                if (!map.containsKey(id)) {
+                    map.put(id, new TreeMap<>());
+                }
+                Object t = unit.get("ret_range");
+                if (t == null) {
+                    continue;
+                }
+                map.get(id).put(unit.get("end_date").toString(), Double.valueOf(unit.get("ret_range").toString()));
+            }
+
+        }
+        return map;
     }
 }

+ 8 - 0
src/main/java/com/smppw/analysis/client/FundApi.java

@@ -2,11 +2,14 @@ package com.smppw.analysis.client;
 
 import com.smppw.analysis.application.dto.info.*;
 import com.smppw.analysis.application.service.info.FundInfoService;
+import com.smppw.analysis.domain.dto.info.FundSimilarVO;
 import com.smppw.common.pojo.ResultVo;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * @author wangzaijun
  * @date 2023/8/7 15:40
@@ -35,4 +38,9 @@ public class FundApi {
     public ResultVo<HeadIndicatorVO> headIndicator(HeadIndicatorReq params) {
         return ResultVo.ok(this.service.headIndicator(params));
     }
+
+    @GetMapping("similar")
+    public ResultVo<List<FundSimilarVO>> similar(FundSimilarReq params) {
+        return ResultVo.ok(this.service.getFundSimilarList(params));
+    }
 }

+ 2 - 2
src/main/java/com/smppw/analysis/domain/dao/FundInformationDao.java

@@ -73,10 +73,10 @@ public class FundInformationDao {
     }
 
     public List<FundSimilarDo> getSameCompanyFundIds(Map<String, Object> params) {
-        return null;
+        return this.fundInformationDoMapper.getSameCompanyFundIds(params);
     }
 
     public List<FundSimilarDo> getSameStrategyFundIds(Map<String, Object> params) {
-        return null;
+        return this.fundInformationDoMapper.getSameStrategyFundIds(params);
     }
 }

+ 9 - 4
src/main/java/com/smppw/analysis/domain/dao/PubliclyFundPositionDao.java

@@ -26,7 +26,7 @@ public class PubliclyFundPositionDao {
     }
 
     public List<FundPositionBaseInfoDO> fundPositionBaseInfos(String fundId, String startDate, String endDate) {
-        List<FundPositionBaseInfoDO> dataList = this.publiclyFundExtInfoMapper.queryPositionBaseInfos(fundId, startDate, endDate);
+        List<FundPositionBaseInfoDO> dataList = this.publiclyFundExtInfoMapper.queryPositionBaseInfos(this.getRealFundId(fundId), startDate, endDate);
         if (CollUtil.isNotEmpty(dataList)) {
             dataList = dataList.stream().filter(e -> StrUtil.containsAny(DateUtil.formatDate(e.getReportDate()),
                     PUBLICLY_VALID_DATES)).collect(Collectors.toList());
@@ -35,7 +35,7 @@ public class PubliclyFundPositionDao {
     }
 
     public List<FundPositionDetailDO> positionDetailList(String fundId) {
-        List<FundPositionDetailDO> dataList = this.publiclyFundExtInfoMapper.queryPositionDetails(fundId);
+        List<FundPositionDetailDO> dataList = this.publiclyFundExtInfoMapper.queryPositionDetails(this.getRealFundId(fundId));
         if (CollUtil.isNotEmpty(dataList)) {
             dataList = dataList.stream().filter(e -> StrUtil.containsAny(DateUtil.formatDate(e.getValuationDate()),
                     PUBLICLY_VALID_DATES)).collect(Collectors.toList());
@@ -44,10 +44,15 @@ public class PubliclyFundPositionDao {
     }
 
     public List<PubliclyFundHolderInfoDO> mfHolderInfoList(String fundId, String startDate, String endDate) {
-        return this.publiclyFundExtInfoMapper.mfHolderInfoList(fundId, startDate, endDate);
+        return this.publiclyFundExtInfoMapper.mfHolderInfoList(this.getRealFundId(fundId), startDate, endDate);
     }
 
     public List<PubliclyFundStockChangeDO> mfStockChangeList(String fundId, String startDate, String endDate) {
-        return this.publiclyFundExtInfoMapper.mfStockChangeList(fundId, startDate, endDate);
+        return this.publiclyFundExtInfoMapper.mfStockChangeList(this.getRealFundId(fundId), startDate, endDate);
+    }
+
+    private String getRealFundId(String fundId) {
+        String relationFund = this.publiclyFundExtInfoMapper.getRelationFund(fundId);
+        return StrUtil.isNotBlank(relationFund) ? relationFund : fundId;
     }
 }

+ 4 - 0
src/main/java/com/smppw/analysis/domain/dto/info/FundSimilarParams.java

@@ -35,4 +35,8 @@ public class FundSimilarParams {
      * 末级策略,head-info接口返回的
      */
     private String strategy;
+
+    private String benchmarkId;
+
+    private String startDate;
 }

+ 4 - 3
src/main/java/com/smppw/analysis/domain/manager/performance/handler/CorrelationHandler.java

@@ -43,12 +43,13 @@ public class CorrelationHandler extends AbstractSingleSecPerformance<Correlation
         String endDate = params.getEndDate();
         List<String> refIds = params.getRefIds();
         String fundId = refIds.get(0);
-
-        Map<String, List<DateValue>> allNavMap = this.navService.getSecIdDateValueNavListMapByDb(refIds, params.getStartDate(), params.getEndDate(), Visibility.Both, params.getNavType(), MapUtil.empty());
+        Map<String, List<DateValue>> allNavMap = this.navService.getSecIdDateValueNavListMapByDb(refIds,
+                params.getStartDate(), params.getEndDate(), Visibility.Both, params.getNavType(), MapUtil.empty());
         List<IndicatorCalcTimeRangeDto> secTimeRanges = IndicatorService.getInstance().getSecTimeRange(fundId, params.getFrequency(), allNavMap);
         List<String> secIds = this.getSecIdsByParams(params);
         List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-        List<DateRange> dateRangeList = new RollingSpliter(startDate, endDate, params.getRollingWindow(), params.getRollingWindow(), false, Frequency.Monthly).split();
+        List<DateRange> dateRangeList = new RollingSpliter(startDate, endDate, params.getRollingWindow(), params.getRollingWindow(),
+                false, Frequency.Monthly).split();
         if (dateRangeList.isEmpty()) {
             throw new APIException("净值数量小于窗口期,请尝试调整取值区间");
         }

+ 17 - 0
src/main/java/com/smppw/analysis/domain/mapper/FundInformationDoMapper.java

@@ -1,6 +1,7 @@
 package com.smppw.analysis.domain.mapper;
 
 import com.smppw.analysis.domain.dataobject.FundInformationDo;
+import com.smppw.analysis.domain.dataobject.FundSimilarDo;
 import org.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
 
@@ -75,4 +76,20 @@ public interface FundInformationDoMapper {
      * @return /
      */
     List<Map<String, Object>> getFundRankByCall(Map<String, Object> params);
+
+    /**
+     * 获取同公司末级策略相同的所有产品中最近一年有净值的产品
+     *
+     * @param params /
+     * @return /
+     */
+    List<FundSimilarDo> getSameCompanyFundIds(Map<String, Object> params);
+
+    /**
+     * 取产品末级策略同策略近一年收益排名前50的产品(排除本产品
+     *
+     * @param params /
+     * @return /
+     */
+    List<FundSimilarDo> getSameStrategyFundIds(Map<String, Object> params);
 }

+ 8 - 0
src/main/java/com/smppw/analysis/domain/mapper/PubliclyFundExtInfoMapper.java

@@ -19,6 +19,14 @@ import java.util.Map;
 public interface PubliclyFundExtInfoMapper {
     List<FundPositionDetailDO> queryPositionDetails(String fundId);
 
+    /**
+     * 获取公募基金的关联基金
+     *
+     * @param fundId /
+     * @return /
+     */
+    String getRelationFund(String fundId);
+
     List<FundPositionBaseInfoDO> queryPositionBaseInfos(@Param("fundId") String fundId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
     List<PubliclyFundHolderInfoDO> mfHolderInfoList(@Param("fundId") String fundId, @Param("startDate") String startDate, @Param("endDate") String endDate);

+ 1 - 1
src/main/java/com/smppw/analysis/domain/service/impl/BaseInfoServiceImpl.java

@@ -237,7 +237,7 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
         String rankDate = this.getLatestRankRat();
         List<FundSimilarDo> tempList = ListUtil.list(true);
         if (params.getCalcType() == 2) {
-            Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId())
+            Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId()).put("startDate", params.getStartDate())
                     .put("tableName", "rz_hfdb_core.nav").put("trustId", params.getTrustId()).put("rankDate", rankDate).build();
             tempList.addAll(this.fundInformationDao.getSameCompanyFundIds(req));
         } else {

+ 63 - 0
src/main/resources/mapping/FundInformationDoMapper.xml

@@ -352,4 +352,67 @@
     <select id="getFundRankByCall" resultType="hashmap" parameterType="hashmap" statementType="CALLABLE">
         CALL rz_hfdb_core.sp_get_fund_strategy_year_ret_pro(1,null,#{rankDate,mode=IN},#{fundId,mode=IN},#{indexIds,mode=IN},#{indicator,mode=IN},null)
     </select>
+
+    <select id="getSameCompanyFundIds" resultType="com.smppw.analysis.domain.dataobject.FundSimilarDo" parameterType="hashmap">
+        select t.fund_id             as fundId,
+               t.fund_short_name     as fundName,
+               fs.first_strategy     as strategy,
+               fs.second_strategy    as subStrategy,
+               fs.third_strategy     as thirdStrategy,
+               fp.ret_ytd            as retYtd,
+               fp.ret_1y             as ret1y,
+               fp.ret_incep          as retIncep,
+               fp.ret_incep_a        as annualIncep,
+               frs.sharperatio_incep as shapeIncep,
+               fr.maxdrawdown_incep  as maxdownIncep,
+               fr.stddev_incep       as stdDevIncep
+        from rz_hfdb_core.fund_information t
+                 inner join rz_hfdb_core.fund_strategy fs on t.fund_id = fs.fund_id and fs.isvalid = 1
+                 left join rz_hfdb_core.fund_performance fp
+                           on fp.fund_id = t.fund_id and fp.isvalid = 1 and fp.end_date = #{rankDate}
+                 left join rz_hfdb_core.fund_riskadjret_stats frs
+                           on frs.fund_id = t.fund_id and frs.isvalid = 1 and frs.end_date = #{rankDate}
+                 left join rz_hfdb_core.fund_risk_stats fr
+                           on fr.fund_id = t.fund_id and fr.isvalid = 1 and fr.end_date = #{rankDate}
+        where t.trust_id = #{trustId} and t.isvalid = 1
+          and (fs.third_strategy = #{strategy} or fs.second_strategy = #{strategy})
+          and (select count(1) as cnt
+               from rz_hfdb_core.fund_information a
+                        join ${tableName} b on a.fund_id = b.fund_id and b.isvalid = 1
+            where b.price_date > #{startDate}
+          and a.fund_id = t.fund_id) > 0
+            limit 100
+    </select>
+
+    <select id="getSameStrategyFundIds" parameterType="hashmap" resultType="com.smppw.analysis.domain.dataobject.FundSimilarDo">
+        select t.fund_id             as fundId,
+               t.fund_short_name     as fundName,
+               fs.first_strategy     as strategy,
+               fs.second_strategy    as subStrategy,
+               fs.third_strategy     as thirdStrategy,
+               fp.ret_ytd            as retYtd,
+               fp.ret_1y             as ret1y,
+               fp.ret_incep          as retIncep,
+               fp.ret_incep_a        as annualIncep,
+               frs.sharperatio_incep as shapeIncep,
+               fr.maxdrawdown_incep  as maxdownIncep,
+               fr.stddev_incep       as stdDevIncep
+        from rz_hfdb_core.fund_information t
+                 inner join rz_hfdb_core.fund_strategy fs on t.fund_id = fs.fund_id and fs.isvalid = 1
+                 inner join ${tableName} c
+                            on t.fund_id = c.fund_id and c.indicator_id = 1
+                 left join rz_hfdb_core.fund_performance fp
+                           on fp.fund_id = t.fund_id and fp.isvalid = 1 and fp.end_date = #{rankDate}
+                 left join rz_hfdb_core.fund_riskadjret_stats frs
+                           on frs.fund_id = t.fund_id and frs.isvalid = 1 and frs.end_date = #{rankDate}
+                 left join rz_hfdb_core.fund_risk_stats fr
+                           on fr.fund_id = t.fund_id and fr.isvalid = 1 and fr.end_date = #{rankDate}
+        where t.isvalid = 1
+          and (fs.third_strategy = #{strategy} or fs.second_strategy = #{strategy})
+          and c.end_date = #{rankDate}
+          and c.indicator_id = 1
+          and c.isvalid = 1
+          and c.absrank_1y <![CDATA[<=]]> #{rankNum}
+            limit #{rankNum}
+    </select>
 </mapper>

+ 4 - 0
src/main/resources/mapping/PubliclyFundExtInfoMapper.xml

@@ -20,6 +20,10 @@
         order by a.valuation_date
     </select>
 
+    <select id="getRelationFund" resultType="string" parameterType="string">
+        select t.fund_id from gil_public_fund_relationship t where t.related_fund_id = #{fundId} and t.code_define in (21,22) limit 1
+    </select>
+
     <select id="queryPositionBaseInfos" resultType="com.smppw.analysis.domain.dataobject.FundPositionBaseInfoDO">
         select a.fund_id as fundId,
         a.mv_of_money as mvOfMoney,