Jelajahi Sumber

业绩表现接口完成

wangzaijun 1 tahun lalu
induk
melakukan
d481b0a531
74 mengubah file dengan 3426 tambahan dan 2969 penghapusan
  1. 26 0
      src/main/java/com/smppw/analysis/application/dto/BaseReq.java
  2. 23 0
      src/main/java/com/smppw/analysis/application/dto/info/CommonInfoReq.java
  3. 47 0
      src/main/java/com/smppw/analysis/application/dto/info/CommonInfoVO.java
  4. 37 0
      src/main/java/com/smppw/analysis/application/dto/info/HeadIndicatorReq.java
  5. 26 0
      src/main/java/com/smppw/analysis/application/dto/info/HeadIndicatorVO.java
  6. 18 0
      src/main/java/com/smppw/analysis/application/dto/info/HeadInfoReq.java
  7. 83 0
      src/main/java/com/smppw/analysis/application/dto/info/HeadInfoVO.java
  8. 58 0
      src/main/java/com/smppw/analysis/application/dto/info/PrivatelyFundHeadInfoVO.java
  9. 65 0
      src/main/java/com/smppw/analysis/application/dto/info/PubilclyCurrencyFundHeadInfoVO.java
  10. 49 0
      src/main/java/com/smppw/analysis/application/dto/info/PubilclyFundHeadInfoVO.java
  11. 64 0
      src/main/java/com/smppw/analysis/application/dto/performance/BasePerformanceReq.java
  12. 20 0
      src/main/java/com/smppw/analysis/application/dto/performance/CorrelationReq.java
  13. 16 0
      src/main/java/com/smppw/analysis/application/dto/performance/DrawdownTrendReq.java
  14. 30 0
      src/main/java/com/smppw/analysis/application/dto/performance/ImfTrendReq.java
  15. 24 0
      src/main/java/com/smppw/analysis/application/dto/performance/IndicatorReq.java
  16. 20 0
      src/main/java/com/smppw/analysis/application/dto/performance/IntervalReq.java
  17. 21 0
      src/main/java/com/smppw/analysis/application/dto/performance/RankReq.java
  18. 28 0
      src/main/java/com/smppw/analysis/application/dto/performance/RevenueReq.java
  19. 20 0
      src/main/java/com/smppw/analysis/application/dto/performance/RollingReq.java
  20. 25 0
      src/main/java/com/smppw/analysis/application/dto/performance/TrendReq.java
  21. 20 0
      src/main/java/com/smppw/analysis/application/dto/performance/WinReq.java
  22. 105 0
      src/main/java/com/smppw/analysis/application/service/info/FundInfoService.java
  23. 0 57
      src/main/java/com/smppw/analysis/application/service/performance/CommonService.java
  24. 80 0
      src/main/java/com/smppw/analysis/application/service/performance/FundPerformanceService.java
  25. 12 0
      src/main/java/com/smppw/analysis/application/service/performance/MultiPerformanceService.java
  26. 0 390
      src/main/java/com/smppw/analysis/application/service/performance/PerformanceService.java
  27. 3 3
      src/main/java/com/smppw/analysis/application/service/position/FuturePositionAnalysis.java
  28. 3 3
      src/main/java/com/smppw/analysis/application/service/position/StockPositionAnalysis.java
  29. 3 3
      src/main/java/com/smppw/analysis/application/service/position/SynthesizePositionAnalysis.java
  30. 24 0
      src/main/java/com/smppw/analysis/client/FundApi.java
  31. 58 20
      src/main/java/com/smppw/analysis/client/FundPerformanceApi.java
  32. 11 1
      src/main/java/com/smppw/analysis/domain/dao/FundInformationDao.java
  33. 70 0
      src/main/java/com/smppw/analysis/domain/dataobject/MonetaryFundProfitDO.java
  34. 1 1
      src/main/java/com/smppw/analysis/domain/dto/performance/AnalyzeCovParams.java
  35. 0 18
      src/main/java/com/smppw/analysis/domain/dto/performance/HeadIndicatorParams.java
  36. 0 18
      src/main/java/com/smppw/analysis/domain/dto/performance/ImfTrendParams.java
  37. 5 0
      src/main/java/com/smppw/analysis/domain/dto/performance/IndicatorParams.java
  38. 2 2
      src/main/java/com/smppw/analysis/domain/dto/performance/RangIndicatorParams.java
  39. 1 1
      src/main/java/com/smppw/analysis/domain/dto/performance/RollIndicatorParams.java
  40. 5 1
      src/main/java/com/smppw/analysis/domain/dto/performance/TrendParams.java
  41. 49 0
      src/main/java/com/smppw/analysis/domain/dto/performance/WinVO.java
  42. 95 0
      src/main/java/com/smppw/analysis/domain/manager/performance/AbstractPerformance.java
  43. 0 1287
      src/main/java/com/smppw/analysis/domain/manager/performance/AbstractPerformanceService.java
  44. 108 0
      src/main/java/com/smppw/analysis/domain/manager/performance/AbstractSingleSecPerformance.java
  45. 435 0
      src/main/java/com/smppw/analysis/domain/manager/performance/HistoryRetTableUtil.java
  46. 12 0
      src/main/java/com/smppw/analysis/domain/manager/performance/Performance.java
  47. 21 0
      src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceConstants.java
  48. 35 0
      src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceFactory.java
  49. 0 145
      src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceService.java
  50. 0 946
      src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceServiceImpl.java
  51. 207 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/CorrelationHandler.java
  52. 42 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/ImfTrendHandler.java
  53. 118 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/IndicatorHandler.java
  54. 117 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/IntervalHandler.java
  55. 97 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/RankHandler.java
  56. 282 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/RevenueHandler.java
  57. 215 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/RollingHandler.java
  58. 109 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/TrendHandler.java
  59. 175 0
      src/main/java/com/smppw/analysis/domain/manager/performance/handler/WinHandler.java
  60. 0 5
      src/main/java/com/smppw/analysis/domain/manager/performance/package-info.java
  61. 2 1
      src/main/java/com/smppw/analysis/domain/manager/position/AbstractBizHandler.java
  62. 3 3
      src/main/java/com/smppw/analysis/domain/manager/position/BizHandlerFactor.java
  63. 4 4
      src/main/java/com/smppw/analysis/domain/manager/position/PositionLoadFactory.java
  64. 3 3
      src/main/java/com/smppw/analysis/domain/manager/position/stock/IndustryAllocationPreferenceComponent.java
  65. 15 2
      src/main/java/com/smppw/analysis/domain/service/BaseIndicatorServiceV2.java
  66. 11 2
      src/main/java/com/smppw/analysis/domain/service/BaseInfoService.java
  67. 3 5
      src/main/java/com/smppw/analysis/domain/service/NavService.java
  68. 34 9
      src/main/java/com/smppw/analysis/domain/service/impl/BaseIndicatorServiceV2Impl.java
  69. 46 25
      src/main/java/com/smppw/analysis/domain/service/impl/BaseInfoServiceImpl.java
  70. 4 5
      src/main/java/com/smppw/analysis/domain/service/impl/NavServiceImpl.java
  71. 18 0
      src/main/java/com/smppw/analysis/infrastructure/config/AnalysisProperty.java
  72. 2 3
      src/main/java/com/smppw/analysis/infrastructure/consts/RedisConst.java
  73. 50 6
      src/main/java/com/smppw/analysis/infrastructure/gatewayimpl/InMemoryCacheGateway.java
  74. 11 0
      src/main/java/com/smppw/analysis/infrastructure/persistence/MonetaryFundProfitMapper.java

+ 26 - 0
src/main/java/com/smppw/analysis/application/dto/BaseReq.java

@@ -0,0 +1,26 @@
+package com.smppw.analysis.application.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:24
+ * @description 基本请求参数,用来做接口签名验证的,验证通过后把这些参数洗掉
+ */
+@Setter
+@Getter
+public abstract class BaseReq {
+    /**
+     * 参数签名,防止参数被篡改
+     */
+    private String sign;
+    /**
+     * 随机字符串,防止重放攻击
+     */
+    private String nonce;
+    /**
+     * 时间戳,防止重放攻击
+     */
+    private long timestamp;
+}

+ 23 - 0
src/main/java/com/smppw/analysis/application/dto/info/CommonInfoReq.java

@@ -0,0 +1,23 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.analysis.application.dto.BaseReq;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:44
+ * @description 公共接口-统一设置
+ */
+@Setter
+@Getter
+public class CommonInfoReq extends BaseReq {
+    /**
+     * 标的id
+     */
+    private String secId;
+    /**
+     * 策略,核心策略,默认All,基金不传或传All
+     */
+    private String strategy;
+}

+ 47 - 0
src/main/java/com/smppw/analysis/application/dto/info/CommonInfoVO.java

@@ -0,0 +1,47 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.common.pojo.ValueLabelVO;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:51
+ * @description 统一设置返回数据
+ */
+@Setter
+@Getter
+public class CommonInfoVO {
+    /**
+     * 当前标的的基准id
+     */
+    private String benchmarkId;
+    /**
+     * 支持的净值频率
+     * 前端把公募基金固定为日频
+     */
+    private List<ValueLabelVO> frequency;
+    /**
+     * 净值类型
+     */
+    private List<ValueLabelVO> navType;
+    /**
+     * 时段
+     */
+    private Map<String, String> timeRangeMap;
+    /**
+     * 所有可用的基准
+     */
+    private List<ValueLabelVO> usefulBenchmark;
+    /**
+     * 开始日期
+     */
+    private String startDate;
+    /**
+     * 结束日期
+     */
+    private String endDate;
+}

+ 37 - 0
src/main/java/com/smppw/analysis/application/dto/info/HeadIndicatorReq.java

@@ -0,0 +1,37 @@
+package com.smppw.analysis.application.dto.info;
+
+import cn.hutool.core.util.StrUtil;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.NavType;
+import com.smppw.common.pojo.enums.RaiseType;
+import com.smppw.common.pojo.enums.strategy.Strategy;
+import lombok.Setter;
+
+@Setter
+public class HeadIndicatorReq {
+    private String secId;
+    private NavType navType;
+    private Frequency frequency;
+    private RaiseType raiseType;
+    private String strategy;
+
+    public String getSecId() {
+        return secId;
+    }
+
+    public NavType getNavType() {
+        return StrUtil.isBlankIfStr(this.navType) ? NavType.CumulativeNav : this.navType;
+    }
+
+    public Frequency getFrequency() {
+        return StrUtil.isBlankIfStr(this.frequency) ? Frequency.Default : this.frequency;
+    }
+
+    public RaiseType getRaiseType() {
+        return StrUtil.isBlankIfStr(this.raiseType) ? RaiseType.Private : this.raiseType;
+    }
+
+    public String getStrategy() {
+        return StrUtil.isBlank(this.strategy) ? Strategy.All.getStrategyOriginName() : this.strategy;
+    }
+}

+ 26 - 0
src/main/java/com/smppw/analysis/application/dto/info/HeadIndicatorVO.java

@@ -0,0 +1,26 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 17:40
+ * @description 头部成立以来指标
+ */
+@Setter
+@Getter
+public class HeadIndicatorVO {
+    @JsonProperty(value = "AnnualReturn")
+    private String annualReturn;
+
+    @JsonProperty(value = "AnnualStdDev")
+    private String annualStdDev;
+
+    @JsonProperty(value = "MaxDrawdown")
+    private String maxDrawdown;
+
+    @JsonProperty(value = "SharpeRatio")
+    private String sharpeRatio;
+}

+ 18 - 0
src/main/java/com/smppw/analysis/application/dto/info/HeadInfoReq.java

@@ -0,0 +1,18 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.analysis.application.dto.BaseReq;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class HeadInfoReq extends BaseReq {
+    /**
+     * 标的id
+     */
+    private String secId;
+    /**
+     * 策略,核心策略,默认All,基金不传或传All
+     */
+    private String strategy;
+}

+ 83 - 0
src/main/java/com/smppw/analysis/application/dto/info/HeadInfoVO.java

@@ -0,0 +1,83 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.common.pojo.ValueLabelVO;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 18:18
+ * @description 公共的头部信息
+ */
+@Setter
+@Getter
+public abstract class HeadInfoVO {
+    /**
+     * 基金id,'HF'开头(后加36进制编码格式,不足8位长度左补零) 例:HF00000001
+     */
+    private String refId;
+    /**
+     * 供前端使用 方便他们判断
+     */
+    private String detailId;
+    /**
+     * 基金中文简称
+     */
+    private String refShortName;
+    /**
+     * 基金中文全称
+     */
+    private String refName;
+    /**
+     * 备案编码
+     */
+    private String registerNumber;
+    /**
+     * 备案编码跳转到中基协链接
+     */
+    private String amacUrl;
+    /**
+     * 公私募类型
+     */
+    private String raiseType;
+    /**
+     * 公私募类型
+     */
+    private String raiseTypeValue;
+    /**
+     * 成立日期
+     */
+    private String inceptionDate;
+    /**
+     * 一级策略id
+     */
+    private String strategyId;
+    /**
+     * 一级策略名称
+     */
+    private String strategy;
+    /**
+     * 二级策略id
+     */
+    private String substrategyId;
+    /**
+     * 二级策略名称
+     */
+    private String substrategy;
+    /**
+     * 公司规模
+     */
+    private Byte companyAssetSize;
+    /**
+     * 合并后的策略
+     */
+    private String strategySummaryName;
+    /**
+     * 最新净值日期
+     */
+    private String priceDate;
+    /**
+     * 是否小于500万
+     */
+    private ValueLabelVO lowerThanFiveMillionLabel;
+}

+ 58 - 0
src/main/java/com/smppw/analysis/application/dto/info/PrivatelyFundHeadInfoVO.java

@@ -0,0 +1,58 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.common.pojo.ValueLabelVO;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:41
+ * @description 私募基金基本信息-头部
+ */
+@Setter
+@Getter
+public class PrivatelyFundHeadInfoVO extends HeadInfoVO {
+    /**
+     * 基金管理人ID
+     */
+    private String trustId;
+    /**
+     * 基金管理人
+     */
+    private String trustName;
+    /**
+     * 基金经理 id:名称
+     */
+    private List<ValueLabelVO> managers;
+    /**
+     * 基金状态值
+     */
+    private String fundStatusValue;
+    /**
+     * 三级策略名称
+     */
+    private String thirdStrategyId;
+    /**
+     * 三级策略名称
+     */
+    private String thirdStrategy;
+    /**
+     * 基金规模 中基协数据
+     */
+    private String fundScale;
+
+    /**
+     * 单位净值
+     */
+    private String originalNav;
+    /**
+     * 复权净值
+     */
+    private String cumulativeNav;
+    /**
+     * 累计净值
+     */
+    private String cumulativeNavWithdrawal;
+}

+ 65 - 0
src/main/java/com/smppw/analysis/application/dto/info/PubilclyCurrencyFundHeadInfoVO.java

@@ -0,0 +1,65 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.common.pojo.ValueLabelVO;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:41
+ * @description 货币型公募基金 头部
+ */
+@Setter
+@Getter
+public class PubilclyCurrencyFundHeadInfoVO {
+    /**
+     * 基金管理人ID
+     */
+    private String trustId;
+    /**
+     * 基金管理人
+     */
+    private String trustName;
+    /**
+     * 基金经理 id:名称
+     */
+    private List<ValueLabelVO> managers;
+    /**
+     * 基金状态值
+     */
+    private String fundStatusValue;
+    /**
+     * 基金规模---仅仅公募用
+     */
+    private String fundSize;
+
+    /**
+     * 基金规模日期---基金公募用(货币型)
+     */
+    private String fundSizeDate;
+
+    /**
+     * 基金规模--仅仅公募用--单位
+     */
+    private String fundSizeUnit;
+    /**
+     * 是否货币型公募基金
+     */
+    private Integer isCurrency;
+    /**
+     * 7日年化收益
+     */
+    private BigDecimal profitSevenDayAnnual;
+    /**
+     * 百份、万份、百万份收益
+     */
+    private BigDecimal retPerUnit;
+
+    /**
+     * 单位- 1:百份  2:万份  3:百万份
+     */
+    private String publicWorthUnit;
+}

+ 49 - 0
src/main/java/com/smppw/analysis/application/dto/info/PubilclyFundHeadInfoVO.java

@@ -0,0 +1,49 @@
+package com.smppw.analysis.application.dto.info;
+
+import com.smppw.common.pojo.ValueLabelVO;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/7 16:41
+ * @description 普通的非货币型基金基本信息-头部
+ */
+@Setter
+@Getter
+public class PubilclyFundHeadInfoVO {
+    /**
+     * 基金管理人ID
+     */
+    private String trustId;
+    /**
+     * 基金管理人
+     */
+    private String trustName;
+    /**
+     * 基金经理 id:名称
+     */
+    private List<ValueLabelVO> managers;
+    /**
+     * 基金状态值
+     */
+    private String fundStatusValue;
+    /**
+     * 基金规模 中基协数据
+     */
+    private String fundScale;
+    /**
+     * 单位净值
+     */
+    private String originalNav;
+    /**
+     * 复权净值
+     */
+    private String cumulativeNav;
+    /**
+     * 累计净值
+     */
+    private String cumulativeNavWithdrawal;
+}

+ 64 - 0
src/main/java/com/smppw/analysis/application/dto/performance/BasePerformanceReq.java

@@ -0,0 +1,64 @@
+package com.smppw.analysis.application.dto.performance;
+
+import com.smppw.analysis.application.dto.BaseReq;
+import com.smppw.analysis.domain.dto.performance.Params;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.NavType;
+import com.smppw.common.pojo.enums.RaiseType;
+import com.smppw.common.pojo.enums.TimeRange;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter
+@Getter
+public abstract class BasePerformanceReq<R extends Params> extends BaseReq {
+    /**
+     * 标的id,包括基金、机构和经理
+     */
+    private List<String> refIds;
+    /**
+     * 基准
+     */
+    private String benchmarkId;
+    /**
+     * 对比指数
+     */
+    private List<String> secIds;
+    /**
+     * 净值类型
+     */
+    private NavType navType;
+    /**
+     * 时段
+     */
+    private TimeRange timeRange;
+    /**
+     * 频率
+     */
+    private Frequency frequency;
+    /**
+     * 标的类型
+     */
+    private RaiseType raiseType;
+    /**
+     * 二级策略
+     */
+    private String strategy;
+    /**
+     * 开始日期
+     */
+    private String startDate;
+    /**
+     * 结束日期
+     */
+    private String endDate;
+
+    /**
+     * 参数转换,必须实现
+     *
+     * @return /
+     */
+    public abstract R convert();
+}

+ 20 - 0
src/main/java/com/smppw/analysis/application/dto/performance/CorrelationReq.java

@@ -0,0 +1,20 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.CorrelationParams;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class CorrelationReq extends BasePerformanceReq<CorrelationParams> {
+    // 滚动窗口
+    private Integer rollingWindow;
+    // 步长
+    private Integer step;
+
+    @Override
+    public CorrelationParams convert() {
+        return BeanUtil.copyProperties(this, CorrelationParams.class);
+    }
+}

+ 16 - 0
src/main/java/com/smppw/analysis/application/dto/performance/DrawdownTrendReq.java

@@ -0,0 +1,16 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.smppw.analysis.domain.dto.performance.TrendParams;
+import com.smppw.common.pojo.enums.TrendType;
+
+public class DrawdownTrendReq extends BasePerformanceReq<TrendParams> {
+    @Override
+    public TrendParams convert() {
+        TrendParams params = BeanUtil.copyProperties(this, TrendParams.class);
+        params.setTrendTypes(ListUtil.toList(TrendType.DrawdownTrend, TrendType.ExtraDrawdownTrend));
+        params.setIndexTrendTypes(ListUtil.toList(TrendType.DrawdownTrend));
+        return params;
+    }
+}

+ 30 - 0
src/main/java/com/smppw/analysis/application/dto/performance/ImfTrendReq.java

@@ -0,0 +1,30 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.smppw.analysis.domain.dto.performance.TrendParams;
+import com.smppw.common.pojo.enums.TrendType;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 15:48
+ * @description 货币型基金业绩走势图接口请求参数
+ */
+@Setter
+@Getter
+public class ImfTrendReq extends BasePerformanceReq<TrendParams> {
+    @Override
+    public TrendParams convert() {
+        List<TrendType> trendTypes = ListUtil.toList(TrendType.Ret, TrendType.Nav, TrendType.ExtraNav, TrendType.OrigNav,
+                TrendType.NetValueChange, TrendType.ExtraRetGeo);
+        List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.Ret, TrendType.OrigNav);
+        TrendParams params = BeanUtil.copyProperties(this, TrendParams.class);
+        params.setTrendTypes(trendTypes);
+        params.setIndexTrendTypes(indexTrendTypes);
+        return params;
+    }
+}

+ 24 - 0
src/main/java/com/smppw/analysis/application/dto/performance/IndicatorReq.java

@@ -0,0 +1,24 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.smppw.analysis.domain.dto.performance.IndicatorParams;
+import com.smppw.common.pojo.enums.Indicator;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class IndicatorReq extends BasePerformanceReq<IndicatorParams> {
+    private String riskOfFreeId;
+    private Double riskOfFreeValue;
+    private Boolean calcExtraRet;
+
+    @Override
+    public IndicatorParams convert() {
+        IndicatorParams params = BeanUtil.copyProperties(this, IndicatorParams.class);
+        params.setIndicators(ListUtil.toList(Indicator.INDICATOR_TYPE_ARRAY));
+        params.setExtraIndicators(ListUtil.toList(Indicator.RISK_TABLE_EXCESS_INDICATOR_ARRAY));
+        return params;
+    }
+}

+ 20 - 0
src/main/java/com/smppw/analysis/application/dto/performance/IntervalReq.java

@@ -0,0 +1,20 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.IntervalParams;
+import com.smppw.common.pojo.enums.Indicator;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class IntervalReq extends BasePerformanceReq<IntervalParams> {
+    private Indicator indicator;
+
+    private Boolean excess = false;
+
+    @Override
+    public IntervalParams convert() {
+        return BeanUtil.copyProperties(this, IntervalParams.class);
+    }
+}

+ 21 - 0
src/main/java/com/smppw/analysis/application/dto/performance/RankReq.java

@@ -0,0 +1,21 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.RankParams;
+import com.smppw.common.pojo.enums.Indicator;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class RankReq extends BasePerformanceReq<RankParams> {
+    /**
+     * 选择的指标
+     */
+    private Indicator indicator;
+
+    @Override
+    public RankParams convert() {
+        return BeanUtil.copyProperties(this, RankParams.class);
+    }
+}

+ 28 - 0
src/main/java/com/smppw/analysis/application/dto/performance/RevenueReq.java

@@ -0,0 +1,28 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.RevenueParams;
+import com.smppw.common.pojo.enums.Frequency;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class RevenueReq extends BasePerformanceReq<RevenueParams> {
+    // 1-收益统计,2-收益分布
+    private String revenuType;
+
+    // 是否计算超额
+    private Boolean ifExcessReturn = false;
+
+    // 滚动频率,周、月、季度和年度
+    private Frequency rollingFrequency;
+
+    // 组距,收益分布图表支持用户自定义,收益分布必传参数,可以提供默认值为6
+    private String space;
+
+    @Override
+    public RevenueParams convert() {
+        return BeanUtil.copyProperties(this, RevenueParams.class);
+    }
+}

+ 20 - 0
src/main/java/com/smppw/analysis/application/dto/performance/RollingReq.java

@@ -0,0 +1,20 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.RollingParams;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.Indicator;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class RollingReq extends BasePerformanceReq<RollingParams> {
+    private Indicator indicator;
+    private Frequency rollingFrequency;
+
+    @Override
+    public RollingParams convert() {
+        return BeanUtil.copyProperties(this, RollingParams.class);
+    }
+}

+ 25 - 0
src/main/java/com/smppw/analysis/application/dto/performance/TrendReq.java

@@ -0,0 +1,25 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.smppw.analysis.domain.dto.performance.TrendParams;
+import com.smppw.common.pojo.enums.TrendType;
+
+import java.util.List;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 11:15
+ * @description 业绩走势接口请求参数
+ */
+public class TrendReq extends BasePerformanceReq<TrendParams> {
+    @Override
+    public TrendParams convert() {
+        List<TrendType> trendTypes = ListUtil.toList(TrendType.Ret, TrendType.Nav, TrendType.ExtraNav, TrendType.OrigNav,
+                TrendType.ExtraRetAri, TrendType.NetValueChange, TrendType.ExtraRetGeo, TrendType.DrawdownTrend);
+        TrendParams params = BeanUtil.copyProperties(this, TrendParams.class);
+        params.setTrendTypes(trendTypes);
+        params.setIndexTrendTypes(ListUtil.toList(TrendType.Ret, TrendType.OrigNav));
+        return params;
+    }
+}

+ 20 - 0
src/main/java/com/smppw/analysis/application/dto/performance/WinReq.java

@@ -0,0 +1,20 @@
+package com.smppw.analysis.application.dto.performance;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.smppw.analysis.domain.dto.performance.WinParams;
+import com.smppw.analysis.infrastructure.consts.WinRateBmk;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class WinReq extends BasePerformanceReq<WinParams> {
+    private WinRateBmk winRateBmk;
+    private String lower;
+    private String upper;
+
+    @Override
+    public WinParams convert() {
+        return BeanUtil.copyProperties(this, WinParams.class);
+    }
+}

+ 105 - 0
src/main/java/com/smppw/analysis/application/service/info/FundInfoService.java

@@ -0,0 +1,105 @@
+package com.smppw.analysis.application.service.info;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import com.smppw.analysis.application.dto.info.*;
+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.BaseInfoService;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.common.pojo.enums.TimeRange;
+import com.smppw.constants.Consts;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.Map;
+
+@Service
+public class FundInfoService {
+    private final PerformanceFactory factory;
+    private final BaseInfoService baseInfoService;
+
+    public FundInfoService(PerformanceFactory factory, BaseInfoService baseInfoService) {
+        this.factory = factory;
+        this.baseInfoService = baseInfoService;
+    }
+
+    public PrivatelyFundHeadInfoVO headInfo(HeadInfoReq params) {
+        return new PrivatelyFundHeadInfoVO();
+    }
+
+    public CommonInfoVO commonInfo(CommonInfoReq params) {
+//        CommonInfoVO res = new CommonInfoVO();
+//        IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
+//        String secId = params.getSecId();
+//        Byte raiseType = null;
+//        List<Frequency> result = CollectionUtil.newArrayList();
+//        String fundType = this.baseInfoService.getFundType(secId);
+//        List<IStrategy> originStrategy = CollectionUtil.newArrayList();
+//        // 获取频率
+//        CmBigDataFundInfoDo fundHeadInfo = fundHeadInfoBaseService.getFundHeadInfo(secId);
+//        if (fundHeadInfo == null) {
+//            throw new APIException("");
+//        }
+//        raiseType = fundHeadInfo.getRaiseType();
+//        Frequency navFrequency = fundInformationDao.getNavFrequency(secId);
+//        result.add(navFrequency);
+//        // 将频率转换一道 取最小频率
+//        List<Frequency> frequencies = fundInformationDao.toFrequencyList(result);
+//        if (raiseType == 2) {
+//            frequencies.removeIf(p -> p.getId() == Frequency.Default.getId());
+//        }
+//        List<ValueLabelVO> frequencyValueLabel = trans2ValueLabel(frequencies);
+//        res.setFrequency(frequencyValueLabel);
+//        // 净值类型
+//        List<ValueLabelVO> navType = Arrays.stream(NavType.values())
+//                .filter(p -> !NavType.All.equals(p) && !NavType.UnitAndCumulativeNav.equals(p))
+//                .map(p -> new ValueLabelVO(p.name(), p.getDesc())).collect(Collectors.toList());
+//        res.setNavType(navType);
+//        // 策略曲线
+//        RaiseType realRaiseType = RaiseType.getRaiseType(raiseType);
+//        handleTimeRange(strategy, res, secId, companyOrManager, realRaiseType);
+//        // 获取常用指数
+////        List<ValueLabelVO> benchmarkList = userCommonIndexService.getByUser(-1);
+////        handleBenchmark(strategy, res, secId, fundType, originStrategy, companyOrManager, benchmarkList);
+        return new CommonInfoVO();
+    }
+
+    @SuppressWarnings("unchecked")
+    public HeadIndicatorVO headIndicator(HeadIndicatorReq req) {
+        // 构建参数体
+        IndicatorParams params = this.prepareParams(req);
+        Performance<IndicatorParams, Map<String, Object>> instance = this.factory.getInstance(PerformanceConstants.INDICATOR);
+        Map<String, Object> dataset = instance.execute(params);
+        Map<String, Object> indicatorMap = MapUtil.get(dataset, req.getSecId(), Map.class);
+        HeadIndicatorVO vo = new HeadIndicatorVO();
+        vo.setAnnualReturn(MapUtil.getStr(indicatorMap, Indicator.AnnualReturn.name()));
+        vo.setAnnualStdDev(MapUtil.getStr(indicatorMap, Indicator.AnnualStdDev.name()));
+        vo.setMaxDrawdown(MapUtil.getStr(indicatorMap, Indicator.MaxDrawdown.name()));
+        vo.setSharpeRatio(MapUtil.getStr(indicatorMap, Indicator.SharpeRatio.name()));
+        return vo;
+    }
+
+    private IndicatorParams prepareParams(HeadIndicatorReq req) {
+        IndicatorParams params = new IndicatorParams();
+        params.setSecIds(CollectionUtil.newArrayList());
+        params.setRefIds(CollectionUtil.newArrayList(req.getSecId()));
+        params.setBenchmarkId(Consts.BENCHMARK);
+        params.setNavType(req.getNavType());
+        params.setRaiseType(req.getRaiseType());
+        params.setStrategy(req.getStrategy());
+        params.setCalcExtraRet(false);
+        params.setRiskOfFreeId(Consts.RISK_OF_FREE);
+        params.setTimeRange(TimeRange.FromSetup);
+        params.setFrequency(req.getFrequency());
+        params.setStartDate(Consts.START_DATE);
+        params.setEndDate(DateUtil.formatDate(new Date()));
+        params.setIndicators(ListUtil.of(Indicator.AnnualReturn, Indicator.AnnualStdDev, Indicator.MaxDrawdown, Indicator.SharpeRatio));
+        params.setExtraIndicators(ListUtil.of(Indicator.IntervalReturn));
+        return params;
+    }
+}

+ 0 - 57
src/main/java/com/smppw/analysis/application/service/performance/CommonService.java

@@ -1,57 +0,0 @@
-package com.smppw.analysis.application.service.performance;
-
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.map.MapUtil;
-import com.smppw.analysis.domain.dto.performance.HeadIndicatorParams;
-import com.smppw.analysis.domain.dto.performance.IndicatorParams;
-import com.smppw.common.pojo.enums.Indicator;
-import com.smppw.common.pojo.enums.TimeRange;
-import com.smppw.constants.Consts;
-import org.springframework.stereotype.Service;
-
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
-@Service
-public class CommonService {
-    private final PerformanceService performanceService;
-
-    public CommonService(PerformanceService performanceService) {
-        this.performanceService = performanceService;
-    }
-
-    public Map<String, Object> getIndicator(HeadIndicatorParams params) {
-        Map<String, Object> res = MapUtil.newHashMap();
-        // 构建参数体
-        IndicatorParams param = prepareParams(params);
-        List<Indicator> indicators = ListUtil.of(Indicator.AnnualReturn, Indicator.AnnualStdDev, Indicator.MaxDrawdown, Indicator.SharpeRatio);
-        List<Indicator> geoIndicators = ListUtil.of(Indicator.IntervalReturn);
-        Map<String, Object> dataset = performanceService.calcIndicators(param, indicators, geoIndicators);
-        Map<String, Object> indicatorMap = MapUtil.get(dataset, params.getSecId(), Map.class);
-        res.put(Indicator.AnnualReturn.name(), indicatorMap.get(Indicator.AnnualReturn.name()));
-        res.put(Indicator.AnnualStdDev.name(), indicatorMap.get(Indicator.AnnualStdDev.name()));
-        res.put(Indicator.MaxDrawdown.name(), indicatorMap.get(Indicator.MaxDrawdown.name()));
-        res.put(Indicator.SharpeRatio.name(), indicatorMap.get(Indicator.SharpeRatio.name()));
-        return res;
-    }
-
-    private IndicatorParams prepareParams(HeadIndicatorParams params) {
-        IndicatorParams rateRiskIndicatorParams = new IndicatorParams();
-        rateRiskIndicatorParams.setSecIds(CollectionUtil.newArrayList());
-        rateRiskIndicatorParams.setRefIds(CollectionUtil.newArrayList(params.getSecId()));
-        rateRiskIndicatorParams.setBenchmarkId(Consts.BENCHMARK);
-        rateRiskIndicatorParams.setNavType(params.getNavType());
-        rateRiskIndicatorParams.setRaiseType(params.getRaiseType());
-        rateRiskIndicatorParams.setStrategy(params.getStrategy().getStrategyOriginName());
-        rateRiskIndicatorParams.setCalcExtraRet(false);
-        rateRiskIndicatorParams.setRiskOfFreeId(Consts.RISK_OF_FREE);
-        rateRiskIndicatorParams.setTimeRange(TimeRange.FromSetup);
-        rateRiskIndicatorParams.setFrequency(params.getFrequency());
-        rateRiskIndicatorParams.setStartDate(Consts.START_DATE);
-        rateRiskIndicatorParams.setEndDate(DateUtil.formatDate(new Date()));
-        return rateRiskIndicatorParams;
-    }
-}

+ 80 - 0
src/main/java/com/smppw/analysis/application/service/performance/FundPerformanceService.java

@@ -0,0 +1,80 @@
+package com.smppw.analysis.application.service.performance;
+
+import com.smppw.analysis.application.dto.performance.*;
+import com.smppw.analysis.domain.dto.performance.*;
+import com.smppw.analysis.domain.manager.performance.Performance;
+import com.smppw.analysis.domain.manager.performance.PerformanceFactory;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+import static com.smppw.analysis.domain.manager.performance.PerformanceConstants.*;
+
+@Service
+public class FundPerformanceService {
+    private final PerformanceFactory factory;
+
+    public FundPerformanceService(PerformanceFactory factory) {
+        this.factory = factory;
+    }
+
+    public Map<String, Object> calcIndicator(IndicatorReq req) {
+        IndicatorParams params = req.convert();
+        Performance<IndicatorParams, Map<String, Object>> instance = this.factory.getInstance(INDICATOR);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> trend(TrendReq req) {
+        TrendParams params = req.convert();
+        Performance<TrendParams, Map<String, Object>> instance = this.factory.getInstance(TREND);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> dynamicDown(DrawdownTrendReq req) {
+        TrendParams params = req.convert();
+        Performance<TrendParams, Map<String, Object>> instance = this.factory.getInstance(TREND);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> cor(CorrelationReq req) {
+        CorrelationParams params = req.convert();
+        Performance<CorrelationParams, Map<String, Object>> instance = this.factory.getInstance(CORRELATION);
+        return instance.execute(params);
+    }
+
+    public WinVO win(WinReq req) {
+        WinParams params = req.convert();
+        Performance<WinParams, WinVO> instance = this.factory.getInstance(WIN);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> revenue(RevenueReq req) {
+        RevenueParams params = req.convert();
+        Performance<RevenueParams, Map<String, Object>> instance = this.factory.getInstance(CORRELATION);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> imfTrend(ImfTrendReq req) {
+        TrendParams params = req.convert();
+        Performance<TrendParams, Map<String, Object>> instance = this.factory.getInstance(IMF);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> interval(IntervalReq req) {
+        IntervalParams params = req.convert();
+        Performance<IntervalParams, Map<String, Object>> instance = this.factory.getInstance(INTERVAL);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> rolling(RollingReq req) {
+        RollingParams params = req.convert();
+        Performance<RollingParams, Map<String, Object>> instance = this.factory.getInstance(ROLLING);
+        return instance.execute(params);
+    }
+
+    public Map<String, Object> rank(RankReq req) {
+        RankParams params = req.convert();
+        Performance<RankParams, Map<String, Object>> instance = this.factory.getInstance(ROLLING);
+        return instance.execute(params);
+    }
+}

+ 12 - 0
src/main/java/com/smppw/analysis/application/service/performance/MultiPerformanceService.java

@@ -0,0 +1,12 @@
+package com.smppw.analysis.application.service.performance;
+
+import org.springframework.stereotype.Service;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 16:52
+ * @description 多标的的业绩表现
+ */
+@Service
+public class MultiPerformanceService {
+}

+ 0 - 390
src/main/java/com/smppw/analysis/application/service/performance/PerformanceService.java

@@ -1,390 +0,0 @@
-package com.smppw.analysis.application.service.performance;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.collection.ListUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.NumberUtil;
-import cn.hutool.core.util.StrUtil;
-import com.smppw.analysis.domain.dto.performance.BaseParams;
-import com.smppw.analysis.domain.dto.performance.IndicatorParams;
-import com.smppw.analysis.domain.dto.performance.TrendParams;
-import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
-import com.smppw.common.pojo.IStrategy;
-import com.smppw.common.pojo.dto.calc.IndicatorCalcIndexDataDto;
-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.constants.Consts;
-import com.smppw.core.reta.calc.PerformanceConsistency;
-import com.smppw.utils.StrategyHandleUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.BinaryOperator;
-import java.util.stream.Collectors;
-
-@Service
-public class PerformanceService {
-    private final Logger logger = LoggerFactory.getLogger(PerformanceService.class);
-    private final BaseIndicatorServiceV2 baseIndicatorServiceV2;
-
-    public PerformanceService(BaseIndicatorServiceV2 baseIndicatorServiceV2) {
-        this.baseIndicatorServiceV2 = baseIndicatorServiceV2;
-    }
-
-    public Map<String, Object> calcIndicators(IndicatorParams params) {
-        return this.calcIndicators(params, ListUtil.toList(Indicator.INDICATOR_TYPE_ARRAY), ListUtil.toList(Indicator.RISK_TABLE_EXCESS_INDICATOR_ARRAY));
-    }
-
-    public Map<String, Object> calcIndicators(IndicatorParams params, List<Indicator> indicators, List<Indicator> geoIndicators) {
-        try {
-            // 1.参数处理
-            this.checkParams(params);
-            List<String> refIds = params.getRefIds();
-            List<String> secIds = this.getSecIdsByParams(params);
-            // 差集求指数id集合,包括基�
-            List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-            String riskOfFreeId = params.getRiskOfFreeId();
-            Double riskOfFreeValue = params.getRiskOfFreeValue();
-            if (StrUtil.isBlank(riskOfFreeId)) {
-                riskOfFreeId = Consts.RISK_OF_FREE;
-            } else if (NumberUtil.isNumber(riskOfFreeId)) {
-                riskOfFreeValue = Double.parseDouble(riskOfFreeId);
-                riskOfFreeId = null;
-            }
-            CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, geoIndicators, DateIntervalType.CustomInterval, null);
-            req.setRiskOfFreeId(riskOfFreeId);
-            req.setRiskOfFreeValue(riskOfFreeValue);
-
-            // 2.指标计算
-            Map<String, List<IndicatorCalcPropertyDto>> indicator = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-
-            // 3.返回结果处理
-            Map<String, Object> valuesMap = MapUtil.newHashMap(true);
-            Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
-            for (String refId : refIds) {
-                IndicatorCalcPropertyDto dto = Optional.ofNullable(indicator.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
-                // 标的指标
-                Map<String, String> indicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getIndicatorValueMap).orElse(MapUtil.empty());
-                // 标的几何指标
-                Map<String, String> geoIndicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getExtraGeoIndicatorValueMap).orElse(MapUtil.empty());
-                // 指数指标,包括基�
-                Map<String, Map<String, String>> indexIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).orElse(MapUtil.empty());
-                // 指数几何指标
-                Map<String, Map<String, String>> indexGeoIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexGeoExtraIndicatorValueMap).orElse(MapUtil.empty());
-                // 标的和指数分别处理最大回撤指标,并合并指标结果到一个map�
-                Map<String, String> values = this.handleMaxDrawdown(indicatorValues, refId, null, false);
-                Map<String, String> geoValues = this.handleMaxDrawdown(geoIndicatorValues, refId, null, true);
-                Map<String, String> unionValues = MapUtil.<String, String>builder().putAll(values).putAll(geoValues).build();
-                valuesMap.put(refId, unionValues);
-                for (String indexId : indexIds) {
-                    if (indexValuesMap.containsKey(indexId)) {
-                        continue;
-                    }
-                    Map<String, String> indexValues = this.handleMaxDrawdown(indexIndicatorValuesMap.get(indexId), indexId, null, false);
-                    Map<String, String> indexGeoValues = this.handleMaxDrawdown(indexGeoIndicatorValuesMap.get(indexId), indexId, params.getBenchmarkId(), true);
-                    Map<String, String> unionIndexValues = MapUtil.<String, String>builder().putAll(indexValues).putAll(indexGeoValues).build();
-                    indexValuesMap.put(indexId, unionIndexValues);
-                }
-            }
-
-            // 返回结果对象构建
-            return MapUtil.builder(valuesMap).putAll(indexValuesMap).build();
-        } catch (Exception e) {
-            e.printStackTrace();
-            logger.error(String.format("基金收益风险指标计算错误:%s", e.getMessage()));
-        }
-        return MapUtil.newHashMap();
-    }
-
-    public Map<String, Object> trend(TrendParams params) {
-        List<TrendType> trendTypes = ListUtil.toList(TrendType.Ret, TrendType.Nav, TrendType.ExtraNav, TrendType.OrigNav,
-                TrendType.ExtraRetAri, TrendType.NetValueChange, TrendType.ExtraRetGeo, TrendType.DrawdownTrend);
-        List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.Ret, TrendType.OrigNav);
-        return this.handleTrends(params, trendTypes, indexTrendTypes);
-    }
-
-    public Map<String, Object> dynamicDown(TrendParams params) {
-        List<TrendType> trendTypes = ListUtil.toList(TrendType.DrawdownTrend, TrendType.ExtraDrawdownTrend);
-        List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.DrawdownTrend);
-        return this.handleTrends(params, trendTypes, indexTrendTypes);
-    }
-
-    public Map<String, Object> handleTrends(TrendParams params, List<TrendType> trendTypes, List<TrendType> indexTrendTypes) {
-        // 1、参数处理
-        this.checkParams(params);
-        List<String> refIds = params.getRefIds();
-        List<String> secIds = this.getSecIdsByParams(params);
-        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-
-        // 时段参数构建
-        DateIntervalDto dateInterval = this.buildDateIntervalByParams(params, DateIntervalType.CustomInterval, null);
-        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
-        for (String refId : refIds) {
-            if (StrUtil.isBlank(params.getBenchmarkId())) {
-                continue;
-            }
-            benchmarkIdMap.put(refId, params.getBenchmarkId());
-        }
-
-        // 计算走势图
-        Map<String, List<IndicatorCalcPropertyDto>> trendMap = this.baseIndicatorServiceV2.getMultipleSecTrend(refIds, benchmarkIdMap,
-                indexIds, dateInterval, params.getFrequency(), null, null, params.getRaiseType(), this.getOriginStrategy(params),
-                Visibility.Both, params.getNavType(), trendTypes);
-
-        // 结果处理,支持多标的
-        // 处理走势图
-        Map<String, List<Map<String, Object>>> dataListMap = MapUtil.newHashMap(true);
-        Map<String, List<Map<String, Object>>> indexDataListMap = MapUtil.newHashMap(true);
-        Map<String, Map<TrendType, List<Double>>> trendListMap = MapUtil.newHashMap(true);
-        for (String refId : refIds) {
-            IndicatorCalcPropertyDto dto = Optional.ofNullable(trendMap.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
-            List<String> tempDateList = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getDateList).orElse(ListUtil.empty());
-            // 基金走势序列
-            Map<TrendType, List<Double>> trendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getTrendValueMap).orElse(MapUtil.empty());
-            trendListMap.put(refId, trendTypeListMap);
-            dataListMap.put(refId, this.buildDateValue(tempDateList, trendTypeListMap, trendTypes));
-            // 指数净值和收益序列
-            Map<String, Map<TrendType, List<Double>>> tempIndexTrendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexTrendValueMap).orElse(MapUtil.empty());
-            for (String indexId : indexIds) {
-                if (indexDataListMap.containsKey(indexId) && !indexId.equals(params.getBenchmarkId())) {
-                    continue;
-                }
-                indexDataListMap.put(indexId, this.buildDateValue(tempDateList, tempIndexTrendTypeListMap.get(indexId), indexTrendTypes));
-            }
-        }
-        Map<String, List<Map<String, Object>>> dataset = MapUtil.<String, List<Map<String, Object>>>builder().putAll(dataListMap).build();
-        Map<String, Object> extInfos = MapUtil.<String, Object>builder().put("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
-        for (String refId : refIds) {
-            Map<TrendType, List<Double>> trendTypeListMap = trendListMap.getOrDefault(refId, MapUtil.empty());
-            Double maxDown = this.handleMaxAndMin(trendTypeListMap.get(TrendType.DrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
-            Double maxExtraDown = this.handleMaxAndMin(trendTypeListMap.get(TrendType.ExtraDrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
-            Map<String, Object> data = MapUtil.<String, Object>builder().put("maxDown", maxDown).put("maxExtraDown", maxExtraDown).build();
-            extInfos.put(refId, data);
-        }
-        return MapUtil.<String, Object>builder().put("dataset", dataset).putAll(extInfos).build();
-    }
-
-    /**
-     * 构建指标计算参数
-     *
-     * @param params          接口请求参数
-     * @param indicators      要计算的普通指标
-     * @param geoIndicators   geo指标
-     * @param dateIntervalMap 时段
-     * @param <P>             类型参数
-     * @return /
-     */
-    private <P extends BaseParams> CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(P params, List<Indicator> indicators, List<Indicator> geoIndicators, Map<String, List<DateIntervalDto>> dateIntervalMap) {
-        List<String> refIds = params.getRefIds();
-        List<String> secIds = this.getSecIdsByParams(params);
-        // 差集求指数id集合,包括基准
-        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
-        for (String refId : refIds) {
-            if (StrUtil.isBlank(params.getBenchmarkId())) {
-                continue;
-            }
-            benchmarkIdMap.put(refId, params.getBenchmarkId());
-        }
-        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
-                .mainSecIdList(refIds)
-                .secBenchmarkIdMap(benchmarkIdMap)
-                .indexIdList(indexIds)
-                .raiseType(params.getRaiseType())
-                .strategy(this.getOriginStrategy(params))
-                .visibility(Visibility.Both)
-                .dataFrequency(params.getFrequency())
-                .navType(params.getNavType())
-                .secDateIntervalDtoListMap(dateIntervalMap)
-                .indicatorList(indicators)
-                .geoExtraindicatorList(geoIndicators)
-                .ifAnnualize(true)
-                .calcIndexRetIndicatorValue(true)
-                .ifConvertPerformanceConsistencyWord(true).build();
-    }
-
-    /**
-     * 构建指标计算请求参数
-     *
-     * @param params           /
-     * @param indicatorList    要计算的普通指标列表
-     * @param geoIndicatorList 几何指标列表
-     * @param dateIntervalType /
-     * @param frequency        /
-     * @param <P>              /
-     * @return /
-     */
-    protected <P extends BaseParams> CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(P params, List<Indicator> indicatorList, List<Indicator> geoIndicatorList,
-                                                                                               DateIntervalType dateIntervalType, Frequency frequency) {
-        List<String> refIds = params.getRefIds();
-        DateIntervalDto dateInterval = this.buildDateIntervalByParams(params, dateIntervalType, frequency);
-        Map<String, List<DateIntervalDto>> dateIntervalMap = MapUtil.newHashMap(true);
-        for (String refId : refIds) {
-            dateIntervalMap.put(refId, ListUtil.toList(dateInterval));
-        }
-        return this.buildCalcReq(params, indicatorList, geoIndicatorList, dateIntervalMap);
-    }
-
-    /**
-     * 根据请求参数构建 DateIntervalDto 对象
-     *
-     * @param params           请求参数,需继承 CommonParams
-     * @param dateIntervalType 时段类型
-     * @param frequency        接口传递的频率,一般为滚动计算时传递的滚动频率
-     * @param <P>              参数类型
-     * @return /
-     */
-    protected <P extends BaseParams> DateIntervalDto buildDateIntervalByParams(P params, DateIntervalType dateIntervalType, Frequency frequency) {
-        if (dateIntervalType == null) {
-            dateIntervalType = DateIntervalType.DefaultInterval;
-        }
-        if (frequency == null) {
-            frequency = params.getFrequency();
-        }
-        return DateIntervalDto.builder()
-                .id(dateIntervalType.name())
-                .startDate(params.getStartDate())
-                .endDate(params.getEndDate())
-                .timeRange(params.getTimeRange())
-                .dateIntervalType(dateIntervalType)
-                .frequency(frequency).build();
-    }
-
-
-    /**
-     * 策略枚举,从字符串转换。实现类太多不能自动转换需特殊处理
-     */
-    protected <P extends BaseParams> IStrategy getOriginStrategy(P params) {
-        return StrategyHandleUtils.getStrategy(params.getStrategy());
-    }
-
-    /**
-     * 公共参数检验,部分参数为空时设置默认值.
-     *
-     * @param params 请求参数
-     * @param <P>    类型参数
-     */
-    protected <P extends BaseParams> void checkParams(P params) {
-        if (params.getRefIds() == null || params.getRefIds().isEmpty()) {
-            throw new RuntimeException("refIds 参数不能为空");
-        }
-        if (StrUtil.isBlank(params.getStartDate()) && StrUtil.isBlank(params.getEndDate())) {
-            throw new RuntimeException("时段不能为空");
-        }
-        if (params.getNavType() == null) {
-            logger.warn(String.format("navType 为null, 设置一个初始值:%s", NavType.CumulativeNav));
-            params.setNavType(NavType.CumulativeNav);
-        }
-        if (params.getFrequency() == null) {
-            logger.warn(String.format("frequency 为null, 设置一个初始值:%s", Frequency.Daily));
-            params.setFrequency(Frequency.Daily);
-        }
-    }
-
-    /**
-     * 从请求参数中获取所有标的并集集合
-     *
-     * @param params 公共请求参数
-     * @param <P>    类型
-     * @return /
-     */
-    protected <P extends BaseParams> List<String> getSecIdsByParams(P params) {
-        List<String> tempList = ListUtil.list(true);
-        tempList.addAll(params.getRefIds());
-        if (StrUtil.isNotBlank(params.getBenchmarkId())) {
-            tempList.add(params.getBenchmarkId());
-        }
-        return params.getSecIds() == null ? tempList : CollUtil.addAllIfNotContains(tempList, params.getSecIds());
-    }
-
-    /**
-     * 处理最大回撤问题,是否已恢复
-     *
-     * @param indicatorValues 指标结果
-     * @param secId           标的id
-     * @param benchmarkId     基准
-     * @param geo             是否处理geo几何指标
-     * @return 新map
-     */
-    protected Map<String, String> handleMaxDrawdown(Map<String, String> indicatorValues, String secId, String benchmarkId, boolean geo) {
-        Map<String, String> result = MapUtil.newHashMap();
-        String maxDrawdown = indicatorValues.get(Indicator.MaxDrawdown.name());
-        String consistency = indicatorValues.get(Indicator.PerformanceConsistency.name());
-        if (StrUtil.isNotBlank(maxDrawdown) && new BigDecimal(maxDrawdown).compareTo(BigDecimal.ZERO) > 0) {
-            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureDate.name()))) {
-                indicatorValues.put(Indicator.MaxDrawdownRecureDate.name(), "最大回撤未修复");
-            }
-            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureIntervalDays.name()))) {
-                indicatorValues.put(Indicator.MaxDrawdownRecureIntervalDays.name(), "最大回撤未修复");
-            }
-            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureInterval.name()))) {
-                indicatorValues.put(Indicator.MaxDrawdownRecureInterval.name(), "最大回撤未修复");
-            }
-        }
-        if (StrUtil.isEmpty(consistency)) {
-            indicatorValues.put(Indicator.PerformanceConsistency.name(), PerformanceConsistency.convert2Word(null));
-        } else {
-            indicatorValues.put(Indicator.PerformanceConsistency.name(), PerformanceConsistency.convert2Word(Double.parseDouble(consistency)));
-        }
-        if (geo) {
-            indicatorValues.forEach((k, v) -> result.put("geoExcess" + k, secId != null && secId.equals(benchmarkId) ? null : v));
-        } else {
-            result.putAll(indicatorValues);
-        }
-        return result;
-    }
-
-    /**
-     * 构建日期值对象
-     *
-     * @param dateList         日期序列
-     * @param trendTypeListMap 走势图数据
-     * @param trendTypes       走势图类型列表
-     * @return /
-     */
-    private List<Map<String, Object>> buildDateValue(List<String> dateList, Map<TrendType, List<Double>> trendTypeListMap, List<TrendType> trendTypes) {
-        List<Map<String, Object>> dataList = ListUtil.list(true);
-        for (int i = 0; i < dateList.size(); i++) {
-            Map<String, Object> temp = MapUtil.<String, Object>builder("date", dateList.get(i)).build();
-            for (TrendType trendType : trendTypes) {
-                List<Double> doubles = trendTypeListMap.get(trendType);
-                Object value = null;
-                try {
-                    value = i <= doubles.size() ? doubles.get(i) : null;
-                } catch (Exception ignored) {
-                }
-                temp.put(StrUtil.toCamelCase(trendType.name()), value);
-            }
-            dataList.add(temp);
-        }
-        return dataList;
-    }
-
-    /**
-     * 利用jdk8的流操作计算最大最小值
-     *
-     * @param dataList 待计算的数据序列
-     * @param operator 求最大还最小值的操作函数
-     * @return /
-     */
-    private Double handleMaxAndMin(List<Double> dataList, BinaryOperator<Double> operator) {
-        if (dataList == null || dataList.isEmpty()) {
-            return 0d;
-        }
-        List<Double> collect = dataList.stream().filter(Objects::nonNull).collect(Collectors.toList());
-        if (collect.isEmpty()) {
-            return 0d;
-        }
-        return collect.stream().reduce(operator).orElse(0d);
-    }
-}

+ 3 - 3
src/main/java/com/smppw/analysis/application/service/position/FuturePositionAnalysis.java

@@ -9,7 +9,7 @@ import com.smppw.analysis.domain.dto.position.future.MarginalRiskContributionPar
 import com.smppw.analysis.domain.dto.position.future.MarginalRiskContributionVO;
 import com.smppw.analysis.domain.manager.position.BizHandler;
 import com.smppw.analysis.domain.manager.position.BizHandlerConstants;
-import com.smppw.analysis.domain.manager.position.BizHandlerFactor;
+import com.smppw.analysis.domain.manager.position.BizHandlerFactory;
 import com.smppw.common.pojo.FundFuturesOption;
 import org.springframework.stereotype.Component;
 
@@ -25,9 +25,9 @@ import java.util.stream.Collectors;
  */
 @Component
 public class FuturePositionAnalysis {
-    private final BizHandlerFactor factor;
+    private final BizHandlerFactory factor;
 
-    public FuturePositionAnalysis(BizHandlerFactor factor) {
+    public FuturePositionAnalysis(BizHandlerFactory factor) {
         this.factor = factor;
     }
 

+ 3 - 3
src/main/java/com/smppw/analysis/application/service/position/StockPositionAnalysis.java

@@ -7,7 +7,7 @@ import cn.hutool.core.map.MapUtil;
 import com.smppw.analysis.domain.dto.position.*;
 import com.smppw.analysis.domain.dto.position.stock.*;
 import com.smppw.analysis.domain.manager.position.BizHandler;
-import com.smppw.analysis.domain.manager.position.BizHandlerFactor;
+import com.smppw.analysis.domain.manager.position.BizHandlerFactory;
 import com.smppw.analysis.domain.manager.position.stock.BarraSensitivityComponent;
 import com.smppw.analysis.domain.manager.position.stock.IndustryAllocationPreferenceComponent;
 import com.smppw.analysis.domain.dao.PubliclyFundPositionDao;
@@ -42,13 +42,13 @@ public class StockPositionAnalysis {
         POSITION_NAME.put(-1L, "股票持仓");
     }
 
-    private final BizHandlerFactor factor;
+    private final BizHandlerFactory factor;
     private final BaseUnderlyingMapper baseUnderlyingMapper;
     private final BarraSensitivityComponent barraSensitivity;
     private final PubliclyFundPositionDao fundPositionBaseService;
     private final IndustryAllocationPreferenceComponent industryAllocationPreference;
 
-    public StockPositionAnalysis(BizHandlerFactor factor,
+    public StockPositionAnalysis(BizHandlerFactory factor,
                                  BaseUnderlyingMapper baseUnderlyingMapper,
                                  BarraSensitivityComponent barraSensitivity,
                                  PubliclyFundPositionDao fundPositionBaseService,

+ 3 - 3
src/main/java/com/smppw/analysis/application/service/position/SynthesizePositionAnalysis.java

@@ -11,7 +11,7 @@ import com.smppw.analysis.domain.dto.position.PositionConstants;
 import com.smppw.analysis.domain.dto.position.RefMarketValueRatio;
 import com.smppw.analysis.domain.dto.position.synthesize.*;
 import com.smppw.analysis.domain.manager.position.BizHandler;
-import com.smppw.analysis.domain.manager.position.BizHandlerFactor;
+import com.smppw.analysis.domain.manager.position.BizHandlerFactory;
 import com.smppw.analysis.domain.dao.PubliclyFundPositionDao;
 import com.smppw.analysis.domain.dataobject.PubliclyFundHolderInfoDO;
 import com.smppw.common.pojo.ValueLabelVO;
@@ -45,10 +45,10 @@ public class SynthesizePositionAnalysis {
         ASSET_TYPE_MAPPER.put(PositionConstants.ASSET_OTHER, PositionConstants.ASSET_OTHER_DESC);
     }
 
-    private final BizHandlerFactor factor;
+    private final BizHandlerFactory factor;
     private final PubliclyFundPositionDao fundPositionBaseService;
 
-    public SynthesizePositionAnalysis(BizHandlerFactor factor, PubliclyFundPositionDao fundPositionBaseService) {
+    public SynthesizePositionAnalysis(BizHandlerFactory factor, PubliclyFundPositionDao fundPositionBaseService) {
         this.factor = factor;
         this.fundPositionBaseService = fundPositionBaseService;
     }

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

@@ -1,5 +1,9 @@
 package com.smppw.analysis.client;
 
+import com.smppw.analysis.application.dto.info.*;
+import com.smppw.analysis.application.service.info.FundInfoService;
+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;
 
@@ -11,4 +15,24 @@ import org.springframework.web.bind.annotation.RestController;
 @RestController
 @RequestMapping("/v1/api/fund")
 public class FundApi {
+    private final FundInfoService service;
+
+    public FundApi(FundInfoService service) {
+        this.service = service;
+    }
+
+    @GetMapping("head-info")
+    public ResultVo<? extends HeadInfoVO> headInfo(HeadInfoReq params) {
+        return ResultVo.ok(this.service.headInfo(params));
+    }
+
+    @GetMapping("common-info")
+    public ResultVo<CommonInfoVO> commonInfo(CommonInfoReq params) {
+        return ResultVo.ok(this.service.commonInfo(params));
+    }
+
+    @GetMapping("head-indicator")
+    public ResultVo<HeadIndicatorVO> headIndicator(HeadIndicatorReq params) {
+        return ResultVo.ok(this.service.headIndicator(params));
+    }
 }

+ 58 - 20
src/main/java/com/smppw/analysis/client/FundPerformanceApi.java

@@ -1,10 +1,8 @@
 package com.smppw.analysis.client;
 
-import com.smppw.analysis.domain.dto.performance.HeadIndicatorParams;
-import com.smppw.analysis.domain.dto.performance.IndicatorParams;
-import com.smppw.analysis.domain.dto.performance.TrendParams;
-import com.smppw.analysis.application.service.performance.CommonService;
-import com.smppw.analysis.application.service.performance.PerformanceService;
+import com.smppw.analysis.application.dto.performance.*;
+import com.smppw.analysis.application.service.performance.FundPerformanceService;
+import com.smppw.analysis.domain.dto.performance.WinVO;
 import com.smppw.common.pojo.ResultVo;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -20,29 +18,69 @@ import java.util.Map;
 @RestController
 @RequestMapping("/v1/api/performance")
 public class FundPerformanceApi {
-    private final CommonService commonService;
-    private final PerformanceService performanceService;
+    private final FundPerformanceService service;
 
-    public FundPerformanceApi(CommonService commonService, PerformanceService performanceService) {
-        this.commonService = commonService;
-        this.performanceService = performanceService;
+    public FundPerformanceApi(FundPerformanceService service) {
+        this.service = service;
     }
 
-    @GetMapping("/indicator")
-    public ResultVo<Map<String, Object>> indicator(IndicatorParams params) {
-        Map<String, Object> data = this.performanceService.calcIndicators(params);
+    @GetMapping("indicator")
+    public ResultVo<Map<String, Object>> indicator(IndicatorReq req) {
+        Map<String, Object> data = this.service.calcIndicator(req);
         return ResultVo.ok(data);
     }
 
-    @GetMapping("/trend")
-    public ResultVo<Map<String, Object>> trend(TrendParams params) {
-        Map<String, Object> data = this.performanceService.trend(params);
+    @GetMapping("trend")
+    public ResultVo<Map<String, Object>> trend(TrendReq req) {
+        Map<String, Object> data = this.service.trend(req);
         return ResultVo.ok(data);
     }
 
-    @GetMapping("/head/indicator")
-    public ResultVo<Map<String, Object>> headIndicator(HeadIndicatorParams params) {
-        Map<String, Object> indicator = this.commonService.getIndicator(params);
-        return ResultVo.ok(indicator);
+    @GetMapping("imf-trend")
+    public ResultVo<Map<String, Object>> imfTrend(ImfTrendReq req) {
+        Map<String, Object> data = this.service.imfTrend(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("dynamic-down")
+    public ResultVo<Map<String, Object>> dynamicDown(DrawdownTrendReq req) {
+        Map<String, Object> data = this.service.dynamicDown(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("correlation")
+    public ResultVo<Map<String, Object>> cor(CorrelationReq req) {
+        Map<String, Object> data = this.service.cor(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("win")
+    public ResultVo<WinVO> win(WinReq req) {
+        WinVO data = this.service.win(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("revenue")
+    public ResultVo<Map<String, Object>> revenue(RevenueReq req) {
+        Map<String, Object> data = this.service.revenue(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("interval")
+    public ResultVo<Map<String, Object>> interval(IntervalReq req) {
+        Map<String, Object> data = this.service.interval(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("rolling")
+    public ResultVo<Map<String, Object>> rolling(RollingReq req) {
+        Map<String, Object> data = this.service.rolling(req);
+        return ResultVo.ok(data);
+    }
+
+    @GetMapping("rank")
+    public ResultVo<Map<String, Object>> rank(RankReq req) {
+        Map<String, Object> data = this.service.rank(req);
+        return ResultVo.ok(data);
     }
 }

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

@@ -2,8 +2,10 @@ package com.smppw.analysis.domain.dao;
 
 import com.smppw.analysis.domain.dataobject.FundFrequencyDo;
 import com.smppw.analysis.domain.dataobject.FundInformationDo;
+import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
 import com.smppw.analysis.infrastructure.persistence.FundFrequencyDoMapper;
 import com.smppw.analysis.infrastructure.persistence.FundInformationDoMapper;
+import com.smppw.analysis.infrastructure.persistence.MonetaryFundProfitMapper;
 import com.smppw.common.pojo.enums.Frequency;
 import org.springframework.stereotype.Component;
 
@@ -15,10 +17,14 @@ import java.util.Map;
 public class FundInformationDao {
     private final FundFrequencyDoMapper fundFrequencyDoMapper;
     private final FundInformationDoMapper fundInformationDoMapper;
+    private final MonetaryFundProfitMapper monetaryFundProfitMapper;
 
-    public FundInformationDao(FundFrequencyDoMapper fundFrequencyDoMapper, FundInformationDoMapper fundInformationDoMapper) {
+    public FundInformationDao(FundFrequencyDoMapper fundFrequencyDoMapper,
+                              FundInformationDoMapper fundInformationDoMapper,
+                              MonetaryFundProfitMapper monetaryFundProfitMapper) {
         this.fundFrequencyDoMapper = fundFrequencyDoMapper;
         this.fundInformationDoMapper = fundInformationDoMapper;
+        this.monetaryFundProfitMapper = monetaryFundProfitMapper;
     }
 
     public Map<String, Frequency> getNavFrequency(List<String> secIdList) {
@@ -45,4 +51,8 @@ public class FundInformationDao {
         }
         return fundIdNameMap;
     }
+
+    public List<MonetaryFundProfitDO> queryMonetaryFund(String fundId) {
+        return this.monetaryFundProfitMapper.queryByFundId(fundId);
+    }
 }

+ 70 - 0
src/main/java/com/smppw/analysis/domain/dataobject/MonetaryFundProfitDO.java

@@ -0,0 +1,70 @@
+package com.smppw.analysis.domain.dataobject;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+* @author Rain
+* @date 2023/5/23 11:19
+* @description 
+*/
+@Getter
+@Setter
+@ToString
+public class MonetaryFundProfitDO {
+    private Integer id;
+
+    /**
+    * 货币基金id
+    */
+    private String fundId;
+
+    /**
+    * 交易日
+    */
+    private Date priceDate;
+
+    /**
+    * 每万份收益
+    */
+    private BigDecimal profitPerMillion;
+
+    /**
+    * 7日年化收益
+    */
+    private BigDecimal profitServenDayAnnual;
+
+    /**
+    * 涉及天数
+    */
+    private Integer involvedDays;
+
+    /**
+    * 记录的有效性;1-有效;0-无效;
+    */
+    private Byte isvalid;
+
+    /**
+    * 创建者Id,默认第一次创建者名称,创建后不变更
+    */
+    private Integer creatorid;
+
+    /**
+    * 创建时间,默认第一次创建的getdate()时间
+    */
+    private Date createtime;
+
+    /**
+    * 修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+    */
+    private Integer updaterid;
+
+    /**
+    * 修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+    */
+    private Date updatetime;
+}

+ 1 - 1
src/main/java/com/smppw/analysis/domain/dto/performance/AnalyzeCovParams.java

@@ -13,7 +13,7 @@ import java.io.Serial;
  */
 @Setter
 @Getter
-public class AnalyzeCovParams extends BaseParams {
+public class CorrelationParams extends BaseParams {
     @Serial
     private static final long serialVersionUID = Consts.DEFAULT_SERIAL_VERSION_UID;
     // 滚动窗口

+ 0 - 18
src/main/java/com/smppw/analysis/domain/dto/performance/HeadIndicatorParams.java

@@ -1,18 +0,0 @@
-package com.smppw.analysis.domain.dto.performance;
-
-import com.smppw.common.pojo.IStrategy;
-import com.smppw.common.pojo.enums.Frequency;
-import com.smppw.common.pojo.enums.NavType;
-import com.smppw.common.pojo.enums.RaiseType;
-import lombok.Getter;
-import lombok.Setter;
-
-@Setter
-@Getter
-public class HeadIndicatorParams {
-    private String secId;
-    private NavType navType;
-    private Frequency frequency;
-    private RaiseType raiseType;
-    private IStrategy strategy;
-}

+ 0 - 18
src/main/java/com/smppw/analysis/domain/dto/performance/ImfTrendParams.java

@@ -1,18 +0,0 @@
-package com.smppw.analysis.domain.dto.performance;
-
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * @author wangzaijun
- * @date 2023/3/6 8:38
- * @description 公募货币基金业绩走势接口请求参数
- */
-@Setter
-@Getter
-public class ImfTrendParams extends BaseParams {
-    /**
-     * 货币面值类型,百份/万份/百万份收益
-     */
-    private String parValue;
-}

+ 5 - 0
src/main/java/com/smppw/analysis/domain/dto/performance/IndicatorParams.java

@@ -1,8 +1,11 @@
 package com.smppw.analysis.domain.dto.performance;
 
+import com.smppw.common.pojo.enums.Indicator;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.util.List;
+
 /**
  * @author wangzaijun
  * @date 2023/3/3 17:26
@@ -14,4 +17,6 @@ public class IndicatorParams extends BaseParams {
     private String riskOfFreeId;
     private Double riskOfFreeValue;
     private Boolean calcExtraRet;
+    private List<Indicator> indicators;
+    private List<Indicator> extraIndicators;
 }

+ 2 - 2
src/main/java/com/smppw/analysis/domain/dto/performance/RangIndicatorParams.java

@@ -7,11 +7,11 @@ import lombok.Setter;
 /**
  * @author wangzaijun
  * @date 2023/3/6 11:10
- * @description 区间指标缝隙接口请求参数
+ * @description 区间指标分析接口请求参数
  */
 @Setter
 @Getter
-public class RangIndicatorParams extends BaseParams {
+public class IntervalParams extends BaseParams {
     private Indicator indicator;
 
     private Boolean excess = false;

+ 1 - 1
src/main/java/com/smppw/analysis/domain/dto/performance/RollIndicatorParams.java

@@ -12,7 +12,7 @@ import lombok.Setter;
  */
 @Setter
 @Getter
-public class RollIndicatorParams extends BaseParams {
+public class RollingParams extends BaseParams {
     private Indicator indicator;
     private Frequency rollingFrequency;
 }

+ 5 - 1
src/main/java/com/smppw/analysis/domain/dto/performance/TrendParams.java

@@ -1,8 +1,11 @@
 package com.smppw.analysis.domain.dto.performance;
 
+import com.smppw.common.pojo.enums.TrendType;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.util.List;
+
 /**
  * @author wangzaijun
  * @date 2023/3/6 8:38
@@ -11,5 +14,6 @@ import lombok.Setter;
 @Setter
 @Getter
 public class TrendParams extends BaseParams {
-
+    private List<TrendType> trendTypes;
+    private List<TrendType> indexTrendTypes;
 }

+ 49 - 0
src/main/java/com/smppw/analysis/domain/dto/performance/WinVO.java

@@ -0,0 +1,49 @@
+package com.smppw.analysis.domain.dto.performance;
+
+import lombok.*;
+
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public class WinVO {
+    /**
+     * 胜率
+     */
+    private WinData win;
+    /**
+     * 市场特征胜率
+     */
+    private List<WinData> marketWin;
+
+    @Setter
+    @Getter
+    @Builder
+    public static class WinData {
+        /**
+         * 时段(震荡、上涨、下跌、全时段)
+         */
+        private String dateType;
+        /**
+         * 胜率
+         */
+        private String winRate;
+        private String meanRet;
+        private String benchmarkMeanRet;
+        private String excessMeanRet;
+        /**
+         * 跑赢次数
+         */
+        private String winItem;
+        /**
+         * 跑输次数
+         */
+        private String lossItem;
+        /**
+         * 周期数
+         */
+        private String totalItem;
+    }
+}

+ 95 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/AbstractPerformance.java

@@ -0,0 +1,95 @@
+package com.smppw.analysis.domain.manager.performance;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.Params;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.analysis.infrastructure.exception.APIException;
+import com.smppw.common.cache.CaffeineLocalCache;
+import com.smppw.common.pojo.enums.Frequency;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BinaryOperator;
+import java.util.stream.Collectors;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 9:54
+ * @description 抽象的业绩分析接口处理,模板方法模式
+ */
+public abstract class AbstractPerformance<P extends Params, R> implements Performance<P, R> {
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+    protected final BaseInfoService baseInfoService;
+    protected final BaseIndicatorServiceV2 baseIndicatorServiceV2;
+
+    public AbstractPerformance(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        this.baseInfoService = baseInfoService;
+        this.baseIndicatorServiceV2 = baseIndicatorServiceV2;
+    }
+
+    /**
+     * 利用jdk8的流操作计算最大最小值
+     *
+     * @param dataList 待计算的数据序列
+     * @param operator 求最大还最小值的操作函数
+     * @return /
+     */
+    protected static Double handleMaxAndMin(List<Double> dataList, BinaryOperator<Double> operator) {
+        if (dataList == null || dataList.isEmpty()) {
+            return 0d;
+        }
+        List<Double> collect = dataList.stream().filter(Objects::nonNull).collect(Collectors.toList());
+        if (collect.isEmpty()) {
+            return 0d;
+        }
+        return collect.stream().reduce(operator).orElse(0d);
+    }
+
+    /**
+     * 滚动指标 时间字段特殊处理
+     *
+     * @param date             时间
+     * @param rollingFrequency 滚动频率
+     * @return /
+     */
+    protected static String handleStrDate(String date, Frequency rollingFrequency) {
+        if (rollingFrequency == Frequency.Weekly) {
+            String yearMonthWeek = CaffeineLocalCache.getDateMonthWeek(date);
+            String year = yearMonthWeek.substring(0, 4);
+            String month = yearMonthWeek.substring(5, 7);
+            if (month.startsWith("0")) {
+                month = month.substring(1);
+            }
+            String week = yearMonthWeek.substring(8);
+            return year + "年" + month + "月第" + week + "周";
+        }
+        return date;
+    }
+
+    @Override
+    public R execute(P params) {
+        try {
+            this.checkParams(params);
+            return this.bizHandle(params);
+        } catch (Exception e) {
+            this.logger.warn(StrUtil.format("接口请求错误!{}", e.getMessage()));
+        }
+        return null;
+    }
+
+    protected void checkParams(P params) {
+        if (CollUtil.isEmpty(params.getRefIds())) {
+            throw new APIException("标的id不能为空!");
+        }
+        if (CharSequenceUtil.isAllBlank(params.getStartDate(), params.getEndDate())) {
+            throw new APIException("开始日期和结束日期不能为空!");
+        }
+    }
+
+    protected abstract R bizHandle(P params);
+}

File diff ditekan karena terlalu besar
+ 0 - 1287
src/main/java/com/smppw/analysis/domain/manager/performance/AbstractPerformanceService.java


+ 108 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/AbstractSingleSecPerformance.java

@@ -0,0 +1,108 @@
+package com.smppw.analysis.domain.manager.performance;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.BaseParams;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.common.pojo.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
+import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
+import com.smppw.common.pojo.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.Visibility;
+import com.smppw.utils.StrategyHandleUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 9:54
+ * @description 抽象的单标的的业绩表现
+ */
+public abstract class AbstractSingleSecPerformance<P extends BaseParams, R> extends AbstractPerformance<P, R> {
+    public AbstractSingleSecPerformance(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected R bizHandle(P params) {
+        return this.bizSecHandle(params);
+    }
+
+    protected abstract R bizSecHandle(P params);
+
+    /**
+     * 从请求参数中获取所有标的并集集合
+     *
+     * @param params 公共请求参数
+     * @return /
+     */
+    protected List<String> getSecIdsByParams(P params) {
+        List<String> tempList = ListUtil.list(true);
+        tempList.addAll(params.getRefIds());
+        if (StrUtil.isNotBlank(params.getBenchmarkId())) {
+            tempList.add(params.getBenchmarkId());
+        }
+        return params.getSecIds() == null ? tempList : CollUtil.addAllIfNotContains(tempList, params.getSecIds());
+    }
+
+    /**
+     * 根据请求参数构建 DateIntervalDto 对象
+     *
+     * @param params           请求参数,需继承 CommonParams
+     * @param dateIntervalType 时段类型
+     * @param frequency        接口传递的频率,一般为滚动计算时传递的滚动频率
+     * @return /
+     */
+    protected DateIntervalDto buildDateIntervalByParams(P params, DateIntervalType dateIntervalType, Frequency frequency) {
+        if (dateIntervalType == null) {
+            dateIntervalType = DateIntervalType.DefaultInterval;
+        }
+        if (frequency == null) {
+            frequency = params.getFrequency();
+        }
+        return DateIntervalDto.builder()
+                .id(dateIntervalType.name())
+                .startDate(params.getStartDate())
+                .endDate(params.getEndDate())
+                .timeRange(params.getTimeRange())
+                .dateIntervalType(dateIntervalType)
+                .frequency(frequency).build();
+    }
+
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(P params, DateIntervalType dateIntervalType) {
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        // 差集求指数id集合,包括基准
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(refIds.size(), true);
+        for (String refId : refIds) {
+            if (StrUtil.isBlank(params.getBenchmarkId())) {
+                continue;
+            }
+            benchmarkIdMap.put(refId, params.getBenchmarkId());
+        }
+        DateIntervalDto dateInterval = this.buildDateIntervalByParams(params, dateIntervalType, params.getFrequency());
+        Map<String, List<DateIntervalDto>> dateIntervalMap = MapUtil.newHashMap(refIds.size(), true);
+        for (String refId : refIds) {
+            dateIntervalMap.put(refId, ListUtil.toList(dateInterval));
+        }
+        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
+                .mainSecIdList(refIds)
+                .secBenchmarkIdMap(benchmarkIdMap)
+                .indexIdList(indexIds)
+                .raiseType(params.getRaiseType())
+                .strategy(StrategyHandleUtils.getStrategy(params.getStrategy()))
+                .visibility(Visibility.Both)
+                .dataFrequency(params.getFrequency())
+                .secDateIntervalDtoListMap(dateIntervalMap)
+                .navType(params.getNavType())
+                .ifAnnualize(true)
+                .calcIndexRetIndicatorValue(true)
+                .ifConvertPerformanceConsistencyWord(true).build();
+    }
+}

+ 435 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/HistoryRetTableUtil.java

@@ -0,0 +1,435 @@
+package com.smppw.analysis.domain.manager.performance;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.HistoryRetTableSingleData;
+import com.smppw.analysis.domain.dto.performance.HistoryRetTableSingleResp;
+import com.smppw.analysis.domain.dto.performance.HistoryRetTableSingleRet;
+import com.smppw.common.cache.CaffeineLocalCache;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.time.TimeIntervalDto;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.constants.DateConst;
+import org.apache.commons.lang3.time.DateUtils;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class HistoryRetTableUtil {
+    public static final String EXTRA = "extra";
+    public static final String YEAR_ROLL_DEFAULT_ID = "YearRoll";
+    public static final String MONTH_ROLL_DEFAULT_ID = "MonthRoll";
+    public static final List<String> YEAR_MONTH_ROLL_LIST = ListUtil.of(YEAR_ROLL_DEFAULT_ID, MONTH_ROLL_DEFAULT_ID);
+
+    private static final Map<Frequency, List<Integer>> CATE_LIST_MAP = MapUtil.newHashMap();
+    private static final Map<Frequency, List<String>> MONTH_WEEK_LIST_MAP = MapUtil.newHashMap();
+    private static final Map<String, Pair<String, String>> MONTH_QUARTERLY_MAP = MapUtil.newHashMap();
+
+    static {
+        CATE_LIST_MAP.put(Frequency.Monthly, ListUtil.toLinkedList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        CATE_LIST_MAP.put(Frequency.Weekly, ListUtil.toLinkedList(1, 2, 3, 4, 5));
+        CATE_LIST_MAP.put(Frequency.Quarterly, ListUtil.toLinkedList(1, 2, 3, 4));
+        CATE_LIST_MAP.put(Frequency.Annually, ListUtil.list(true));
+        MONTH_WEEK_LIST_MAP.put(Frequency.Monthly, ListUtil.toLinkedList("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"));
+        MONTH_WEEK_LIST_MAP.put(Frequency.Weekly, ListUtil.toLinkedList("1", "2", "3", "4", "5"));
+        MONTH_WEEK_LIST_MAP.put(Frequency.Quarterly, ListUtil.toLinkedList("03", "06", "09", "12"));
+        MONTH_WEEK_LIST_MAP.put(Frequency.Annually, ListUtil.list(true));
+
+        MONTH_QUARTERLY_MAP.put("01", Pair.of("01", "03"));
+        MONTH_QUARTERLY_MAP.put("02", Pair.of("01", "03"));
+        MONTH_QUARTERLY_MAP.put("03", Pair.of("01", "03"));
+        MONTH_QUARTERLY_MAP.put("04", Pair.of("03", "06"));
+        MONTH_QUARTERLY_MAP.put("05", Pair.of("03", "06"));
+        MONTH_QUARTERLY_MAP.put("06", Pair.of("03", "06"));
+        MONTH_QUARTERLY_MAP.put("07", Pair.of("06", "09"));
+        MONTH_QUARTERLY_MAP.put("08", Pair.of("06", "09"));
+        MONTH_QUARTERLY_MAP.put("09", Pair.of("06", "09"));
+        MONTH_QUARTERLY_MAP.put("10", Pair.of("09", "12"));
+        MONTH_QUARTERLY_MAP.put("11", Pair.of("09", "12"));
+        MONTH_QUARTERLY_MAP.put("12", Pair.of("09", "12"));
+    }
+
+    public static HistoryRetTableSingleResp getHistoryRetTableSingleResp(List<String> secIds, List<String> indexIdList, Map<String, List<IndicatorCalcPropertyDto>> indicatorCalcPropertyDtoListMap,
+                                                                         Indicator indicator, boolean ifExcessReturn, Frequency rollingFrequency) {
+        TimeIntervalDto timeIntervalDto = new TimeIntervalDto();
+        List<String> yearOrYearMonthList = ListUtil.list(true);
+        List<Integer> cates = CATE_LIST_MAP.get(rollingFrequency);
+        List<String> monthOrWeekList = MONTH_WEEK_LIST_MAP.get(rollingFrequency);
+
+        // Map<secId, Map<年或者年月, Map<月或者周, value>>>
+        Map<String, Map<String, Map<String, String>>> secYearMonthValueMapMapMap = new HashMap<>(16);
+        // Map<secId, Map<年或者年月, value>>
+        Map<String, Map<String, String>> secYearValueMapMap = new HashMap<>(16);
+
+        for (String secId : secIds) {
+            List<IndicatorCalcPropertyDto> indicatorCalcPropertyDtoList = indicatorCalcPropertyDtoListMap.get(secId);
+            for (IndicatorCalcPropertyDto indicatorCalcPropertyDto : indicatorCalcPropertyDtoList) {
+                String id = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId();
+                if (Frequency.Monthly == rollingFrequency || Frequency.Quarterly == rollingFrequency) {
+                    if (YEAR_ROLL_DEFAULT_ID.equals(id)) {
+                        prepareSingleYearDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, secYearValueMapMap, ifExcessReturn);
+                    } else {
+                        prepareSingleMonthDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, timeIntervalDto, yearOrYearMonthList, secYearMonthValueMapMapMap, ifExcessReturn);
+                    }
+                } else if (Frequency.Weekly == rollingFrequency) {
+                    if (MONTH_ROLL_DEFAULT_ID.equals(id)) {
+                        prepareSingleYearMonthDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, secYearValueMapMap, ifExcessReturn);
+                    } else {
+                        prepareSingleWeekDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, timeIntervalDto, yearOrYearMonthList, secYearMonthValueMapMapMap, ifExcessReturn);
+                    }
+                } else if (Frequency.Annually == rollingFrequency) {
+                    prepareSingleYearDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, secYearValueMapMap, ifExcessReturn);
+                    prepareSingleMonthDate(secId, indexIdList, indicatorCalcPropertyDto, indicator, timeIntervalDto, yearOrYearMonthList, secYearMonthValueMapMapMap, ifExcessReturn);
+                }
+            }
+        }
+
+        Collections.sort(yearOrYearMonthList);
+
+        List<HistoryRetTableSingleData> data = new ArrayList<>();
+        for (int i = yearOrYearMonthList.size() - 1; i >= 0; i--) {
+            List<HistoryRetTableSingleRet> rets = new ArrayList<>();
+            String yearOrYearMonth = yearOrYearMonthList.get(i);
+            HistoryRetTableSingleData historyRetTableSingleData = getHistoryRetTableSingleData(secIds, monthOrWeekList,
+                    secYearMonthValueMapMapMap, secYearValueMapMap, rets, yearOrYearMonth, rollingFrequency);
+
+            if (ifExcessReturn) {
+                for (String secId : secIds) {
+                    HistoryRetTableSingleRet extraRet = new HistoryRetTableSingleRet();
+                    List<String> secExtraRetList = new ArrayList<>();
+                    String yearValue = null;
+                    if (secYearValueMapMap.get(secId + EXTRA) != null) {
+                        yearValue = secYearValueMapMap.get(secId + EXTRA).get(yearOrYearMonth);
+                    }
+                    secExtraRetList.add(yearValue);
+                    Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(secId + EXTRA);
+                    Map<String, String> monthValueMap = Optional.ofNullable(yearMonthValueMapMap).map(e -> e.get(yearOrYearMonth)).orElse(null);
+                    List<String> monthList = null;
+                    if (monthValueMap != null) {
+                        monthList = new ArrayList<>(monthValueMap.keySet());
+                    }
+                    for (String monthOrWeek : monthOrWeekList) {
+                        String value = null;
+                        if (monthValueMap != null) {
+                            value = monthValueMap.get(monthOrWeek);
+                            if (value == null && rollingFrequency == Frequency.Quarterly) {
+                                Pair<String, String> pair = MONTH_QUARTERLY_MAP.get(monthOrWeek);
+                                String s = monthList.stream().filter(e -> e.compareTo(pair.getKey()) > 0).filter(e -> e.compareTo(pair.getValue()) < 0)
+                                        .filter(e -> e.compareTo(monthOrWeek) <= 0).max(String::compareTo).orElse(null);
+                                value = s == null ? null : monthValueMap.get(s);
+                            }
+                        }
+                        secExtraRetList.add(value);
+                    }
+                    extraRet.setId(secId);
+                    extraRet.setType("extraRet");
+                    extraRet.setRet(secExtraRetList);
+                    rets.add(extraRet);
+                }
+            }
+
+            calcIndexRet(indexIdList, monthOrWeekList, secYearMonthValueMapMapMap, secYearValueMapMap, data, historyRetTableSingleData, yearOrYearMonth, rets, rollingFrequency);
+        }
+
+        HistoryRetTableSingleResp resp = new HistoryRetTableSingleResp();
+        resp.setData(data);
+        resp.setDatetime(cates);
+        resp.setStartDate(timeIntervalDto.getStartDate());
+        resp.setEndDate(timeIntervalDto.getEndDate());
+        return resp;
+    }
+
+    /**
+     * 构建年度统计表格数据
+     *
+     * @param productNameMapping 名称映射
+     * @param resp               数据
+     * @return /
+     */
+    public static Map<String, Object> buildTableData(Map<String, String> productNameMapping, HistoryRetTableSingleResp resp, boolean excess, boolean flag) {
+        List<Map<String, Object>> data = ListUtil.list(true);
+        for (HistoryRetTableSingleData datum : resp.getData()) {
+            String year = datum.getYear();
+            if (excess && flag) {
+                List<HistoryRetTableSingleRet> collect = datum.getRets().stream().filter(e -> "extraRet".equals(e.getType())).collect(Collectors.toList());
+                for (HistoryRetTableSingleRet ret : collect) {
+                    Map<String, Object> temp = MapUtil.<String, Object>builder("year", year)
+                            .put("name", productNameMapping.get(ret.getId()))
+                            .put("ret", ret.getRet()).build();
+                    data.add(temp);
+                }
+            } else {
+                for (HistoryRetTableSingleRet ret : datum.getRets()) {
+                    Map<String, Object> temp = MapUtil.<String, Object>builder("year", year)
+                            .put("name", "ret".equals(ret.getType()) ? productNameMapping.get(ret.getId()) : productNameMapping.get(ret.getId()) + "-超额收益")
+                            .put("ret", ret.getRet()).build();
+                    data.add(temp);
+                }
+            }
+        }
+        return MapUtil.<String, Object>builder("datetime", resp.getDatetime()).put("data", data).build();
+    }
+
+    private static HistoryRetTableSingleData getHistoryRetTableSingleData(List<String> secIds, List<String> monthOrWeekList, Map<String, Map<String, Map<String, String>>> secYearMonthValueMapMapMap,
+                                                                          Map<String, Map<String, String>> secYearValueMapMap, List<HistoryRetTableSingleRet> rets, String yearOrYearMonth, Frequency rollingFrequency) {
+        HistoryRetTableSingleData historyRetTableSingleData = new HistoryRetTableSingleData();
+        historyRetTableSingleData.setYear(yearOrYearMonth);
+
+        for (String secId : secIds) {
+            HistoryRetTableSingleRet ret = new HistoryRetTableSingleRet();
+            List<String> secRetList = new ArrayList<>();
+            String yearValue = null;
+            if (secYearValueMapMap.get(secId) != null) {
+                yearValue = secYearValueMapMap.get(secId).get(yearOrYearMonth);
+            }
+
+            secRetList.add(yearValue);
+            Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(secId);
+            Map<String, String> monthValueMap = Optional.ofNullable(yearMonthValueMapMap).map(e -> e.get(yearOrYearMonth)).orElse(null);
+            List<String> monthList = null;
+            if (monthValueMap != null) {
+                monthList = new ArrayList<>(monthValueMap.keySet());
+            }
+            for (String monthOrWeek : monthOrWeekList) {
+                String value = null;
+                if (monthValueMap != null) {
+                    value = monthValueMap.get(monthOrWeek);
+                    if (value == null && rollingFrequency == Frequency.Quarterly) {
+                        Pair<String, String> pair = MONTH_QUARTERLY_MAP.get(monthOrWeek);
+                        String s = monthList.stream().filter(e -> e.compareTo(pair.getKey()) > 0).filter(e -> e.compareTo(pair.getValue()) < 0)
+                                .filter(e -> e.compareTo(monthOrWeek) <= 0).max(String::compareTo).orElse(null);
+                        value = s == null ? null : monthValueMap.get(s);
+                    }
+                }
+                secRetList.add(value);
+            }
+            ret.setId(secId);
+            ret.setType("ret");
+            ret.setRet(secRetList);
+            rets.add(ret);
+        }
+        return historyRetTableSingleData;
+    }
+
+    private static void prepareSingleWeekDate(String secId, List<String> indexIdList, IndicatorCalcPropertyDto indicatorCalcPropertyDto, Indicator indicator, TimeIntervalDto timeIntervalDto,
+                                              List<String> yearMonthList, Map<String, Map<String, Map<String, String>>> secYearMonthWeekValueMapMapMap, boolean ifExtraRet) {
+        String startDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getStartDate();
+        String endDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getEndDate();
+        if (StrUtil.isBlank(timeIntervalDto.getStartDate()) || startDate1.compareTo(timeIntervalDto.getStartDate()) < 0) {
+            timeIntervalDto.setStartDate(startDate1);
+        }
+        if (StrUtil.isBlank(timeIntervalDto.getEndDate()) || endDate1.compareTo(timeIntervalDto.getEndDate()) > 0) {
+            timeIntervalDto.setEndDate(endDate1);
+        }
+        String calcEndDate = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getEndDate();
+        String yearMonthWeek = CaffeineLocalCache.getDateMonthWeek(calcEndDate);
+        String yearMonth = yearMonthWeek.substring(0, 7);
+        String week = yearMonthWeek.substring(8);
+        if (!yearMonthList.contains(yearMonth)) {
+            yearMonthList.add(yearMonth);
+        }
+        handleMonthWeekYearData(secId, indexIdList, indicatorCalcPropertyDto, indicator, secYearMonthWeekValueMapMapMap, ifExtraRet, yearMonth, week);
+    }
+
+    private static void prepareSingleYearDate(String secId, List<String> indexIdList, IndicatorCalcPropertyDto indicatorCalcPropertyDto, Indicator indicator,
+                                              Map<String, Map<String, String>> secYearValueMapMap, boolean ifExcessRet) {
+        String endDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getEndDate();
+        Date monthDate = DateUtils.addDays(DateUtil.parse(endDate1, DateConst.YYYY_MM_DD), -5);
+        String date = DateUtil.format(monthDate, DateConst.YYYY_MM_DD);
+        String year = date.substring(0, 4);
+        String value = indicatorCalcPropertyDto.getSecData().getIndicatorValueMap().get(indicator.name());
+        if (secYearValueMapMap.containsKey(secId)) {
+            secYearValueMapMap.get(secId).put(year, value);
+        } else {
+            Map<String, String> yearValueMap = new HashMap<>(16);
+            yearValueMap.put(year, value);
+            secYearValueMapMap.put(secId, yearValueMap);
+        }
+        if (Indicator.ExcessReturn == indicator || ifExcessRet) {
+            String extraValue = indicatorCalcPropertyDto.getSecData().getExtraGeoIndicatorValueMap().get(indicator.name());
+            if (secYearValueMapMap.containsKey(secId + EXTRA)) {
+                secYearValueMapMap.get(secId + EXTRA).put(year, extraValue);
+            } else {
+                Map<String, String> yearValueMap = new HashMap<>(16);
+                yearValueMap.put(year, extraValue);
+                secYearValueMapMap.put(secId + EXTRA, yearValueMap);
+            }
+        }
+
+        for (String indexId : indexIdList) {
+            String indexValue = indicatorCalcPropertyDto.getIndexData().getIndexIndicatorValueMap().get(indexId).get(indicator.name());
+            if (secYearValueMapMap.containsKey(indexId)) {
+                secYearValueMapMap.get(indexId).put(year, indexValue);
+            } else {
+                Map<String, String> yearValueMap = new HashMap<>(16);
+                yearValueMap.put(year, indexValue);
+                secYearValueMapMap.put(indexId, yearValueMap);
+            }
+        }
+    }
+
+    private static void prepareSingleMonthDate(String secId, List<String> indexIdList, IndicatorCalcPropertyDto indicatorCalcPropertyDto, Indicator indicator,
+                                               TimeIntervalDto timeInterval, List<String> yearList, Map<String, Map<String, Map<String, String>>> secYearMonthValueMapMapMap, boolean ifExcessRet) {
+        String startDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getStartDate();
+        String endDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getEndDate();
+        if (StrUtil.isBlank(timeInterval.getStartDate()) || startDate1.compareTo(timeInterval.getStartDate()) < 0) {
+            timeInterval.setStartDate(startDate1);
+        }
+        if (StrUtil.isBlank(timeInterval.getEndDate()) || endDate1.compareTo(timeInterval.getEndDate()) > 0) {
+            timeInterval.setEndDate(endDate1);
+        }
+        String yearMonth = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId();
+        String year = yearMonth.substring(0, 4);
+        if (!yearList.contains(year)) {
+            yearList.add(year);
+        }
+        String month = yearMonth.substring(5);
+        handleMonthWeekYearData(secId, indexIdList, indicatorCalcPropertyDto, indicator, secYearMonthValueMapMapMap, ifExcessRet, year, month);
+    }
+
+    private static void handleMonthWeekYearData(String secId, List<String> indexIdList, IndicatorCalcPropertyDto indicatorCalcPropertyDto,
+                                                Indicator indicator, Map<String, Map<String, Map<String, String>>> secYearMonthValueMapMapMap,
+                                                boolean ifExcessRet, String year, String month) {
+        String value = indicatorCalcPropertyDto.getSecData().getIndicatorValueMap().get(indicator.name());
+        if (secYearMonthValueMapMapMap.containsKey(secId)) {
+            Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(secId);
+            if (yearMonthValueMapMap.containsKey(year)) {
+                Map<String, String> monthValueMap = yearMonthValueMapMap.get(year);
+                monthValueMap.put(month, value);
+            } else {
+                Map<String, String> monthValueMap = new HashMap<>(16);
+                monthValueMap.put(month, value);
+                yearMonthValueMapMap.put(year, monthValueMap);
+            }
+        } else {
+            Map<String, Map<String, String>> yearMonthValueMapMap = new HashMap<>(16);
+            Map<String, String> monthValueMap = new HashMap<>(16);
+            monthValueMap.put(month, value);
+            yearMonthValueMapMap.put(year, monthValueMap);
+            secYearMonthValueMapMapMap.put(secId, yearMonthValueMapMap);
+        }
+        if (Indicator.ExcessReturn == indicator || ifExcessRet) {
+            String extraValue = indicatorCalcPropertyDto.getSecData().getExtraGeoIndicatorValueMap().get(indicator.name());
+            if (secYearMonthValueMapMapMap.containsKey(secId + EXTRA)) {
+                Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(secId + EXTRA);
+                if (yearMonthValueMapMap.containsKey(year)) {
+                    Map<String, String> monthValueMap = yearMonthValueMapMap.get(year);
+                    monthValueMap.put(month, extraValue);
+                } else {
+                    Map<String, String> monthValueMap = new HashMap<>(16);
+                    monthValueMap.put(month, extraValue);
+                    yearMonthValueMapMap.put(year, monthValueMap);
+                }
+            } else {
+                Map<String, Map<String, String>> yearMonthValueMapMap = new HashMap<>(16);
+                Map<String, String> monthValueMap = new HashMap<>(16);
+                monthValueMap.put(month, extraValue);
+                yearMonthValueMapMap.put(year, monthValueMap);
+                secYearMonthValueMapMapMap.put(secId + EXTRA, yearMonthValueMapMap);
+            }
+        }
+        for (String index : indexIdList) {
+            String indexValue = indicatorCalcPropertyDto.getIndexData().getIndexIndicatorValueMap().get(index).get(indicator.name());
+            if (secYearMonthValueMapMapMap.containsKey(index)) {
+                Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(index);
+                if (yearMonthValueMapMap.containsKey(year)) {
+                    Map<String, String> monthValueMap = yearMonthValueMapMap.get(year);
+                    monthValueMap.put(month, indexValue);
+                } else {
+                    Map<String, String> monthValueMap = new HashMap<>(16);
+                    monthValueMap.put(month, indexValue);
+                    yearMonthValueMapMap.put(year, monthValueMap);
+                }
+            } else {
+                Map<String, Map<String, String>> yearMonthValueMapMap = new HashMap<>(16);
+                Map<String, String> monthValueMap = new HashMap<>(16);
+                monthValueMap.put(month, indexValue);
+                yearMonthValueMapMap.put(year, monthValueMap);
+                secYearMonthValueMapMapMap.put(index, yearMonthValueMapMap);
+            }
+        }
+    }
+
+    private static void prepareSingleYearMonthDate(String secId, List<String> indexIdList, IndicatorCalcPropertyDto indicatorCalcPropertyDto, Indicator indicator,
+                                                   Map<String, Map<String, String>> secMonthValueMapMap, boolean ifExtraRet) {
+        String endDate1 = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getEndDate();
+        Date monthDate = DateUtils.addDays(DateUtil.parse(endDate1, DateConst.YYYY_MM_DD), -5);
+        String date = DateUtil.format(monthDate, DateConst.YYYY_MM_DD);
+        String yearMonth = date.substring(0, 7);
+        String value = indicatorCalcPropertyDto.getSecData().getIndicatorValueMap().get(indicator.name());
+
+        if (secMonthValueMapMap.containsKey(secId)) {
+            secMonthValueMapMap.get(secId).put(yearMonth, value);
+        } else {
+            Map<String, String> yearValueMap = new HashMap<>(16);
+            yearValueMap.put(yearMonth, value);
+            secMonthValueMapMap.put(secId, yearValueMap);
+        }
+
+        if (Indicator.ExcessReturn == indicator || ifExtraRet) {
+            String extraValue = indicatorCalcPropertyDto.getSecData().getExtraGeoIndicatorValueMap().get(indicator.name());
+            if (secMonthValueMapMap.containsKey(secId + EXTRA)) {
+                secMonthValueMapMap.get(secId + EXTRA).put(yearMonth, extraValue);
+            } else {
+                Map<String, String> yearValueMap = new HashMap<>(16);
+                yearValueMap.put(yearMonth, extraValue);
+                secMonthValueMapMap.put(secId + EXTRA, yearValueMap);
+            }
+        }
+
+        //指数的
+        for (String indexId : indexIdList) {
+            String indexValue = indicatorCalcPropertyDto.getIndexData().getIndexIndicatorValueMap().get(indexId).get(indicator.name());
+            if (secMonthValueMapMap.containsKey(indexId)) {
+                secMonthValueMapMap.get(indexId).put(yearMonth, indexValue);
+            } else {
+                Map<String, String> yearValueMap = new HashMap<>(16);
+                yearValueMap.put(yearMonth, indexValue);
+                secMonthValueMapMap.put(indexId, yearValueMap);
+            }
+        }
+    }
+
+    private static void calcIndexRet(List<String> indexIdList, List<String> monthOrWeekList, Map<String, Map<String, Map<String, String>>> secYearMonthValueMapMapMap,
+                                     Map<String, Map<String, String>> secYearValueMapMap, List<HistoryRetTableSingleData> data,
+                                     HistoryRetTableSingleData historyRetTableSingleData, String yearOrYearMonth, List<HistoryRetTableSingleRet> rets, Frequency rollingFrequency) {
+        for (String indexId : indexIdList) {
+            HistoryRetTableSingleRet indexRet = new HistoryRetTableSingleRet();
+            List<String> indexRetList = new ArrayList<>();
+            String yearValue = null;
+            if (secYearValueMapMap.get(indexId) != null) {
+                yearValue = secYearValueMapMap.get(indexId).get(yearOrYearMonth);
+            }
+            indexRetList.add(yearValue);
+            Map<String, Map<String, String>> yearMonthValueMapMap = secYearMonthValueMapMapMap.get(indexId);
+            Map<String, String> monthValueMap = Optional.ofNullable(yearMonthValueMapMap).map(e -> e.get(yearOrYearMonth)).orElse(null);
+            List<String> monthList = null;
+            if (monthValueMap != null) {
+                monthList = new ArrayList<>(monthValueMap.keySet());
+            }
+            for (String monthOrWeek : monthOrWeekList) {
+                String value = null;
+                if (monthValueMap != null) {
+                    value = monthValueMap.get(monthOrWeek);
+                    if (value == null && rollingFrequency == Frequency.Quarterly) {
+                        Pair<String, String> pair = MONTH_QUARTERLY_MAP.get(monthOrWeek);
+                        String s = monthList.stream().filter(e -> e.compareTo(pair.getKey()) > 0).filter(e -> e.compareTo(pair.getValue()) < 0)
+                                .filter(e -> e.compareTo(monthOrWeek) <= 0).max(String::compareTo).orElse(null);
+                        value = s == null ? null : monthValueMap.get(s);
+                    }
+                }
+                indexRetList.add(value);
+            }
+            indexRet.setId(indexId);
+            indexRet.setType("ret");
+            indexRet.setRet(indexRetList);
+            rets.add(indexRet);
+        }
+        historyRetTableSingleData.setRets(rets);
+        data.add(historyRetTableSingleData);
+    }
+}

+ 12 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/Performance.java

@@ -0,0 +1,12 @@
+package com.smppw.analysis.domain.manager.performance;
+
+import com.smppw.analysis.domain.dto.performance.Params;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 9:53
+ * @description 业绩表现业务处理
+ */
+public interface Performance<P extends Params, R> {
+    R execute(P params);
+}

+ 21 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceConstants.java

@@ -0,0 +1,21 @@
+package com.smppw.analysis.domain.manager.performance;
+
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 15:55
+ * @description 业绩表现的组件名称常量
+ */
+public final class PerformanceConstants {
+    public static final String INDICATOR = "indicatorCalc";
+    public static final String TREND = "trend";
+    public static final String CORRELATION = "cor";
+    public static final String WIN = "win";
+    public static final String REVENUE = "revenue";
+    public static final String IMF = "imf";
+    public static final String INTERVAL = "interval";
+    public static final String ROLLING = "rolling";
+    public static final String RANK = "rank";
+
+    private PerformanceConstants() {
+    }
+}

+ 35 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceFactory.java

@@ -0,0 +1,35 @@
+package com.smppw.analysis.domain.manager.performance;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import com.smppw.analysis.domain.dto.performance.Params;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class PerformanceFactory {
+    private static final Performance<Params, Object> EMPTY = p -> null;
+    private static final Map<String, Performance<? extends Params, ?>> PERFORMANCE_STRATEGY = MapUtil.newHashMap(16);
+
+    public PerformanceFactory(Map<String, Performance<? extends Params, ?>> component) {
+        PERFORMANCE_STRATEGY.putAll(component);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <P extends Params, R> Performance<P, R> getInstance(String strategyKey) {
+        Performance<P, R> empty = (Performance<P, R>) EMPTY;
+        if (CharSequenceUtil.isBlank(strategyKey)) {
+            return empty;
+        }
+        Performance<? extends Params, ?> performance = PERFORMANCE_STRATEGY.get(strategyKey);
+        if (performance == null) {
+            return empty;
+        }
+        try {
+            return (Performance<P, R>) performance;
+        } catch (Exception e) {
+            return empty;
+        }
+    }
+}

+ 0 - 145
src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceService.java

@@ -1,145 +0,0 @@
-//package com.smppw.analysis.domain.manager.performance;
-//
-//import cn.hutool.core.collection.ListUtil;
-//import com.smppw.analysis.domain.dto.performance.*;
-//import com.smppw.common.pojo.enums.Indicator;
-//import com.smppw.common.pojo.enums.TimeRange;
-//import com.smppw.common.pojo.enums.TrendType;
-//
-//import java.util.List;
-//import java.util.Map;
-//
-///**
-// * @author wangzaijun
-// * @date 2023/3/10 17:51
-// * @description 业绩表现接口,包括基金、机构和基金经理
-// */
-//public interface PerformanceService {
-//    /**
-//     * 计算收益风险指标,包括部分几何指标
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    default Map<String, Object> rateRiskIndicators(IndicatorParams params) {
-//        return this.rateRiskIndicators(params, ListUtil.toList(Indicator.INDICATOR_TYPE_ARRAY), ListUtil.toList(Indicator.RISK_TABLE_EXCESS_INDICATOR_ARRAY));
-//    }
-//
-//    Map<String, Object> rateRiskIndicators(IndicatorParams params, List<Indicator> indicators, List<Indicator> geoIndicators);
-//
-//    /**
-//     * 动态回撤 接口业务,返回回撤、超额回撤、最大回撤和最大超额回撤
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    default Map<String, Object> dynamicDown(TrendParams params) {
-//        return this.dynamicDown(params, null);
-//    }
-//
-//    /**
-//     * 动态回撤 接口业务,返回回撤、超额回撤、最大回撤和最大超额回撤
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    Map<String, Object> dynamicDown(TrendParams params, String masterId);
-//
-//    /**
-//     * 业绩走势接口业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    default Map<String, Object> trend(TrendParams params) {
-//        List<TrendType> trendTypes = ListUtil.toList(TrendType.Ret, TrendType.Nav, TrendType.ExtraNav, TrendType.OrigNav, TrendType.ExtraRetAri, TrendType.NetValueChange, TrendType.ExtraRetGeo, TrendType.DrawdownTrend);
-//        List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.Ret, TrendType.OrigNav);
-//        return this.trend(params, trendTypes, indexTrendTypes);
-//    }
-//
-//    /**
-//     * 业绩走势接口业务处理
-//     *
-//     * @param params          请求参数
-//     * @param trendTypes      标的走势图类型列表
-//     * @param indexTrendTypes 指数走势图类型列表
-//     * @return /
-//     */
-//    Map<String, Object> trend(TrendParams params, List<TrendType> trendTypes, List<TrendType> indexTrendTypes);
-//
-//    /**
-//     * 货币基金业绩走势
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    Map<String, Object> imfTrend(ImfTrendParams params);
-//
-//    /**
-//     * 业绩排名 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    Map<String, Object> rank(RankParams params);
-//
-//    /**
-//     * 区间指标分析 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    default Map<String, Object> rangIndicator(RangIndicatorParams params) {
-//        return this.rangIndicator(params, null);
-//    }
-//
-//
-//    /**
-//     * 区间指标分析 接口请求业务处理
-//     *
-//     * @param params   请求参数
-//     * @param rangeMap 返回结果映射函数
-//     * @return /
-//     */
-//    Map<String, Object> rangIndicator(RangIndicatorParams params, Map<TimeRange, String> rangeMap);
-//
-//    /**
-//     * 滚动指标分析 接口请求业务处理,不支持多标的
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    Map<String, Object> rollIndicator(RollIndicatorParams params);
-//
-//    /**
-//     * 收益统计/收益分布 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    Map<String, Object> revenue(RevenueParams params);
-//
-//    /**
-//     * 胜率分析,只支持单标的 业务处理
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    Map<String, Object> win(WinParams params);
-//
-//    /**
-//     * 指标分析
-//     *
-//     * @param params
-//     * @return
-//     */
-//    Map<String, Object> analyzeIndicatorNew(RangIndicatorParams params);
-//
-//    /**
-//     * 相关性
-//     *
-//     * @param params
-//     * @return
-//     */
-//    Map<String, Object> analyzeCovNew(AnalyzeCovParams params);
-//}

+ 0 - 946
src/main/java/com/smppw/analysis/domain/manager/performance/PerformanceServiceImpl.java

@@ -1,946 +0,0 @@
-//package com.smppw.analysis.domain.manager.performance;
-//
-//import cn.hutool.core.collection.CollUtil;
-//import cn.hutool.core.collection.CollectionUtil;
-//import cn.hutool.core.collection.ListUtil;
-//import cn.hutool.core.date.DateUtil;
-//import cn.hutool.core.map.MapUtil;
-//import cn.hutool.core.text.CharSequenceUtil;
-//import cn.hutool.core.util.NumberUtil;
-//import cn.hutool.core.util.StrUtil;
-//
-//import com.smppw.analysis.domain.dto.performance.*;
-//import com.smppw.analysis.infrastructure.consts.WinRateBmk;
-//import com.smppw.analysis.infrastructure.exception.APIException;
-//import com.smppw.common.pojo.IStrategy;
-//import com.smppw.common.pojo.dto.CompoundRet;
-//import com.smppw.common.pojo.dto.DateRange;
-//import com.smppw.common.pojo.dto.calc.*;
-//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.common.rollrange.RollingSpliter;
-//import com.smppw.constants.Consts;
-//import com.smppw.utils.CalcUtils;
-//import com.smppw.utils.CommonUtil;
-//import com.smppw.utils.NavUtil;
-//import com.smppw.utils.StrategyHandleUtils;
-//import lombok.extern.slf4j.Slf4j;
-//import org.apache.commons.lang3.StringUtils;
-//import org.springframework.beans.factory.annotation.Autowired;
-//import org.springframework.beans.factory.annotation.Qualifier;
-//import org.springframework.jdbc.core.JdbcTemplate;
-//import org.springframework.stereotype.Service;
-//
-//import java.io.IOException;
-//import java.math.BigDecimal;
-//import java.util.*;
-//import java.util.function.Function;
-//import java.util.stream.Collectors;
-//
-//
-///**
-// * @author wangzaijun
-// * @date 2023/3/3 17:22
-// * @description 业绩表现页面的所有接口服务,包含基金、机构和经理
-// */
-//@Service
-//@Slf4j
-//public class PerformanceServiceImpl extends AbstractPerformanceService {
-//    /**
-//     * 指数成分类型: 1-表示融智策略指数;2-表示融智获奖指数;
-//     */
-//    public static final int COMPONENT_TYPE_STRATEGY = 1;
-//
-//    private static final String ONE = "1";
-//    private static final String TWO = "2";
-//
-//    private static final List<String> TYPE_LIST = ListUtil.of(ONE, TWO);
-//
-//    @Autowired
-//    @Qualifier("jdbcTemplateReportBuilder")
-//    private JdbcTemplate jdbcTemplate;
-//    @Autowired
-//    private RankRatService rankRatService;
-//    @Autowired
-//    private IndexPerformanceBaseService indexPerformanceBaseService;
-//    @Autowired
-//    private FundHeadInfoBaseService fundHeadInfoBaseService;
-//    @Autowired
-//    private ManagerHeadInfoBaseService managerHeadInfoBaseService;
-//    @Autowired
-//    private CompanyHeadInfoBaseService companyHeadInfoBaseService;
-//    @Autowired
-//    private ManagerInfoImpl managerInfo;
-//    @Autowired
-//    private MonetaryFundProfitBaseService monetaryFundProfitBaseService;
-//
-//    @Autowired
-//    private CmPublicCompanyStatisHistoryDAO cmPublicCompanyStatisHistoryDAO;
-//    private UserPermissionService userPermissionService;
-//
-//    @Autowired
-//    private FundManagerMappingDOMapper fundManagerMappingDOMapper;
-//
-//    @Autowired
-//    private MfAdvisorScaleRankMapper mfAdvisorScaleRankMapper;
-//
-//    public PerformanceServiceImpl(NavService navService, InfoService infoService, SecId2NameService secId2NameService,
-//                                  BaseIndicatorServiceV2 baseIndicatorServiceV2, UserPermissionService userPermissionService) {
-//        super(navService, infoService, secId2NameService, baseIndicatorServiceV2);
-//        this.userPermissionService = userPermissionService;
-//    }
-//
-//    /**
-//     * 计算收益风险指标,包括部分几何指标
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    public Map<String, Object> rateRiskIndicators(IndicatorParams params, List<Indicator> indicators, List<Indicator> geoIndicators) {
-//        try {
-//            // 1.参数处理
-//            this.checkParams(params);
-//            List<String> refIds = params.getFundId();
-//            List<String> secIds = this.getSecIdsByParams(params);
-//            // 差集求指数id集合,包括基�
-//            List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//            String riskOfFreeId = params.getRiskOfFreeId();
-//            Double riskOfFreeValue = params.getRiskOfFreeValue();
-//            if (StrUtil.isBlank(riskOfFreeId)) {
-//                riskOfFreeId = Consts.RISK_OF_FREE;
-//            } else if (NumberUtil.isNumber(riskOfFreeId)) {
-//                riskOfFreeValue = Double.parseDouble(riskOfFreeId);
-//                riskOfFreeId = null;
-//            }
-//            CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, geoIndicators, DateIntervalType.CustomInterval, null);
-//            req.setRiskOfFreeId(riskOfFreeId);
-//            req.setRiskOfFreeValue(riskOfFreeValue);
-//            req.setIfExtract(params.getIsExtract() != null && params.getIsExtract());
-//
-//            // 2.指标计算
-//            Map<String, List<IndicatorCalcPropertyDto>> indicator = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-//
-//            // 3.返回结果处理
-//            Map<String, Object> valuesMap = MapUtil.newHashMap(true);
-//            Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
-//            for (String refId : refIds) {
-//                IndicatorCalcPropertyDto dto = Optional.ofNullable(indicator.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
-//                // 标的指标
-//                Map<String, String> indicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getIndicatorValueMap).orElse(MapUtil.empty());
-//                // 标的几何指标
-//                Map<String, String> geoIndicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getExtraGeoIndicatorValueMap).orElse(MapUtil.empty());
-//                // 指数指标,包括基�
-//                Map<String, Map<String, String>> indexIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).orElse(MapUtil.empty());
-//                // 指数几何指标
-//                Map<String, Map<String, String>> indexGeoIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexGeoExtraIndicatorValueMap).orElse(MapUtil.empty());
-//                // 标的和指数分别处理最大回撤指标,并合并指标结果到一个map�
-//                Map<String, String> values = this.handleMaxDrawdown(indicatorValues, refId, null, false);
-//                Map<String, String> geoValues = this.handleMaxDrawdown(geoIndicatorValues, refId, null, true);
-//                Map<String, String> unionValues = MapUtil.<String, String>builder().putAll(values).putAll(geoValues).build();
-//                valuesMap.put(refId, unionValues);
-//                for (String indexId : indexIds) {
-//                    if (indexValuesMap.containsKey(indexId)) {
-//                        continue;
-//                    }
-//                    Map<String, String> indexValues = this.handleMaxDrawdown(indexIndicatorValuesMap.get(indexId), indexId, null, false);
-//                    Map<String, String> indexGeoValues = this.handleMaxDrawdown(indexGeoIndicatorValuesMap.get(indexId), indexId, params.getBenchmarkId(), true);
-//                    Map<String, String> unionIndexValues = MapUtil.<String, String>builder().putAll(indexValues).putAll(indexGeoValues).build();
-//                    indexValuesMap.put(indexId, unionIndexValues);
-//                }
-//            }
-//
-//            // 返回结果对象构建
-//            Map<String, Object> dataset = MapUtil.builder(valuesMap).putAll(indexValuesMap).build();
-//            Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getStartDate() + "~" + params.getEndDate()).build();
-//            Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
-//            CommonData<Map<String, Object>> data = CommonData.<Map<String, Object>>builder().dataset(dataset).productNameMapping(productNameMapping).extInfos(extInfos).build();
-//            return CommonUtil.covertToMap(data, "endDate");
-//        } catch (Exception e) {
-//            logger.error(String.format("基金收益风险指标计算错误:%s", e.getMessage()));
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    /**
-//     * 动态回撤接口业务,返回回撤、超额回撤、最大回撤和最大超额回撤
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    public Map<String, Object> dynamicDown(TrendParams params, String masterId) {
-//        try {
-//            List<TrendType> trendTypes = ListUtil.toList(TrendType.DrawdownTrend, TrendType.ExtraDrawdownTrend);
-//            List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.DrawdownTrend);
-//            CommonData<Map<String, List<Map<String, Object>>>> data = this.handleTrends(params, trendTypes, indexTrendTypes, masterId);
-//            return CommonUtil.covertToMap(data, "maxDown", "maxExtraDown", "startDate", "endDate");
-//        } catch (Exception e) {
-//            logger.error(String.format("动态回撤错误:%s", e.getMessage()), e);
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    /**
-//     * 业绩排名 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    public Map<String, Object> rank(RankParams params) {
-//        try {
-//            // 1.参数处理
-//            this.checkParams(params);
-//            String refId = params.getFundId().get(0);
-//            List<String> secIds = this.getSecIdsByParams(params);
-//            List<String> indexIds = CollectionUtil.subtractToList(secIds, params.getFundId());
-//            String rankDate = Optional.ofNullable(rankRatService.getLatestRankRat()).map(CmRankRatControlDo::getEndDate).orElse(null);
-//            IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
-//            List<Map<String, Object>> tempList = ListUtil.list(false);
-//            String rankFiled = null;
-//            CmBigDataFundRetDO cmBigDataFundRetDO = fundHeadInfoBaseService.selectFundRetByFundId(refId);
-//            String endDate = Optional.ofNullable(cmBigDataFundRetDO).map(CmBigDataFundRetDO::getEndDate).orElse(null);
-//            if (StringUtils.isNotEmpty(endDate) && StringUtils.isNotEmpty(rankDate)) {
-//                rankDate = endDate.compareTo(rankDate) > 0 ? rankDate : endDate;
-//            } else {
-//                if (StringUtils.isEmpty(endDate)) {
-//                    rankDate = endDate;
-//                }
-//            }
-//            rankFiled = "fund_rank";
-//            Integer isInvestAdvisor = Optional.ofNullable(UserUtils.getLoginUser()).map(SysUserDto::getIsInvestAdvisor).orElse(null);
-//            if (params.getIsExtract() != null && params.getIsExtract()) {
-//                tempList = null;
-//            } else {
-//                tempList = new FundRankProDao(this.jdbcTemplate, rankDate, refId, indexIds, params.getIndicator(), isInvestAdvisor).query();
-//            }
-//            Map<String, String> mapper = this.secId2NameService.query(secIds);
-//            Map<String, String> productMapper = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).putAll(mapper)
-//                    .put("rank", "同策略排名")
-//                    .put("strategy_avg", "同策略平均")
-//                    .put("strategy_avg_99", "同策略平均(1%-99%)")
-//                    .put("strategy_best", "同策略最好")
-//                    .put("strategy_worst", "同策略最差")
-//                    .put("percent5", "5%分位数")
-//                    .put("percent25", "25%分位数")
-//                    .put("percent50", "50%分位数")
-//                    .put("percent75", "75%分位数")
-//                    .put("percent95", "95%分位数").build();
-//            Map<String, Object> extInfos = MapUtil.<String, Object>builder("strategy", strategy.getStrategyNameDesc()).build();
-//            List<Map<String, Object>> dataset = this.getRankDataset(tempList, rankFiled);
-//            if (CollUtil.isEmpty(dataset)) {
-//                CommonData<List<Map<String, Object>>> data = CommonData.<List<Map<String, Object>>>builder()
-//                        .dataset(dataset).productNameMapping(productMapper).extInfos(extInfos).build();
-//                return CommonUtil.covertToMap(data);
-//            }
-//            CommonData<List<Map<String, Object>>> data = CommonData.<List<Map<String, Object>>>builder()
-//                    .dataset(dataset).productNameMapping(productMapper).extInfos(extInfos).build();
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("业绩排名错误:%s", e.getMessage()), e);
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    private List<Map<String, Object>> getRankDataset(List<Map<String, Object>> tempList, String rankFiled) {
-//        Map<String, Map<String, Object>> resMap = new LinkedHashMap<>();
-//        if (CollUtil.isEmpty(tempList)) {
-//            return CollUtil.newArrayList();
-//        }
-//        for (Map<String, Object> unit : tempList) {
-//            String classification = MapUtil.getStr(unit, "classification");
-//            String name = MapUtil.getStr(unit, "name");
-//            if (name == null && classification == null) {
-//                continue;
-//            }
-//            List<String> keys = new ArrayList<>(unit.keySet());
-//            keys.remove("name");
-//            keys.remove("classification");
-//            for (String key : keys) {
-//                if (!resMap.containsKey(key)) {
-//                    resMap.put(key, MapUtil.newHashMap(false));
-//                }
-//                if (classification.startsWith("strategy") || classification.startsWith("percen") || classification.equals(rankFiled)) {
-//                    name = classification;
-//                }
-//                resMap.get(key).put(name, unit.get(key));
-//            }
-//        }
-//        List<Map<String, Object>> dataset = ListUtil.list(false);
-//        resMap.forEach((k, v) -> dataset.add(MapUtil.<String, Object>builder("date", k).putAll(v).build()));
-//        dataset.forEach(e -> {
-//            String rank = MapUtil.getStr(e, rankFiled);
-//            String rankCnt = MapUtil.getStr(e, "strategy_rank_cnt");
-//            String strRank = null;
-//            if (CharSequenceUtil.isAllNotBlank(rank, rankCnt)) {
-//                strRank = StrUtil.subBefore(rank, ".", false) + "/"
-//                        + StrUtil.subBefore(rankCnt, ".", false);
-//            }
-//            e.put("rank", strRank);
-//            e.remove(rankFiled);
-//            e.remove("strategy_rank_cnt");
-//        });
-//        dataset.sort((o1, o2) -> MapUtil.getStr(o2, "date").compareTo(MapUtil.getStr(o1, "date")));
-//        return dataset;
-//    }
-//
-//    /**
-//     * 业绩走势接口业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    public Map<String, Object> trend(TrendParams params, List<TrendType> trendTypes, List<TrendType> indexTrendTypes) {
-//        try {
-//            // 1.参数处理
-//            List<String> refIds = params.getFundId();
-//            CommonData<Map<String, List<Map<String, Object>>>> data = this.handleTrends(params, trendTypes, indexTrendTypes, null);
-//            List<Map<String, String>> warnings = this.infoService.getWarningInfo(refIds, params.getStartDate(), params.getEndDate());
-//            data.getExtInfos().put("warning", warnings);
-//            return CommonUtil.covertToMap(data, "endDate", "startDate", "warning", "annualBenchmark", "annual");
-//        } catch (Exception e) {
-//            logger.error(String.format("业绩走势接口业务错误:%s", e.getMessage()), e);
-//
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    @Override
-//    public Map<String, Object> imfTrend(ImfTrendParams params) {
-//        String fundId = params.getFundId().get(0);
-//        List<TrendType> trendTypes = ListUtil.toList(TrendType.Ret, TrendType.Nav, TrendType.ExtraNav, TrendType.OrigNav, TrendType.NetValueChange, TrendType.ExtraRetGeo);
-//        List<TrendType> indexTrendTypes = ListUtil.toList(TrendType.Ret, TrendType.OrigNav);
-//        CommonData<Map<String, List<Map<String, Object>>>> data = this.handleTrends(params, trendTypes, indexTrendTypes, null);
-//        Map<String, List<Map<String, Object>>> dataset = data.getDataset();
-//        List<MonetaryFundProfitDO> doList = this.monetaryFundProfitBaseService.queryByFundId(fundId);
-//        dataset.forEach((k, v) -> {
-//            if (fundId.equals(k)) {
-//                for (Map<String, Object> map : v) {
-//                    String date = MapUtil.getStr(map, "date");
-//                    MonetaryFundProfitDO aDo = doList.stream().filter(e -> date.equals(DateUtil.formatDate(e.getPriceDate()))).findFirst().orElse(null);
-//                    map.put("profit", Optional.ofNullable(aDo).map(MonetaryFundProfitDO::getProfitPerMillion).orElse(null));
-//                    map.put("serven", Optional.ofNullable(aDo).map(MonetaryFundProfitDO::getProfitServenDayAnnual).orElse(null));
-//                }
-//            }
-//        });
-//        data.setDataset(dataset);
-//        return CommonUtil.covertToMap(data, "endDate", "startDate", "annualBenchmark", "annual");
-//    }
-//
-//    /**
-//     * 区间指标分析 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    public Map<String, Object> rangIndicator(RangIndicatorParams params, Map<TimeRange, String> rangeMap) {
-//        try {
-//            if (params.getIndicator() == null) {
-//                throw new APIException("分析的指标不能为空");
-//            }
-//            Function<IndicatorCalcTimeRangeDto, String> function = e -> e.getTimeRange().name();
-//            if (rangeMap != null && !rangeMap.isEmpty()) {
-//                function = e -> rangeMap.get(e.getTimeRange());
-//            }
-//            boolean excess = params.getExcess() == Boolean.TRUE || Indicator.INDICATOR_EXCESS_RETURN_TYPE_ARRAY.contains(params.getIndicator());
-//            CommonData<Map<String, Object>> data = this.analyzeMultiIndicator(params, params.getIndicator(), excess, params.getFrequency(), function);
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("区间指标分析接口业务错误:%s", e.getMessage()), e);
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    /**
-//     * 滚动指标分析 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    public Map<String, Object> rollIndicator(RollIndicatorParams params) {
-//        try {
-//            if (params.getIndicator() == null) {
-//                throw new APIException("分析的指标不能为空");
-//            }
-//            List<Frequency> frequencies = ListUtil.toList(Frequency.Monthly, Frequency.Quarterly, Frequency.Annually);
-//            if (params.getRollingFrequency() == null || !frequencies.contains(params.getRollingFrequency())) {
-//                logger.warn(String.format("当前滚动频率为:%s,设置为默认滚动频率:%s", params.getRollingFrequency(), Frequency.Monthly));
-//                params.setRollingFrequency(Frequency.Monthly);
-//            }
-//            CommonData<Map<String, Object>> data = this.analyzeIndicator(params, params.getIndicator(), DateIntervalType.DefaultRolling,
-//                    Indicator.INDICATOR_EXCESS_RETURN_TYPE_ARRAY.contains(params.getIndicator()), params.getRollingFrequency(), IndicatorCalcTimeRangeDto::getEndDate);
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("滚动指标分析接口业务错误:%s", e.getMessage()), e);
-//
-//        }
-//        return MapUtil.newHashMap();
-//    }
-//
-//    private <P extends BaseParams> CommonData<Map<String, Object>> analyzeMultiIndicator(P params, Indicator indicator, boolean excess,
-//                                                                                         Frequency rollingFrequency, Function<IndicatorCalcTimeRangeDto, String> function) {
-//        // 1.参数处理
-//        this.checkParams(params);
-//        List<String> refIds = params.getFundId();
-//        List<String> secIds = this.getSecIdsByParams(params);
-//        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//        List<Indicator> indicators = ListUtil.toList(Indicator.MaxDrawdown);
-//        List<Indicator> geoIndicators = ListUtil.list(false);
-//        if (excess) {
-//            geoIndicators.add(indicator);
-//        } else {
-//            indicators.add(indicator);
-//        }
-//        CalcMultipleSecMultipleTimeRangeIndicatorReq req;
-//
-//        req = this.buildMultiCalcReq(params, indicators, geoIndicators, rollingFrequency);
-//
-//        req.setRiskOfFreeId(RetConst.RISK_OF_FREE_1Y);
-//
-//        // 2、指标计�
-//        Map<String, List<IndicatorCalcPropertyDto>> indicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-//
-//        // 3、结果处�
-//        Map<TimeRange, Boolean> timeRangeFlag = MapUtil.newHashMap();
-//        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
-//        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
-//        for (String refId : refIds) {
-//            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(indicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
-//            // 当前基金的数据处�
-//            List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
-//            for (IndicatorCalcPropertyDto dto : dtos) {
-//                String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(function).orElse(null);
-//                String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
-//                TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
-//                if (timeRange == null || (id != null && YEAR_MONTH_ROLL_LIST.contains(id)) || timeRange == TimeRange.FromSetup) {
-//                    continue;
-//                }
-//                String start = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getStartDate).orElse(null);
-//                if (params.getStartDate() != null && start != null && params.getStartDate().compareTo(start) > 0) {
-//                    timeRangeFlag.put(timeRange, true);
-//                    continue;
-//                }
-//                // 如果是月�需要过滤掉近一�
-//                if (Frequency.Monthly == params.getFrequency()) {
-//                    if (timeRange == TimeRange.Last1Week) {
-//                        timeRangeFlag.put(TimeRange.Last1Week, true);
-//                        continue;
-//                    }
-//
-//                }
-//
-//                String value = Optional.ofNullable(dto.getSecData()).map(e -> excess ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap()).map(e -> e.get(indicator.name())).orElse(null);
-//                fundIndicatorList.add(MapUtil.<String, Object>builder("date", date).put("value", value).build());
-//            }
-//            valuesMap.put(refId, fundIndicatorList);
-//            // 指数的数据处�
-//            if (excess) {
-//                continue;
-//            }
-//            for (String indexId : indexIds) {
-//                if (indexValuesMap.containsKey(indexId)) {
-//                    continue;
-//                }
-//                List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
-//                for (IndicatorCalcPropertyDto dto : dtos) {
-//                    String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
-//                    String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(function).orElse(null);
-//                    TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
-//                    if (timeRange == null || date == null || timeRangeFlag.getOrDefault(timeRange, false) || (id != null && YEAR_MONTH_ROLL_LIST.contains(id))) {
-//                        continue;
-//                    }
-//                    String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(indicator.name())).orElse(null);
-//                    indexIndicatorList.add(MapUtil.<String, Object>builder("date", date).put("value", value).build());
-//                }
-//                indexValuesMap.put(indexId, indexIndicatorList);
-//            }
-//        }
-//        Map<String, Object> dataset = MapUtil.<String, Object>builder().putAll(valuesMap).putAll(indexValuesMap).build();
-//
-//        Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
-//        if (excess) {
-//            for (String indexId : indexIds) {
-//                productNameMapping.remove(indexId);
-//            }
-//        }
-//        Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
-//        return CommonData.<Map<String, Object>>builder().dataset(dataset).productNameMapping(productNameMapping).extInfos(extInfos).build();
-//    }
-//
-//    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildMultiCalcReq(BaseParams params, List<Indicator> indicatorList,
-//                                                                             List<Indicator> geoIndicatorList,
-//                                                                             Frequency frequency) {
-//        List<String> refIds = params.getFundId();
-//        List<DateIntervalDto> dateIntervalDtoList = new ArrayList<>();
-//        DateIntervalDto defaultIntervalDto = new DateIntervalDto();
-//        defaultIntervalDto.setEndDate(params.getEndDate());
-//        defaultIntervalDto.setFrequency(frequency);
-//        defaultIntervalDto.setDateIntervalType(DateIntervalType.DefaultInterval);
-//        dateIntervalDtoList.add(defaultIntervalDto);
-//
-//        DateIntervalDto customIntervalDto = new DateIntervalDto();
-//        customIntervalDto.setStartDate(params.getStartDate());
-//        customIntervalDto.setEndDate(params.getEndDate());
-//        customIntervalDto.setTimeRange(TimeRange.Custom);
-//        customIntervalDto.setFrequency(frequency);
-//        customIntervalDto.setDateIntervalType(DateIntervalType.CustomInterval);
-//        dateIntervalDtoList.add(customIntervalDto);
-//
-//        Map<String, List<DateIntervalDto>> dateIntervalMap = MapUtil.newHashMap(true);
-//        for (String refId : refIds) {
-//            dateIntervalMap.put(refId, dateIntervalDtoList);
-//        }
-//
-//        List<String> secIds = this.getSecIdsByParams(params);
-//        // 差集求指数id集合,包括基�
-//        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
-//        for (String refId : refIds) {
-//            if (StrUtil.isBlank(params.getBenchmarkId())) {
-//                continue;
-//            }
-//            benchmarkIdMap.put(refId, params.getBenchmarkId());
-//        }
-//        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
-//                .mainSecIdList(refIds) // 标的id集合
-//                .secBenchmarkIdMap(benchmarkIdMap) // 标的对应基准
-//                .indexIdList(indexIds) // 指数id集合,包括基�
-//                .raiseType(params.getRaiseType()) // 标的类型
-//                .strategy(this.getOriginStrategy(params)) // 二级策略
-//                .visibility(Visibility.Both)
-//                .dataFrequency(params.getFrequency()) // 净值频�
-//                .navType(params.getNavType()) // 净值类�
-//                .secDateIntervalDtoListMap(dateIntervalMap) // 日期区间
-//                .indicatorList(indicatorList) // 要计算的指标
-//                .geoExtraindicatorList(geoIndicatorList) // 要计算的几何指标
-//                .ifAnnualize(true) // 要年�
-//                .needExtraRet(true)
-//                .needRet(true)
-//                .calcIndexRetIndicatorValue(true) //
-//                .ifConvertPerformanceConsistencyWord(true).build();
-//    }
-//
-//    /**
-//     * 收益统计/收益分布 接口请求业务处理
-//     *
-//     * @param params 请求参数
-//     * @return /
-//     */
-//    public Map<String, Object> revenue(RevenueParams params) {
-//        try {
-//            // 1.参数处理
-//            this.checkParams(params);
-//            if (StrUtil.isBlank(params.getRevenuType()) || !TYPE_LIST.contains(params.getRevenuType())) {
-//                params.setRevenuType(ONE);
-//            }
-//            List<Frequency> frequencies = ListUtil.toList(Frequency.Weekly, Frequency.Monthly, Frequency.Quarterly, Frequency.Annually);
-//            if (params.getRollingFrequency() == null || !frequencies.contains(params.getRollingFrequency())) {
-//                logger.warn(String.format("当前滚动频率为:%s,设置为默认滚动频率:%s", params.getRollingFrequency(), Frequency.Monthly));
-//                params.setRollingFrequency(Frequency.Monthly);
-//            }
-//            //支持调整组距�-20%�
-//            if (TWO.equals(params.getRevenuType())) {
-//                if (!NumberUtil.isNumber(params.getSpace()) || !NumberUtil.isIn(NumberUtil.toBigDecimal(params.getSpace()), NumberUtil.toBigDecimal("1"), NumberUtil.toBigDecimal("20"))) {
-//                    throw new APIException("组距必须是大于1小于20的数");
-//                }
-//            }
-//            boolean ifExcessReturn = params.getIfExcessReturn() != null && params.getIfExcessReturn();
-//            List<String> refIds = params.getFundId();
-//            List<String> secIds = this.getSecIdsByParams(params);
-//            List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//            List<Indicator> indicators = ListUtil.toList(Indicator.IntervalReturn);
-//            CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, indicators, params.getRollingFrequency());
-//            req.setRiskOfFreeId(Consts.RISK_OF_FREE);
-//
-//            // 2、指标计�
-//            Map<String, List<IndicatorCalcPropertyDto>> secRangIndicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-//
-//            // 3、结果处�
-//            Map<String, Object> dataset = MapUtil.newHashMap();
-//            if (ONE.equals(params.getRevenuType())) {
-//                dataset = this.getRevenueDataset(refIds, indexIds, params.getRollingFrequency(), secRangIndicatorMap, ifExcessReturn);
-//            } else if (TWO.equals(params.getRevenuType())) {
-//                dataset = this.loadDistributionData(refIds, indexIds, secRangIndicatorMap, Double.parseDouble(params.getSpace()), ifExcessReturn);
-//            }
-//            Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
-//            Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
-//            if (ONE.equals(params.getRevenuType())) {
-//                // table
-//                HistoryRetTableSingleResp resp = getHistoryRetTableSingleResp(refIds, indexIds, secRangIndicatorMap, Indicator.IntervalReturn, ifExcessReturn, params.getRollingFrequency());
-//                extInfos.put("table", this.buildTableData(productNameMapping, resp, ifExcessReturn, false));
-//            }
-//            CommonData<Map<String, Object>> data = CommonData.<Map<String, Object>>builder().dataset(dataset).productNameMapping(productNameMapping).extInfos(extInfos).build();
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("收益统计/收益分布接口业务错误:%s", e.getMessage()), e);
-//            return MapUtil.newHashMap();
-//        }
-//    }
-//
-//    private Map<String, Object> getRevenueDataset(List<String> refIds, List<String> indexIds, Frequency frequency, Map<String, List<IndicatorCalcPropertyDto>> secRangIndicatorMap, boolean ifExcessReturn) {
-//        Map<String, Object> dataset = MapUtil.newHashMap();
-//        Map<String, List<Map<String, Object>>> valuesMap = MapUtil.newHashMap(true);
-//        Map<String, List<Map<String, Object>>> indexValuesMap = MapUtil.newHashMap(true);
-//        List<String> dateList = ListUtil.list(false);
-//        for (String refId : refIds) {
-//            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(secRangIndicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
-//            // 当前基金的数据处�
-//            List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
-//            for (IndicatorCalcPropertyDto dto : dtos) {
-//                String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
-//                String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
-//                if (id == null || YEAR_MONTH_ROLL_LIST.contains(id)) {
-//                    continue;
-//                }
-//                date = this.handleStrDate(date, frequency);
-//                if (!dateList.contains(date)) {
-//                    dateList.add(date);
-//                }
-//                String value = Optional.ofNullable(dto.getSecData()).map(IndicatorCalcSecDataDto::getIndicatorValueMap).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
-//                String extraValue = Optional.ofNullable(dto.getSecData()).map(IndicatorCalcSecDataDto::getExtraGeoIndicatorValueMap).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
-//                Map<String, Object> build = MapUtil.<String, Object>builder("date", date).put("d", date).put("extraValue", extraValue).put("value", value).build();
-//                fundIndicatorList.add(build);
-//            }
-//            valuesMap.put(refId, fundIndicatorList);
-//            // 指数的数据处�
-//            for (String indexId : indexIds) {
-//                if (indexValuesMap.containsKey(indexId)) {
-//                    continue;
-//                }
-//                List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
-//                for (IndicatorCalcPropertyDto dto : dtos) {
-//                    String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
-//                    if (id == null || YEAR_MONTH_ROLL_LIST.contains(id)) {
-//                        continue;
-//                    }
-//                    String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
-//                    date = this.handleStrDate(date, frequency);
-//                    String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
-//                    indexIndicatorList.add(MapUtil.<String, Object>builder("date", date).put("value", value).build());
-//                }
-//                indexValuesMap.put(indexId, indexIndicatorList);
-//            }
-//        }
-//        dateList.sort(Comparator.naturalOrder());
-//        for (String refId : refIds) {
-//            List<Map<String, Object>> data = ListUtil.list(true);
-//            for (String date : dateList) {
-//                String value = valuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
-//                        .findFirst().map(e -> MapUtil.getStr(e, "value")).orElse(null);
-//                Map<String, Object> build = MapUtil.<String, Object>builder().put("date", date).put("value", value).build();
-//                if (ifExcessReturn) {
-//                    String extraValue = valuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
-//                            .findFirst().map(e -> MapUtil.getStr(e, "extraValue")).orElse(null);
-//                    build.put("extraValue", extraValue);
-//                }
-//                data.add(build);
-//            }
-//            dataset.put(refId, data);
-//        }
-//        for (String refId : indexIds) {
-//            List<Map<String, Object>> data = ListUtil.list(true);
-//            for (String date : dateList) {
-//                String value = indexValuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
-//                        .findFirst().map(e -> MapUtil.getStr(e, "value")).orElse(null);
-//                data.add(MapUtil.<String, Object>builder().put("date", date).put("value", value).build());
-//            }
-//            dataset.put(refId, data);
-//        }
-//        return dataset;
-//    }
-//
-//    /**
-//     * 胜率分析 业务处理
-//     *
-//     * @param params /
-//     * @return /
-//     */
-//    public Map<String, Object> win(WinParams params) {
-//        try {
-//            // 1.参数处理
-//            this.checkParams(params);
-//            List<String> refIds = params.getFundId();
-//            if (refIds.size() > 1) {
-//                logger.warn("多标的不支持胜率分析!");
-//            }
-//            String fundId = refIds.get(0);
-//            Indicator indicator = Indicator.WinRate;
-//            boolean winZero = params.getWinRateBmk() == WinRateBmk.Zero;
-//            List<Indicator> indicators = ListUtil.toList(Indicator.IntervalReturn, indicator);
-//
-//            CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, ListUtil.list(false), DateIntervalType.CustomInterval, null);
-//            req.setRiskOfFreeId(Consts.RISK_OF_FREE);
-//            req.setIndexIdList(ListUtil.empty());
-//            req.setNeedRet(true);
-//            req.setNeedExtraRet(true);
-//            if (!winZero) {
-//                req.setGeoExtraindicatorList(ListUtil.toList(indicator));
-//            }
-//
-//            // 2、指标计�
-//            Map<String, List<IndicatorCalcPropertyDto>> secIndicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-//
-//            // 3、结果处�
-//            IndicatorCalcSecDataDto secData = Optional.ofNullable(secIndicatorMap.get(fundId)).filter(e -> !e.isEmpty()).map(e -> e.get(0))
-//                    .map(IndicatorCalcPropertyDto::getSecData).orElseThrow(() -> new APIException("计算错误"));
-//            String winRate = winZero ? secData.getIndicatorValueMap().get(indicator.name()) : secData.getExtraGeoIndicatorValueMap().get(indicator.name());
-//            List<CompoundRet> retList = secData.getRetList();
-//            // 返回结果对象构建
-//            Map<String, String> winData = this.prepareWinRateData("allTime", winRate, retList, winZero);
-//            Double lower = Optional.ofNullable(params.getLower()).map(Double::parseDouble).map(e -> e / 100).orElse(-0.03d);
-//            Double upper = Optional.ofNullable(params.getUpper()).map(Double::parseDouble).map(e -> e / 100).orElse(0.03d);
-//            List<CompoundRet> riseRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() >= upper).collect(Collectors.toList());
-//            List<CompoundRet> fallRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() <= lower).collect(Collectors.toList());
-//            List<CompoundRet> shockRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() <= upper && e.getRetOfBmk() >= lower).collect(Collectors.toList());
-//            List<Map<String, String>> marketWinData = ListUtil.list(true);
-//            Map<String, List<CompoundRet>> timeMap = MapUtil.<String, List<CompoundRet>>builder(MapUtil.newHashMap(true))
-//                    .put("allTime", retList).put("riseTime", riseRetList).put("shockTime", shockRetList).put("fallTime", fallRetList).build();
-//            if (winZero) {
-//                timeMap.remove("shockTime");
-//            }
-//            timeMap.forEach((k, v) -> marketWinData.add(this.prepareWinRateData(k, winRate, v, winZero)));
-//
-//            Map<String, Object> dataset = MapUtil.<String, Object>builder("win", winData).put("marketWin", marketWinData).build();
-//            CommonData<Map<String, Object>> data = CommonData.<Map<String, Object>>builder().dataset(dataset).build();
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("胜率计算错误:%s", e.getMessage()), e);
-//            return MapUtil.newHashMap();
-//        }
-//    }
-//
-//    @Override
-//    public Map<String, Object> analyzeIndicatorNew(RangIndicatorParams params) {
-//        // 1.参数处理
-//        this.checkParams(params);
-//        List<String> refIds = params.getFundId();
-//        List<String> secIds = this.getSecIdsByParams(params);
-//        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//        Indicator indicator = params.getIndicator();
-//        List<Indicator> indicators = ListUtil.toList(Indicator.MaxDrawdown);
-//        List<Indicator> geoIndicators = ListUtil.list(false);
-//        boolean excess = params.getExcess() != null && params.getExcess() || Indicator.INDICATOR_EXCESS_RETURN_TYPE_ARRAY.contains(params.getIndicator());
-//        if (excess) {
-//            geoIndicators.add(indicator);
-//        } else {
-//            indicators.add(indicator);
-//        }
-//
-//        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, geoIndicators, DateIntervalType.DefaultInterval, null);
-//        req.setRiskOfFreeId(Consts.RISK_OF_FREE);
-//
-//        // 2、指标计�
-//        Map<String, List<IndicatorCalcPropertyDto>> indicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
-//
-//        // 3、结果处�
-//        Map<TimeRange, Boolean> timeRangeFlag = MapUtil.newHashMap();
-//        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
-//        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
-//        for (String refId : refIds) {
-//            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(indicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
-//            // 当前基金的数据处�
-//            List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
-//            for (IndicatorCalcPropertyDto dto : dtos) {
-//                TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto)
-//                        .map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
-//                if (timeRange == null) {
-//                    continue;
-//                }
-//                if (params.getTimeRange() != null) {
-//                    String start = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getStartDate).orElse(null);
-//                    boolean isFrom = timeRange != TimeRange.FromSetup && timeRange != TimeRange.FromThisYear;
-//                    boolean isDate = CharSequenceUtil.compare(params.getStartDate(), start, true) > 0;
-//                    if (isFrom && isDate) {
-//                        timeRangeFlag.put(timeRange, true);
-//                        continue;
-//                    }
-//                }
-//                String value = Optional.ofNullable(dto.getSecData()).map(e -> excess ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap())
-//                        .map(e -> e.get(indicator.name())).orElse(null);
-//                fundIndicatorList.add(MapUtil.<String, Object>builder("date", this.handleStrDate(timeRange.name(), null)).put("value", value).build());
-//            }
-//            valuesMap.put(refId, fundIndicatorList);
-//            // 指数的数据处�
-//            for (String indexId : indexIds) {
-//                boolean excessBench = (excess && indexId.equals(params.getBenchmarkId()));
-//                if (indexValuesMap.containsKey(indexId) || excessBench) {
-//                    continue;
-//                }
-//                List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
-//                for (IndicatorCalcPropertyDto dto : dtos) {
-//                    TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto)
-//                            .map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
-//                    if (timeRange == null || timeRangeFlag.getOrDefault(timeRange, false)) {
-//                        continue;
-//                    }
-//                    String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(indicator.name())).orElse(null);
-//                    indexIndicatorList.add(MapUtil.<String, Object>builder("date", this.handleStrDate(timeRange.name(), null)).put("value", value).build());
-//                }
-//                indexValuesMap.put(indexId, indexIndicatorList);
-//            }
-//        }
-//        Map<String, Object> dataset = MapUtil.<String, Object>builder().putAll(valuesMap).putAll(indexValuesMap).build();
-//
-//        Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
-//        if (excess) {
-//            for (String indexId : indexIds) {
-//                productNameMapping.remove(indexId);
-//            }
-//        }
-//        Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
-//        CommonData<Map<String, Object>> data = CommonData.<Map<String, Object>>builder().dataset(dataset).productNameMapping(productNameMapping).extInfos(extInfos).build();
-//        return CommonUtil.covertToMap(data);
-//    }
-//
-//    @Override
-//    public Map<String, Object> analyzeCovNew(AnalyzeCovParams params) {
-//        try {
-//            // 1.参数处理
-//            this.checkParams(params);
-//            String startDate = params.getStartDate();
-//            String endDate = params.getEndDate();
-//            List<String> refIds = params.getFundId();
-//            String fundId = refIds.get(0);
-//            List<Map<String, String>> secTimeRanges = this.baseIndicatorServiceV2.getSecTimeRanges(fundId, params.getRaiseType(), Strategy.All, Visibility.Both);
-//            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();
-//            if (dateRangeList.isEmpty()) {
-//                throw new APIException("净值数量小于窗口期,请尝试调整取值区间");
-//            }
-//            Map<String, List<Double>> corrData = MapUtil.newHashMap();
-//            List<String> dates = ListUtil.list(true);
-//            List<Map<String, Object>> corRetList = ListUtil.list(false);
-//            List<List<Map<String, Object>>> matrixList = this.getMatrixList(params, dateRangeList, dates, corrData, corRetList);
-//            List<Map<String, Object>> dataList = ListUtil.list(true);
-//            for (int i = 0; i < dates.size(); i++) {
-//                Object values = matrixList.get(i).get(0).get("values");
-//                dataList.add(MapUtil.<String, Object>builder("date", dates.get(i))
-//                        .put("matrix", values).build());
-//            }
-//            Map<String, Object> dataset = MapUtil.<String, Object>builder(fundId, dataList).build();
-//            for (String indexId : indexIds) {
-//                List<Map<String, Object>> indexDataList = ListUtil.list(true);
-//                for (int i = 0; i < dates.size(); i++) {
-//                    Object values = matrixList.get(i).stream().filter(e -> Objects.equals(indexId, e.get("id"))).findFirst()
-//                            .map(e -> e.get("values")).orElse(null);
-//                    indexDataList.add(MapUtil.<String, Object>builder("date", dates.get(i))
-//                            .put("value", corrData.get(indexId).get(i))
-//                            .put("matrix", values).build());
-//                }
-//                dataset.put(indexId, indexDataList);
-//            }
-//            String endDate1 = null;
-//            Map<String, String> timeRangeMap = MapUtil.newHashMap();
-//            for (Map<String, String> timeRange : secTimeRanges) {
-//                if (StrUtil.isBlank(endDate1)) {
-//                    endDate1 = timeRange.get("endDate");
-//                }
-//                timeRangeMap.put(timeRange.get("name"), timeRange.get("startDate"));
-//            }
-//            List<Map<String, Object>> resultList = ListUtil.list(true);
-//            Map<TimeRange, String> yearOptions = TimeRange.COR_DATES;
-//            yearOptions.forEach((k, v) -> {
-//                Map<String, Object> result = MapUtil.newHashMap();
-//                result.put("id", v);
-//                result.put("range", k);
-//                result.put("startDate", timeRangeMap.get(k.name()) == null ? null : timeRangeMap.get(k.name()));
-//                resultList.add(result);
-//            });
-//            List<Map<String, Object>> dataset2 = getDataset(params, refIds, indexIds, corRetList, endDate1, resultList);
-//
-//            // 直接把原数据转换一�
-//            Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
-//            Map<String, Object> extInfos = MapUtil.<String, Object>builder().put("table", dataset2).build();
-//            CommonData<Map<String, Object>> data = CommonData.<Map<String, Object>>builder()
-//                    .dataset(dataset).productNameMapping(productNameMapping).extInfos(extInfos).build();
-//            return CommonUtil.covertToMap(data);
-//        } catch (Exception e) {
-//            logger.error(String.format("相关性分析错误:%s", e.getMessage()), e);
-//            return MapUtil.newHashMap();
-//        }
-//    }
-//
-//    private List<List<Map<String, Object>>> getMatrixList(AnalyzeCovParams params, List<DateRange> dateRangeList, List<String> dates, Map<String,
-//            List<Double>> corrData, List<Map<String, Object>> corRetList) {
-//        List<List<Map<String, Object>>> matrixList = ListUtil.list(false);
-//        List<String> refIds = params.getFundId();
-//        String fundId = refIds.get(0);
-//        List<String> secIds = this.getSecIdsByParams(params);
-//        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
-//        IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
-//        List<Map<String, String>> secTimeRanges = this.baseIndicatorServiceV2.getSecTimeRanges(fundId, params.getRaiseType(), strategy, Visibility.Both);
-//        String incepStart = null;
-//        String incepEnd = null;
-//        if (CollUtil.isNotEmpty(secTimeRanges)) {
-//            for (Map<String, String> secTimeRange : secTimeRanges) {
-//                if (secTimeRange.get("name").equals(TimeRange.FromSetup.name())) {
-//                    incepStart = secTimeRange.get("startDate");
-//                    incepEnd = secTimeRange.get("endDate");
-//                }
-//            }
-//        }
-//        Frequency frequency = params.getFrequency();
-//        if (frequency == null || frequency == Frequency.Default) {
-//            frequency = Frequency.Daily;
-//        }
-//        Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew = this.baseIndicatorServiceV2.getMultiSecRetListNew(
-//                secIds, ListUtil.empty(), frequency, Frequency.Daily, incepStart, incepEnd, false, params.getBenchmarkId(),
-//                params.getRaiseType(), strategy, Visibility.Visible, params.getNavType(), isExtract, params.getUserId());
-//        if (CollectionUtil.isEmpty(indexIds)) {
-//            throw new APIException("指数不能为空");
-//        }
-//        List<Map<String, Object>> mapList = NavUtil.handleNextStepNew(secIds, indexIds, multiSecRetListNew, false);
-//        corRetList.addAll(mapList);
-//        for (DateRange dr : dateRangeList) {
-//            String start = dr.getStartDate();
-//            String end = dr.getEndDate();
-//            dates.add(end);
-//            Map<String, Map<String, Double>> retMap = findRetData(corRetList, start, end);
-//            Double[][] correlationMatrix = CalcUtils.getCorrelationMatrix(retMap, refIds, indexIds);
-//            Double[] values = correlationMatrix[0];
-//            for (int i = 0; i < values.length; i++) {
-//                String idx = indexIds.get(i);
-//                List<Double> cList = corrData.getOrDefault(idx, new ArrayList<>());
-//                cList.add(values[i]);
-//                corrData.put(idx, cList);
-//            }
-//            // 相关性矩�
-//            Double[][] matrix = CalcUtils.getCorrelationMatrix(retMap, secIds, secIds);
-//            List<Map<String, Object>> rowList = new ArrayList<>(matrix.length);
-//            for (int i = 0; i < matrix.length; i++) {
-//                rowList.add(MapUtil.<String, Object>builder("id", secIds.get(i)).put("values", matrix[i]).build());
-//            }
-//            matrixList.add(rowList);
-//        }
-//        return matrixList;
-//    }
-//
-//    private List<Map<String, Object>> getDataset(AnalyzeCovParams params, List<String> refIds, List<String> indexIds, List<Map<String, Object>> corRetList,
-//                                                 String endDate1, List<Map<String, Object>> resultList) {
-//        // 除了成立以来  今年以来 其他都需要加上过滤条�只要开始日期大于等�前端传参的开始日�
-//        List<Map<String, Object>> dataset2 = ListUtil.list(true);
-//        for (Map<String, Object> timeRange : resultList) {
-//            Map<String, Object> temp = MapUtil.newHashMap();
-//            String start = MapUtil.getStr(timeRange, "startDate");
-//            if (StrUtil.isBlank(start)) {
-//                continue;
-//            }
-//            TimeRange range = (TimeRange) timeRange.get("range");
-//            boolean isTime = range != TimeRange.FromSetup && range != TimeRange.FromThisYear;
-//            if (isTime && params.getStartDate().compareTo(start) > 0) {
-//                continue;
-//            }
-//
-//            Map<String, Map<String, Double>> retMap = findRetData(corRetList, start, endDate1);
-//            Double[][] correlationMatrix = CalcUtils.getCorrelationMatrix(retMap, refIds, indexIds);
-//            Double[] values = correlationMatrix[0];
-//            temp.put("timeRange", timeRange.get("id"));
-//            for (int i = 0; i < indexIds.size(); i++) {
-//                temp.put(indexIds.get(i), values[i]);
-//            }
-//            dataset2.add(temp);
-//        }
-//        return dataset2;
-//    }
-//}

+ 207 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/CorrelationHandler.java

@@ -0,0 +1,207 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.CorrelationParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.analysis.domain.service.NavService;
+import com.smppw.analysis.infrastructure.exception.APIException;
+import com.smppw.common.pojo.dto.DateRange;
+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.Frequency;
+import com.smppw.common.pojo.enums.TimeRange;
+import com.smppw.common.pojo.enums.Visibility;
+import com.smppw.common.rollrange.RollingSpliter;
+import com.smppw.core.IndicatorService;
+import com.smppw.utils.CalcUtils;
+import com.smppw.utils.NavUtil;
+import com.smppw.utils.StrategyHandleUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+@Component(PerformanceConstants.CORRELATION)
+public class CorrelationHandler extends AbstractSingleSecPerformance<CorrelationParams, Map<String, Object>> {
+    private final NavService navService;
+
+    public CorrelationHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2, NavService navService) {
+        super(baseInfoService, baseIndicatorServiceV2);
+        this.navService = navService;
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(CorrelationParams params) {
+        String startDate = params.getStartDate();
+        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());
+        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();
+        if (dateRangeList.isEmpty()) {
+            throw new APIException("净值数量小于窗口期,请尝试调整取值区间");
+        }
+        Map<String, List<Double>> corrData = MapUtil.newHashMap();
+        List<String> dates = ListUtil.list(true);
+        List<Map<String, Object>> corRetList = ListUtil.list(false);
+        List<List<Map<String, Object>>> matrixList = this.getMatrixList(params, dateRangeList, dates, corrData, corRetList, allNavMap);
+        List<Map<String, Object>> dataList = ListUtil.list(true);
+        for (int i = 0; i < dates.size(); i++) {
+            Object values = matrixList.get(i).get(0).get("values");
+            dataList.add(MapUtil.<String, Object>builder("date", dates.get(i)).put("matrix", values).build());
+        }
+        Map<String, Object> dataset = MapUtil.<String, Object>builder(fundId, dataList).build();
+        for (String indexId : indexIds) {
+            List<Map<String, Object>> indexDataList = ListUtil.list(true);
+            for (int i = 0; i < dates.size(); i++) {
+                Object values = matrixList.get(i).stream().filter(e -> Objects.equals(indexId, e.get("id"))).findFirst()
+                        .map(e -> e.get("values")).orElse(null);
+                indexDataList.add(MapUtil.<String, Object>builder("date", dates.get(i))
+                        .put("value", corrData.get(indexId).get(i)).put("matrix", values).build());
+            }
+            dataset.put(indexId, indexDataList);
+        }
+        String endDate1 = null;
+        Map<String, String> timeRangeMap = MapUtil.newHashMap();
+        for (IndicatorCalcTimeRangeDto timeRange : secTimeRanges) {
+            if (StrUtil.isBlank(endDate1)) {
+                endDate1 = timeRange.getEndDate();
+            }
+            timeRangeMap.put(timeRange.getTimeRange().name(), timeRange.getStartDate());
+        }
+        List<Map<String, Object>> resultList = ListUtil.list(true);
+        Map<TimeRange, String> yearOptions = TimeRange.COR_DATES;
+        yearOptions.forEach((k, v) -> {
+            Map<String, Object> result = MapUtil.newHashMap();
+            result.put("id", v);
+            result.put("range", k);
+            result.put("startDate", timeRangeMap.get(k.name()) == null ? null : timeRangeMap.get(k.name()));
+            resultList.add(result);
+        });
+        List<Map<String, Object>> dataset2 = getDataset(params, refIds, indexIds, corRetList, endDate1, resultList);
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder().put("table", dataset2).build();
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).putAll(extInfos).build();
+    }
+
+    private List<List<Map<String, Object>>> getMatrixList(CorrelationParams params, List<DateRange> dateRangeList, List<String> dates, Map<String,
+            List<Double>> corrData, List<Map<String, Object>> corRetList, Map<String, List<DateValue>> allNavMap) {
+        List<List<Map<String, Object>>> matrixList = ListUtil.list(false);
+        List<String> refIds = params.getRefIds();
+        String fundId = refIds.get(0);
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        List<IndicatorCalcTimeRangeDto> secTimeRanges = IndicatorService.getInstance().getSecTimeRange(fundId, params.getFrequency(), allNavMap);
+        String incepStart = null;
+        String incepEnd = null;
+        if (CollUtil.isNotEmpty(secTimeRanges)) {
+            for (IndicatorCalcTimeRangeDto secTimeRange : secTimeRanges) {
+                if (TimeRange.FromSetup == secTimeRange.getTimeRange()) {
+                    incepStart = secTimeRange.getStartDate();
+                    incepEnd = secTimeRange.getEndDate();
+                }
+            }
+        }
+        Frequency frequency = params.getFrequency();
+        if (frequency == null || frequency == Frequency.Default) {
+            frequency = Frequency.Daily;
+        }
+        Map<String, List<IndicatorCalcPropertyDto>> multiSecRetListNew = this.baseIndicatorServiceV2.getMultiSecRetListNew(
+                secIds, ListUtil.empty(), frequency, Frequency.Daily, incepStart, incepEnd, false, params.getBenchmarkId(),
+                params.getRaiseType(), StrategyHandleUtils.getStrategy(params.getStrategy()), Visibility.Visible, params.getNavType(), allNavMap);
+        if (CollectionUtil.isEmpty(indexIds)) {
+            throw new APIException("指数不能为空");
+        }
+        List<Map<String, Object>> mapList = NavUtil.handleNextStepNew(secIds, indexIds, multiSecRetListNew, false);
+        corRetList.addAll(mapList);
+        for (DateRange dr : dateRangeList) {
+            String start = dr.getStartDate();
+            String end = dr.getEndDate();
+            dates.add(end);
+            Map<String, Map<String, Double>> retMap = findRetData(corRetList, start, end);
+            Double[][] correlationMatrix = CalcUtils.getCorrelationMatrix(retMap, refIds, indexIds);
+            Double[] values = correlationMatrix[0];
+            for (int i = 0; i < values.length; i++) {
+                String idx = indexIds.get(i);
+                List<Double> cList = corrData.getOrDefault(idx, new ArrayList<>());
+                cList.add(values[i]);
+                corrData.put(idx, cList);
+            }
+            // 相关性矩�
+            Double[][] matrix = CalcUtils.getCorrelationMatrix(retMap, secIds, secIds);
+            List<Map<String, Object>> rowList = new ArrayList<>(matrix.length);
+            for (int i = 0; i < matrix.length; i++) {
+                rowList.add(MapUtil.<String, Object>builder("id", secIds.get(i)).put("values", matrix[i]).build());
+            }
+            matrixList.add(rowList);
+        }
+        return matrixList;
+    }
+
+    private List<Map<String, Object>> getDataset(CorrelationParams params, List<String> refIds, List<String> indexIds, List<Map<String, Object>> corRetList,
+                                                 String endDate1, List<Map<String, Object>> resultList) {
+        // 除了成立以来  今年以来 其他都需要加上过滤条�只要开始日期大于等�前端传参的开始日�
+        List<Map<String, Object>> dataset2 = ListUtil.list(true);
+        for (Map<String, Object> timeRange : resultList) {
+            Map<String, Object> temp = MapUtil.newHashMap();
+            String start = MapUtil.getStr(timeRange, "startDate");
+            if (StrUtil.isBlank(start)) {
+                continue;
+            }
+            TimeRange range = (TimeRange) timeRange.get("range");
+            boolean isTime = range != TimeRange.FromSetup && range != TimeRange.FromThisYear;
+            if (isTime && params.getStartDate().compareTo(start) > 0) {
+                continue;
+            }
+
+            Map<String, Map<String, Double>> retMap = this.findRetData(corRetList, start, endDate1);
+            Double[][] correlationMatrix = CalcUtils.getCorrelationMatrix(retMap, refIds, indexIds);
+            Double[] values = correlationMatrix[0];
+            temp.put("timeRange", timeRange.get("id"));
+            for (int i = 0; i < indexIds.size(); i++) {
+                temp.put(indexIds.get(i), values[i]);
+            }
+            dataset2.add(temp);
+        }
+        return dataset2;
+    }
+
+    private Map<String, Map<String, Double>> findRetData(List<Map<String, Object>> dataList, String start, String end) {
+        Map<String, Map<String, Double>> map = MapUtil.newHashMap();
+        for (Map<String, Object> m : dataList) {
+            if (null == m) {
+                continue;
+            }
+            String endDate = m.get("end_date") + "";
+            if (start.compareTo(endDate) <= 0 && end.compareTo(endDate) >= 0) {
+                String fundId = m.get("fund_id") + "";
+                Object retRange = m.get("ret_range");
+                Double ret = null;
+                if (null != retRange) {
+                    try {
+                        ret = Double.parseDouble(retRange + "");
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                } else {
+                    continue;
+                }
+                Map<String, Double> dataMap = map.getOrDefault(fundId, new LinkedHashMap<>());
+                dataMap.put(endDate, ret);
+                map.put(fundId, dataMap);
+            }
+        }
+        return map;
+    }
+}

+ 42 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/ImfTrendHandler.java

@@ -0,0 +1,42 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.map.MapUtil;
+import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
+import com.smppw.analysis.domain.dto.performance.TrendParams;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Component(PerformanceConstants.IMF)
+public class ImfTrendHandler extends TrendHandler {
+    public ImfTrendHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected Map<String, Object> bizSecHandle(TrendParams params) {
+        String fundId = params.getRefIds().get(0);
+        Map<String, Object> result = super.bizSecHandle(params);
+        Map<String, List<Map<String, Object>>> dataset = MapUtil.get(result, "dataset", Map.class);
+        List<MonetaryFundProfitDO> doList = this.baseInfoService.queryMonetaryFund(fundId);
+        dataset.forEach((k, v) -> {
+            if (fundId.equals(k)) {
+                for (Map<String, Object> map : v) {
+                    String date = MapUtil.getStr(map, "date");
+                    MonetaryFundProfitDO aDo = doList.stream().filter(e -> date.equals(DateUtil.formatDate(e.getPriceDate()))).findFirst().orElse(null);
+                    map.put("profit", Optional.ofNullable(aDo).map(MonetaryFundProfitDO::getProfitPerMillion).orElse(null));
+                    map.put("serven", Optional.ofNullable(aDo).map(MonetaryFundProfitDO::getProfitServenDayAnnual).orElse(null));
+                }
+            }
+        });
+        result.put("dataset", dataset);
+        return result;
+    }
+}

+ 118 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/IndicatorHandler.java

@@ -0,0 +1,118 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.IndicatorParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcIndexDataDto;
+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.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.constants.Consts;
+import com.smppw.core.reta.calc.PerformanceConsistency;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Component(PerformanceConstants.INDICATOR)
+public class IndicatorHandler extends AbstractSingleSecPerformance<IndicatorParams, Map<String, Object>> {
+    public IndicatorHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(IndicatorParams params, DateIntervalType dateIntervalType) {
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = super.buildCalcReq(params, dateIntervalType);
+        String riskOfFreeId = params.getRiskOfFreeId();
+        Double riskOfFreeValue = params.getRiskOfFreeValue();
+        if (StrUtil.isBlank(riskOfFreeId)) {
+            riskOfFreeId = Consts.RISK_OF_FREE;
+        } else if (NumberUtil.isNumber(riskOfFreeId)) {
+            riskOfFreeValue = Double.parseDouble(riskOfFreeId);
+            riskOfFreeId = null;
+        }
+        req.setRiskOfFreeId(riskOfFreeId);
+        req.setRiskOfFreeValue(riskOfFreeValue);
+        req.setIndicatorList(params.getIndicators());
+        req.setGeoExtraindicatorList(params.getExtraIndicators());
+        return req;
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(IndicatorParams params) {
+        // 1.参数处理
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, DateIntervalType.CustomInterval);
+        // 2.指标计算
+        Map<String, List<IndicatorCalcPropertyDto>> indicator = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
+        // 3.返回结果处理
+        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
+        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            IndicatorCalcPropertyDto dto = Optional.ofNullable(indicator.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
+            // 标的指标
+            Map<String, String> indicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getIndicatorValueMap).orElse(MapUtil.empty());
+            // 标的几何指标
+            Map<String, String> geoIndicatorValues = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getExtraGeoIndicatorValueMap).orElse(MapUtil.empty());
+            // 指数指标
+            Map<String, Map<String, String>> indexIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).orElse(MapUtil.empty());
+            // 指数几何指标
+            Map<String, Map<String, String>> indexGeoIndicatorValuesMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexGeoExtraIndicatorValueMap).orElse(MapUtil.empty());
+            // 标的和指数分别处理最大回撤指标,并合并指标结果到一个map
+            Map<String, String> values = this.handleMaxDrawdown(indicatorValues, refId, null, false);
+            Map<String, String> geoValues = this.handleMaxDrawdown(geoIndicatorValues, refId, null, true);
+            Map<String, String> unionValues = MapUtil.<String, String>builder().putAll(values).putAll(geoValues).build();
+            valuesMap.put(refId, unionValues);
+            for (String indexId : indexIds) {
+                Map<String, String> indexValues = this.handleMaxDrawdown(indexIndicatorValuesMap.get(indexId), indexId, null, false);
+                Map<String, String> indexGeoValues = this.handleMaxDrawdown(indexGeoIndicatorValuesMap.get(indexId), indexId, params.getBenchmarkId(), true);
+                Map<String, String> unionIndexValues = MapUtil.<String, String>builder().putAll(indexValues).putAll(indexGeoValues).build();
+                indexValuesMap.put(indexId, unionIndexValues);
+            }
+        }
+        // 返回结果对象构建
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        Map<String, Object> dataset = MapUtil.builder(valuesMap).putAll(indexValuesMap).build();
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).build();
+    }
+
+    protected Map<String, String> handleMaxDrawdown(Map<String, String> indicatorValues, String secId, String benchmarkId, boolean geo) {
+        Map<String, String> result = MapUtil.newHashMap();
+        String maxDrawdown = indicatorValues.get(Indicator.MaxDrawdown.name());
+        String consistency = indicatorValues.get(Indicator.PerformanceConsistency.name());
+        if (StrUtil.isNotBlank(maxDrawdown) && new BigDecimal(maxDrawdown).compareTo(BigDecimal.ZERO) > 0) {
+            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureDate.name()))) {
+                indicatorValues.put(Indicator.MaxDrawdownRecureDate.name(), "最大回撤未修复");
+            }
+            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureIntervalDays.name()))) {
+                indicatorValues.put(Indicator.MaxDrawdownRecureIntervalDays.name(), "最大回撤未修复");
+            }
+            if (StrUtil.isBlank(indicatorValues.get(Indicator.MaxDrawdownRecureInterval.name()))) {
+                indicatorValues.put(Indicator.MaxDrawdownRecureInterval.name(), "最大回撤未修复");
+            }
+        }
+        if (StrUtil.isEmpty(consistency)) {
+            indicatorValues.put(Indicator.PerformanceConsistency.name(), PerformanceConsistency.convert2Word(null));
+        } else {
+            indicatorValues.put(Indicator.PerformanceConsistency.name(), PerformanceConsistency.convert2Word(Double.parseDouble(consistency)));
+        }
+        if (geo) {
+            indicatorValues.forEach((k, v) -> result.put("geoExcess" + k, secId != null && secId.equals(benchmarkId) ? null : v));
+        } else {
+            result.putAll(indicatorValues);
+        }
+        return result;
+    }
+}

+ 117 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/IntervalHandler.java

@@ -0,0 +1,117 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import com.smppw.analysis.domain.dto.performance.IntervalParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcIndexDataDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcReqPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcTimeRangeDto;
+import com.smppw.common.pojo.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
+import com.smppw.common.pojo.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.common.pojo.enums.TimeRange;
+import com.smppw.constants.Consts;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Component(PerformanceConstants.INTERVAL)
+public class IntervalHandler extends AbstractSingleSecPerformance<IntervalParams, Map<String, Object>> {
+    public IntervalHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(IntervalParams params, DateIntervalType dateIntervalType) {
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = super.buildCalcReq(params, dateIntervalType);
+        Indicator indicator = params.getIndicator();
+        List<Indicator> indicators = ListUtil.toList(Indicator.MaxDrawdown);
+        List<Indicator> geoIndicators = ListUtil.list(false);
+        boolean excess = params.getExcess() != null && params.getExcess();
+        if (excess) {
+            geoIndicators.add(indicator);
+        } else {
+            indicators.add(indicator);
+        }
+        req.setIndicatorList(indicators);
+        req.setGeoExtraindicatorList(geoIndicators);
+        req.setRiskOfFreeId(Consts.RISK_OF_FREE);
+        return req;
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(IntervalParams params) {
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        Indicator indicator = params.getIndicator();
+        boolean excess = params.getExcess() != null && params.getExcess();
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, DateIntervalType.DefaultInterval);
+        Map<String, List<IndicatorCalcPropertyDto>> indicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
+        Map<TimeRange, Boolean> timeRangeFlag = MapUtil.newHashMap();
+        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
+        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(indicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
+            // 当前基金的数据处�
+            List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
+            for (IndicatorCalcPropertyDto dto : dtos) {
+                TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto)
+                        .map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
+                if (timeRange == null) {
+                    continue;
+                }
+                if (params.getTimeRange() != null) {
+                    String start = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getStartDate).orElse(null);
+                    boolean isFrom = timeRange != TimeRange.FromSetup && timeRange != TimeRange.FromThisYear;
+                    boolean isDate = CharSequenceUtil.compare(params.getStartDate(), start, true) > 0;
+                    if (isFrom && isDate) {
+                        timeRangeFlag.put(timeRange, true);
+                        continue;
+                    }
+                }
+                String value = Optional.ofNullable(dto.getSecData()).map(e -> excess ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap())
+                        .map(e -> e.get(indicator.name())).orElse(null);
+                fundIndicatorList.add(MapUtil.<String, Object>builder("date", handleStrDate(timeRange.name(), null)).put("value", value).build());
+            }
+            valuesMap.put(refId, fundIndicatorList);
+            // 指数的数据处�
+            for (String indexId : indexIds) {
+                boolean excessBench = (excess && indexId.equals(params.getBenchmarkId()));
+                if (indexValuesMap.containsKey(indexId) || excessBench) {
+                    continue;
+                }
+                List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
+                for (IndicatorCalcPropertyDto dto : dtos) {
+                    TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto)
+                            .map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
+                    if (timeRange == null || timeRangeFlag.getOrDefault(timeRange, false)) {
+                        continue;
+                    }
+                    String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(indicator.name())).orElse(null);
+                    indexIndicatorList.add(MapUtil.<String, Object>builder("date", handleStrDate(timeRange.name(), null)).put("value", value).build());
+                }
+                indexValuesMap.put(indexId, indexIndicatorList);
+            }
+        }
+        Map<String, Object> dataset = MapUtil.<String, Object>builder().putAll(valuesMap).putAll(indexValuesMap).build();
+
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        if (excess) {
+            for (String indexId : indexIds) {
+                productNameMapping.remove(indexId);
+            }
+        }
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).putAll(extInfos).build();
+    }
+}

+ 97 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/RankHandler.java

@@ -0,0 +1,97 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.RankParams;
+import com.smppw.analysis.domain.manager.performance.AbstractPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.common.pojo.IStrategy;
+import com.smppw.utils.StrategyHandleUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component(PerformanceConstants.RANK)
+public class RankHandler extends AbstractPerformance<RankParams, Map<String, Object>> {
+    public RankHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected Map<String, Object> bizHandle(RankParams params) {
+        String fundId = params.getRefIds().get(0);
+        List<String> secIds = params.getRefIds();
+        CollUtil.addAllIfNotContains(secIds, ListUtil.of(params.getBenchmarkId()));
+        List<String> indexIds = params.getSecIds();
+        CollUtil.addAllIfNotContains(secIds, indexIds);
+        IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
+        String rankDate = this.baseInfoService.getLatestRankRat();
+        List<Map<String, Object>> tempList = this.baseInfoService.getFundRank(rankDate, fundId, indexIds, params.getIndicator());
+        Map<String, String> mapper = this.baseInfoService.querySecName(secIds);
+        Map<String, String> productMapper = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).putAll(mapper)
+                .put("rank", "同策略排名")
+                .put("strategy_avg", "同策略平均")
+                .put("strategy_avg_99", "同策略平均(1%-99%)")
+                .put("strategy_best", "同策略最好")
+                .put("strategy_worst", "同策略最差")
+                .put("percent5", "5%分位数")
+                .put("percent25", "25%分位数")
+                .put("percent50", "50%分位数")
+                .put("percent75", "75%分位数")
+                .put("percent95", "95%分位数").build();
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder("strategy", strategy.getStrategyNameDesc()).build();
+        List<Map<String, Object>> dataset = this.getRankDataset(tempList);
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productMapper).putAll(extInfos).build();
+    }
+
+    private List<Map<String, Object>> getRankDataset(List<Map<String, Object>> tempList) {
+        String rankFiled = "fund_rank";
+        Map<String, Map<String, Object>> resMap = new LinkedHashMap<>();
+        if (CollUtil.isEmpty(tempList)) {
+            return CollUtil.newArrayList();
+        }
+        for (Map<String, Object> unit : tempList) {
+            String classification = MapUtil.getStr(unit, "classification");
+            String name = MapUtil.getStr(unit, "name");
+            if (name == null && classification == null) {
+                continue;
+            }
+            List<String> keys = new ArrayList<>(unit.keySet());
+            keys.remove("name");
+            keys.remove("classification");
+            for (String key : keys) {
+                if (!resMap.containsKey(key)) {
+                    resMap.put(key, MapUtil.newHashMap(false));
+                }
+                if (classification.startsWith("strategy") || classification.startsWith("percen") || classification.equals(rankFiled)) {
+                    name = classification;
+                }
+                resMap.get(key).put(name, unit.get(key));
+            }
+        }
+        List<Map<String, Object>> dataset = ListUtil.list(false);
+        resMap.forEach((k, v) -> dataset.add(MapUtil.<String, Object>builder("date", k).putAll(v).build()));
+        dataset.forEach(e -> {
+            String rank = MapUtil.getStr(e, rankFiled);
+            String rankCnt = MapUtil.getStr(e, "strategy_rank_cnt");
+            String strRank = null;
+            if (CharSequenceUtil.isAllNotBlank(rank, rankCnt)) {
+                strRank = StrUtil.subBefore(rank, ".", false) + "/"
+                        + StrUtil.subBefore(rankCnt, ".", false);
+            }
+            e.put("rank", strRank);
+            e.remove(rankFiled);
+            e.remove("strategy_rank_cnt");
+        });
+        dataset.sort((o1, o2) -> MapUtil.getStr(o2, "date").compareTo(MapUtil.getStr(o1, "date")));
+        return dataset;
+    }
+}

+ 282 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/RevenueHandler.java

@@ -0,0 +1,282 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.lang.Pair;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.HistoryRetTableSingleResp;
+import com.smppw.analysis.domain.dto.performance.RevenueParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.HistoryRetTableUtil;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.analysis.infrastructure.exception.APIException;
+import com.smppw.common.pojo.dto.calc.*;
+import com.smppw.common.pojo.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
+import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
+import com.smppw.common.pojo.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.Frequency;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.common.pojo.enums.Visibility;
+import com.smppw.constants.Consts;
+import com.smppw.utils.DataUtil;
+import com.smppw.utils.RangeUtils;
+import com.smppw.utils.StrategyHandleUtils;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component(PerformanceConstants.REVENUE)
+public class RevenueHandler extends AbstractSingleSecPerformance<RevenueParams, Map<String, Object>> {
+    private static final String STATISTICS = "1";
+    private static final String DISTRIBUTION = "2";
+    private static final List<String> TYPE_LIST = ListUtil.of(STATISTICS, DISTRIBUTION);
+
+    public RevenueHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected void checkParams(RevenueParams params) {
+        super.checkParams(params);
+        if (StrUtil.isBlank(params.getRevenuType()) || !TYPE_LIST.contains(params.getRevenuType())) {
+            params.setRevenuType(STATISTICS);
+        }
+        List<Frequency> frequencies = ListUtil.toList(Frequency.Weekly, Frequency.Monthly, Frequency.Quarterly, Frequency.Annually);
+        if (params.getRollingFrequency() == null || !frequencies.contains(params.getRollingFrequency())) {
+            logger.warn(String.format("当前滚动频率为:%s,设置为默认滚动频率:%s", params.getRollingFrequency(), Frequency.Monthly));
+            params.setRollingFrequency(Frequency.Monthly);
+        }
+        //支持调整组距 1~20%
+        if (DISTRIBUTION.equals(params.getRevenuType())) {
+            if (!NumberUtil.isNumber(params.getSpace())) {
+                throw new APIException("组距必须是数字");
+            }
+            BigDecimal space = NumberUtil.toBigDecimal(params.getSpace());
+            if (!NumberUtil.isIn(space, BigDecimal.ONE, NumberUtil.toBigDecimal("20"))) {
+                throw new APIException("组距必须是大于1小于20的数");
+            }
+        }
+    }
+
+    @Override
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(RevenueParams params, DateIntervalType dateIntervalType) {
+        Frequency rollingFrequency = params.getRollingFrequency();
+        List<String> refIds = params.getRefIds();
+        String startDate = params.getStartDate();
+        String endDate = params.getEndDate();
+        List<DateIntervalDto> dateIntervalDtoList = new ArrayList<>();
+        DateIntervalDto dateIntervalDto = new DateIntervalDto();
+        dateIntervalDto.setDateIntervalType(DateIntervalType.DefaultRolling);
+        dateIntervalDto.setStartDate(startDate);
+        dateIntervalDto.setEndDate(endDate);
+        dateIntervalDto.setFrequency(rollingFrequency);
+        dateIntervalDtoList.add(dateIntervalDto);
+        if (Frequency.Monthly == rollingFrequency || Frequency.Quarterly == rollingFrequency) {
+            DateIntervalDto yearDateIntervalDto = new DateIntervalDto();
+            yearDateIntervalDto.setDateIntervalType(DateIntervalType.DefaultRolling);
+            yearDateIntervalDto.setStartDate(startDate);
+            yearDateIntervalDto.setEndDate(endDate);
+            yearDateIntervalDto.setFrequency(Frequency.Annually);
+            yearDateIntervalDto.setId(HistoryRetTableUtil.YEAR_ROLL_DEFAULT_ID);
+            dateIntervalDtoList.add(yearDateIntervalDto);
+        } else if (Frequency.Weekly == rollingFrequency) {
+            DateIntervalDto monthDateIntervalDto = new DateIntervalDto();
+            monthDateIntervalDto.setDateIntervalType(DateIntervalType.DefaultRolling);
+            monthDateIntervalDto.setStartDate(startDate);
+            monthDateIntervalDto.setEndDate(endDate);
+            monthDateIntervalDto.setFrequency(Frequency.Monthly);
+            monthDateIntervalDto.setId(HistoryRetTableUtil.MONTH_ROLL_DEFAULT_ID);
+            dateIntervalDtoList.add(monthDateIntervalDto);
+        }
+        Map<String, List<DateIntervalDto>> dateIntervalMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            dateIntervalMap.put(refId, dateIntervalDtoList);
+        }
+        List<String> secIds = this.getSecIdsByParams(params);
+        // 差集求指数id集合,包括基准
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            if (StrUtil.isBlank(params.getBenchmarkId())) {
+                continue;
+            }
+            benchmarkIdMap.put(refId, params.getBenchmarkId());
+        }
+        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
+                .mainSecIdList(refIds)
+                .secBenchmarkIdMap(benchmarkIdMap)
+                .indexIdList(indexIds)
+                .raiseType(params.getRaiseType())
+                .strategy(StrategyHandleUtils.getStrategy(params.getStrategy()))
+                .visibility(Visibility.Both)
+                .dataFrequency(params.getFrequency())
+                .navType(params.getNavType())
+                .secDateIntervalDtoListMap(dateIntervalMap)
+                .indicatorList(ListUtil.toList(Indicator.IntervalReturn))
+                .geoExtraindicatorList(ListUtil.toList(Indicator.IntervalReturn))
+                .ifAnnualize(true)
+                .riskOfFreeId(Consts.RISK_OF_FREE)
+                .calcIndexRetIndicatorValue(true)
+                .ifConvertPerformanceConsistencyWord(true).build();
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(RevenueParams params) {
+        boolean ifExcessReturn = params.getIfExcessReturn() != null && params.getIfExcessReturn();
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, null);
+        Map<String, List<IndicatorCalcPropertyDto>> secRangIndicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
+        // 3、结果处�
+        Map<String, Object> dataset = MapUtil.newHashMap();
+        if (STATISTICS.equals(params.getRevenuType())) {
+            dataset = this.getRevenueDataset(refIds, indexIds, params.getRollingFrequency(), secRangIndicatorMap, ifExcessReturn);
+        } else if (DISTRIBUTION.equals(params.getRevenuType())) {
+            dataset = this.loadDistributionData(refIds, indexIds, secRangIndicatorMap, Double.parseDouble(params.getSpace()), ifExcessReturn);
+        }
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
+        if (STATISTICS.equals(params.getRevenuType())) {
+            // table
+            HistoryRetTableSingleResp resp = HistoryRetTableUtil.getHistoryRetTableSingleResp(refIds, indexIds, secRangIndicatorMap, Indicator.IntervalReturn, ifExcessReturn, params.getRollingFrequency());
+            extInfos.put("table", HistoryRetTableUtil.buildTableData(productNameMapping, resp, ifExcessReturn, false));
+        }
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).putAll(extInfos).build();
+    }
+
+    /**
+     * 获取分布图,已支持多标的
+     *
+     * @param refIds         基金id,支持多标的
+     * @param indexIdList    指数id列表,包括基准
+     * @param dtoMap         计算返回数据
+     * @param space          分布图横坐标间距
+     * @param ifExcessReturn 是否计算超额
+     * @return /
+     */
+    protected Map<String, Object> loadDistributionData(List<String> refIds, List<String> indexIdList, Map<String, List<IndicatorCalcPropertyDto>> dtoMap, double space, boolean ifExcessReturn) {
+        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
+        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
+        double maxValue = 0d;
+        double minValue = 0d;
+        for (String refId : refIds) {
+            List<Double> indicatorValues = dtoMap.get(refId).stream()
+                    .filter(p -> !HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(p.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId()))
+                    .map(IndicatorCalcPropertyDto::getSecData)
+                    .map(e -> ifExcessReturn ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap())
+                    .map(e -> e.get(Indicator.IntervalReturn.name())).filter(Objects::nonNull).map(Double::parseDouble).collect(Collectors.toList());
+            List<Map<String, Map<String, String>>> collect = dtoMap.get(refId).stream()
+                    .filter(p -> !HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(p.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId()))
+                    .map(IndicatorCalcPropertyDto::getIndexData)
+                    .map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).collect(Collectors.toList());
+            maxValue = Math.max(maxValue, handleMaxAndMin(indicatorValues, (o1, o2) -> o1 > o2 ? o1 : o2));
+            minValue = Math.min(minValue, handleMaxAndMin(indicatorValues, (o1, o2) -> o1 > o2 ? o2 : o1));
+            for (String indexId : indexIdList) {
+                List<Double> indexIndicatorValues = collect.stream().map(e -> e.get(indexId)).map(e -> e.get(Indicator.IntervalReturn.name()))
+                        .filter(Objects::nonNull).map(Double::parseDouble).collect(Collectors.toList());
+                maxValue = Math.max(maxValue, handleMaxAndMin(indexIndicatorValues, (o1, o2) -> o1 > o2 ? o1 : o2));
+                minValue = Math.min(minValue, handleMaxAndMin(indexIndicatorValues, (o1, o2) -> o1 > o2 ? o2 : o1));
+            }
+        }
+        for (String refId : refIds) {
+            List<Double> indicatorValues = dtoMap.get(refId).stream()
+                    .filter(p -> !HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(p.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId()))
+                    .map(IndicatorCalcPropertyDto::getSecData)
+                    .map(e -> ifExcessReturn ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap())
+                    .map(e -> e.get(Indicator.IntervalReturn.name())).filter(Objects::nonNull).map(Double::parseDouble).collect(Collectors.toList());
+            List<Pair<Double, Double>> dates = RangeUtils.groupNumberLimitCondition(10, space, minValue, maxValue);
+            valuesMap.put(refId, DataUtil.buildValue(dates, indicatorValues));
+            for (String indexId : indexIdList) {
+                if (indexValuesMap.containsKey(indexId)) {
+                    continue;
+                }
+                List<Double> indexIndicatorValues = dtoMap.get(refId).stream()
+                        .filter(p -> !HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(p.getIndicatorCalcReq().getIndicatorCalcTimeRangeDto().getId()))
+                        .map(IndicatorCalcPropertyDto::getIndexData)
+                        .map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(Indicator.IntervalReturn.name()))
+                        .filter(Objects::nonNull).map(Double::parseDouble).collect(Collectors.toList());
+                indexValuesMap.put(indexId, DataUtil.buildValue(dates, indexIndicatorValues));
+            }
+        }
+        return MapUtil.<String, Object>builder().putAll(valuesMap).putAll(indexValuesMap).build();
+    }
+
+    private Map<String, Object> getRevenueDataset(List<String> refIds, List<String> indexIds, Frequency frequency, Map<String, List<IndicatorCalcPropertyDto>> secRangIndicatorMap, boolean ifExcessReturn) {
+        Map<String, Object> dataset = MapUtil.newHashMap();
+        Map<String, List<Map<String, Object>>> valuesMap = MapUtil.newHashMap(true);
+        Map<String, List<Map<String, Object>>> indexValuesMap = MapUtil.newHashMap(true);
+        List<String> dateList = ListUtil.list(false);
+        for (String refId : refIds) {
+            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(secRangIndicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
+            // 当前基金的数据处�
+            List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
+            for (IndicatorCalcPropertyDto dto : dtos) {
+                String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
+                String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
+                if (id == null || HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(id)) {
+                    continue;
+                }
+                date = handleStrDate(date, frequency);
+                if (!dateList.contains(date)) {
+                    dateList.add(date);
+                }
+                String value = Optional.ofNullable(dto.getSecData()).map(IndicatorCalcSecDataDto::getIndicatorValueMap).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
+                String extraValue = Optional.ofNullable(dto.getSecData()).map(IndicatorCalcSecDataDto::getExtraGeoIndicatorValueMap).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
+                Map<String, Object> build = MapUtil.<String, Object>builder("date", date).put("d", date).put("extraValue", extraValue).put("value", value).build();
+                fundIndicatorList.add(build);
+            }
+            valuesMap.put(refId, fundIndicatorList);
+            // 指数的数据处�
+            for (String indexId : indexIds) {
+                if (indexValuesMap.containsKey(indexId)) {
+                    continue;
+                }
+                List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
+                for (IndicatorCalcPropertyDto dto : dtos) {
+                    String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
+                    if (id == null || HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(id)) {
+                        continue;
+                    }
+                    String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
+                    date = handleStrDate(date, frequency);
+                    String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(Indicator.IntervalReturn.name())).orElse(null);
+                    indexIndicatorList.add(MapUtil.<String, Object>builder("date", date).put("value", value).build());
+                }
+                indexValuesMap.put(indexId, indexIndicatorList);
+            }
+        }
+        dateList.sort(Comparator.naturalOrder());
+        for (String refId : refIds) {
+            List<Map<String, Object>> data = ListUtil.list(true);
+            for (String date : dateList) {
+                String value = valuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
+                        .findFirst().map(e -> MapUtil.getStr(e, "value")).orElse(null);
+                Map<String, Object> build = MapUtil.<String, Object>builder().put("date", date).put("value", value).build();
+                if (ifExcessReturn) {
+                    String extraValue = valuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
+                            .findFirst().map(e -> MapUtil.getStr(e, "extraValue")).orElse(null);
+                    build.put("extraValue", extraValue);
+                }
+                data.add(build);
+            }
+            dataset.put(refId, data);
+        }
+        for (String refId : indexIds) {
+            List<Map<String, Object>> data = ListUtil.list(true);
+            for (String date : dateList) {
+                String value = indexValuesMap.get(refId).stream().filter(e -> date.equals(MapUtil.getStr(e, "date")))
+                        .findFirst().map(e -> MapUtil.getStr(e, "value")).orElse(null);
+                data.add(MapUtil.<String, Object>builder().put("date", date).put("value", value).build());
+            }
+            dataset.put(refId, data);
+        }
+        return dataset;
+    }
+}

+ 215 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/RollingHandler.java

@@ -0,0 +1,215 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.HistoryRetTableSingleResp;
+import com.smppw.analysis.domain.dto.performance.RollingParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.HistoryRetTableUtil;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.analysis.infrastructure.exception.APIException;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcIndexDataDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcReqPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcTimeRangeDto;
+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.constants.Consts;
+import com.smppw.utils.StrategyHandleUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Component(PerformanceConstants.ROLLING)
+public class RollingHandler extends AbstractSingleSecPerformance<RollingParams, Map<String, Object>> {
+    public RollingHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected void checkParams(RollingParams params) {
+        super.checkParams(params);
+        if (params.getIndicator() == null) {
+            throw new APIException("分析的指标不能为空");
+        }
+        List<Frequency> frequencies = ListUtil.toList(Frequency.Monthly, Frequency.Quarterly, Frequency.Annually);
+        if (params.getRollingFrequency() == null || !frequencies.contains(params.getRollingFrequency())) {
+            logger.warn(String.format("当前滚动频率为:%s,设置为默认滚动频率:%s", params.getRollingFrequency(), Frequency.Monthly));
+            params.setRollingFrequency(Frequency.Monthly);
+        }
+    }
+
+    @Override
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(RollingParams params, DateIntervalType dateIntervalType) {
+        Indicator indicator = params.getIndicator();
+        boolean excess = Indicator.INDICATOR_EXCESS_RETURN_TYPE_ARRAY.contains(indicator);
+        List<Indicator> indicators = ListUtil.toList(Indicator.MaxDrawdown);
+        List<Indicator> geoIndicators = ListUtil.list(false);
+        if (excess) {
+            geoIndicators.add(indicator);
+        } else {
+            indicators.add(indicator);
+        }
+        Frequency rollingFrequency = params.getRollingFrequency();
+        List<String> refIds = params.getRefIds();
+        String startDate = params.getStartDate();
+        String endDate = params.getEndDate();
+        List<DateIntervalDto> dateIntervalDtoList = new ArrayList<>();
+        DateIntervalDto dateIntervalDto = new DateIntervalDto();
+        dateIntervalDto.setDateIntervalType(dateIntervalType);
+        dateIntervalDto.setStartDate(startDate);
+        dateIntervalDto.setEndDate(endDate);
+        dateIntervalDto.setFrequency(rollingFrequency);
+        dateIntervalDtoList.add(dateIntervalDto);
+        if (Frequency.Monthly == rollingFrequency || Frequency.Quarterly == rollingFrequency) {
+            DateIntervalDto yearDateIntervalDto = new DateIntervalDto();
+            yearDateIntervalDto.setDateIntervalType(dateIntervalType);
+            yearDateIntervalDto.setStartDate(startDate);
+            yearDateIntervalDto.setEndDate(endDate);
+            yearDateIntervalDto.setFrequency(Frequency.Annually);
+            yearDateIntervalDto.setId(HistoryRetTableUtil.YEAR_ROLL_DEFAULT_ID);
+            dateIntervalDtoList.add(yearDateIntervalDto);
+        } else if (Frequency.Weekly == rollingFrequency) {
+            DateIntervalDto monthDateIntervalDto = new DateIntervalDto();
+            monthDateIntervalDto.setDateIntervalType(dateIntervalType);
+            monthDateIntervalDto.setStartDate(startDate);
+            monthDateIntervalDto.setEndDate(endDate);
+            monthDateIntervalDto.setFrequency(Frequency.Monthly);
+            monthDateIntervalDto.setId(HistoryRetTableUtil.MONTH_ROLL_DEFAULT_ID);
+            dateIntervalDtoList.add(monthDateIntervalDto);
+        }
+        Map<String, List<DateIntervalDto>> dateIntervalMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            dateIntervalMap.put(refId, dateIntervalDtoList);
+        }
+        List<String> secIds = this.getSecIdsByParams(params);
+        // 差集求指数id集合,包括基准
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            if (StrUtil.isBlank(params.getBenchmarkId())) {
+                continue;
+            }
+            benchmarkIdMap.put(refId, params.getBenchmarkId());
+        }
+        return CalcMultipleSecMultipleTimeRangeIndicatorReq.builder()
+                .mainSecIdList(refIds)
+                .secBenchmarkIdMap(benchmarkIdMap)
+                .indexIdList(indexIds)
+                .raiseType(params.getRaiseType())
+                .strategy(StrategyHandleUtils.getStrategy(params.getStrategy()))
+                .visibility(Visibility.Both)
+                .dataFrequency(params.getFrequency())
+                .navType(params.getNavType())
+                .secDateIntervalDtoListMap(dateIntervalMap)
+                .indicatorList(indicators)
+                .geoExtraindicatorList(geoIndicators)
+                .ifAnnualize(true)
+                .riskOfFreeId(Consts.RISK_OF_FREE)
+                .calcIndexRetIndicatorValue(true)
+                .ifConvertPerformanceConsistencyWord(true).build();
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(RollingParams params) {
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        Indicator indicator = params.getIndicator();
+        Frequency rollingFrequency = params.getRollingFrequency();
+        boolean excess = Indicator.INDICATOR_EXCESS_RETURN_TYPE_ARRAY.contains(indicator);
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, DateIntervalType.DefaultRolling);
+        Map<String, List<IndicatorCalcPropertyDto>> indicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
+        Map<TimeRange, Boolean> timeRangeFlag = MapUtil.newHashMap();
+        Map<String, Object> valuesMap = MapUtil.newHashMap(true);
+        Map<String, Object> indexValuesMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            List<IndicatorCalcPropertyDto> dtos = Optional.ofNullable(indicatorMap.get(refId)).filter(e -> !e.isEmpty()).orElse(ListUtil.empty());
+            // 当前基金的数据处理
+            List<Map<String, Object>> fundIndicatorList = getFundIndicatorList(params, indicator, excess, rollingFrequency, timeRangeFlag, dtos);
+            valuesMap.put(refId, fundIndicatorList);
+            // 指数的数据处理
+            if (excess) {
+                continue;
+            }
+            handleIndexData(indicator, rollingFrequency, indexIds, timeRangeFlag, indexValuesMap, dtos);
+        }
+        Map<String, Object> dataset = MapUtil.<String, Object>builder().putAll(valuesMap).putAll(indexValuesMap).build();
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        if (excess) {
+            for (String indexId : indexIds) {
+                productNameMapping.remove(indexId);
+            }
+        }
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
+        HistoryRetTableSingleResp resp = HistoryRetTableUtil.getHistoryRetTableSingleResp(refIds, indexIds, indicatorMap, indicator, excess, rollingFrequency);
+        extInfos.put("table", HistoryRetTableUtil.buildTableData(productNameMapping, resp, excess, true));
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).putAll(extInfos).build();
+    }
+
+    private void handleIndexData(Indicator indicator, Frequency rollingFrequency, List<String> indexIds,
+                                 Map<TimeRange, Boolean> timeRangeFlag, Map<String, Object> indexValuesMap, List<IndicatorCalcPropertyDto> dtos) {
+        for (String indexId : indexIds) {
+            if (indexValuesMap.containsKey(indexId)) {
+                continue;
+            }
+            List<Map<String, Object>> indexIndicatorList = ListUtil.list(true);
+            for (IndicatorCalcPropertyDto dto : dtos) {
+                String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
+                String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
+                TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
+                boolean yearMonthFlag = (id != null && HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(id));
+                boolean tf = timeRange == null || timeRangeFlag.getOrDefault(timeRange, false);
+                boolean flag = yearMonthFlag || tf;
+                if (flag || date == null) {
+                    continue;
+                }
+                String value = Optional.ofNullable(dto.getIndexData()).map(IndicatorCalcIndexDataDto::getIndexIndicatorValueMap).map(e -> e.get(indexId)).map(e -> e.get(indicator.name())).orElse(null);
+                indexIndicatorList.add(MapUtil.<String, Object>builder("date", handleStrDate(date, rollingFrequency)).put("value", value).build());
+            }
+            indexValuesMap.put(indexId, indexIndicatorList);
+        }
+    }
+
+    private List<Map<String, Object>> getFundIndicatorList(RollingParams params, Indicator indicator, boolean excess, Frequency rollingFrequency,
+                                                           Map<TimeRange, Boolean> timeRangeFlag, List<IndicatorCalcPropertyDto> dtos) {
+        List<Map<String, Object>> fundIndicatorList = ListUtil.list(true);
+        for (IndicatorCalcPropertyDto dto : dtos) {
+            String date = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getEndDate).orElse(null);
+            String id = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getId).orElse(null);
+            TimeRange timeRange = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getTimeRange).orElse(null);
+            boolean flag = (id != null && HistoryRetTableUtil.YEAR_MONTH_ROLL_LIST.contains(id));
+            if (timeRange == null || flag) {
+                continue;
+            }
+            if (params.getTimeRange() != null && params.getTimeRange() == TimeRange.Custom) {
+                String start = Optional.ofNullable(dto.getIndicatorCalcReq()).map(IndicatorCalcReqPropertyDto::getIndicatorCalcTimeRangeDto).map(IndicatorCalcTimeRangeDto::getStartDate).orElse(null);
+                boolean isNotNull = params.getStartDate() != null && start != null;
+                if (isNotNull && params.getStartDate().compareTo(start) > 0) {
+                    timeRangeFlag.put(timeRange, true);
+                    continue;
+                }
+            }
+            boolean isFromSetup = params.getTimeRange() != null && params.getTimeRange() != TimeRange.FromSetup;
+            boolean isFromThisYear = params.getTimeRange() != null && params.getTimeRange() != TimeRange.FromThisYear;
+            boolean isCustom = params.getTimeRange() != null && params.getTimeRange() != TimeRange.Custom;
+            boolean isOver = params.getTimeRange() != null && params.getTimeRange().getId() < timeRange.getId();
+            boolean isTimaRange = isFromSetup && isFromThisYear && isCustom && isOver;
+            if (isTimaRange || date == null) {
+                timeRangeFlag.put(timeRange, true);
+                continue;
+            }
+            String value = Optional.ofNullable(dto.getSecData()).map(e -> excess ? e.getExtraGeoIndicatorValueMap() : e.getIndicatorValueMap()).map(e -> e.get(indicator.name())).orElse(null);
+            fundIndicatorList.add(MapUtil.<String, Object>builder("date", handleStrDate(date, rollingFrequency)).put("value", value).build());
+        }
+        return fundIndicatorList;
+    }
+}

+ 109 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/TrendHandler.java

@@ -0,0 +1,109 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.TrendParams;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcIndexDataDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
+import com.smppw.common.pojo.dto.calc.IndicatorCalcSecDataDto;
+import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
+import com.smppw.common.pojo.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.TrendType;
+import com.smppw.common.pojo.enums.Visibility;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Component(PerformanceConstants.TREND)
+public class TrendHandler extends AbstractSingleSecPerformance<TrendParams, Map<String, Object>> {
+    public TrendHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected Map<String, Object> bizSecHandle(TrendParams params) {
+        List<String> refIds = params.getRefIds();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+        // 时段参数构建
+        DateIntervalDto dateInterval = this.buildDateIntervalByParams(params, DateIntervalType.CustomInterval, params.getFrequency());
+        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            if (StrUtil.isBlank(params.getBenchmarkId())) {
+                continue;
+            }
+            benchmarkIdMap.put(refId, params.getBenchmarkId());
+        }
+        List<TrendType> trendTypes = params.getTrendTypes();
+        List<TrendType> indexTrendTypes = params.getIndexTrendTypes();
+        // 计算走势图
+        Map<String, List<IndicatorCalcPropertyDto>> trendMap = this.baseIndicatorServiceV2.getMultipleSecTrend(refIds, benchmarkIdMap,
+                indexIds, dateInterval, params.getFrequency(), null, null, Visibility.Both, params.getNavType(), trendTypes);
+        // 结果处理,支持多标的
+        // 处理走势图
+        Map<String, List<Map<String, Object>>> dataListMap = MapUtil.newHashMap(true);
+        Map<String, List<Map<String, Object>>> indexDataListMap = MapUtil.newHashMap(true);
+        Map<String, Map<TrendType, List<Double>>> trendListMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            IndicatorCalcPropertyDto dto = Optional.ofNullable(trendMap.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
+            List<String> tempDateList = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getDateList).orElse(ListUtil.empty());
+            // 基金走势序列
+            Map<TrendType, List<Double>> trendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getTrendValueMap).orElse(MapUtil.empty());
+            trendListMap.put(refId, trendTypeListMap);
+            dataListMap.put(refId, this.buildDateValue(tempDateList, trendTypeListMap, trendTypes));
+            // 指数净值和收益序列
+            Map<String, Map<TrendType, List<Double>>> tempIndexTrendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexTrendValueMap).orElse(MapUtil.empty());
+            for (String indexId : indexIds) {
+                if (indexDataListMap.containsKey(indexId) && !indexId.equals(params.getBenchmarkId())) {
+                    continue;
+                }
+                indexDataListMap.put(indexId, this.buildDateValue(tempDateList, tempIndexTrendTypeListMap.get(indexId), indexTrendTypes));
+            }
+        }
+        Map<String, String> productNameMapping = this.baseInfoService.querySecName(secIds);
+        Map<String, List<Map<String, Object>>> dataset = MapUtil.<String, List<Map<String, Object>>>builder().putAll(dataListMap).build();
+        Map<String, Object> extInfos = MapUtil.<String, Object>builder().put("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
+        for (String refId : refIds) {
+            Map<TrendType, List<Double>> trendTypeListMap = trendListMap.getOrDefault(refId, MapUtil.empty());
+            Double maxDown = handleMaxAndMin(trendTypeListMap.get(TrendType.DrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
+            Double maxExtraDown = handleMaxAndMin(trendTypeListMap.get(TrendType.ExtraDrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
+            Map<String, Object> data = MapUtil.<String, Object>builder().put("maxDown", maxDown).put("maxExtraDown", maxExtraDown).build();
+            extInfos.put(refId, data);
+        }
+        return MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", productNameMapping).putAll(extInfos).build();
+    }
+
+    /**
+     * 构建日期值对象
+     *
+     * @param dateList         日期序列
+     * @param trendTypeListMap 走势图数据
+     * @param trendTypes       走势图类型列表
+     * @return /
+     */
+    private List<Map<String, Object>> buildDateValue(List<String> dateList, Map<TrendType, List<Double>> trendTypeListMap, List<TrendType> trendTypes) {
+        List<Map<String, Object>> dataList = ListUtil.list(true);
+        for (int i = 0; i < dateList.size(); i++) {
+            Map<String, Object> temp = MapUtil.<String, Object>builder("date", dateList.get(i)).build();
+            for (TrendType trendType : trendTypes) {
+                List<Double> doubles = trendTypeListMap.get(trendType);
+                Object value = null;
+                try {
+                    value = i <= doubles.size() ? doubles.get(i) : null;
+                } catch (Exception ignored) {
+                }
+                temp.put(StrUtil.toCamelCase(trendType.name()), value);
+            }
+            dataList.add(temp);
+        }
+        return dataList;
+    }
+}

+ 175 - 0
src/main/java/com/smppw/analysis/domain/manager/performance/handler/WinHandler.java

@@ -0,0 +1,175 @@
+package com.smppw.analysis.domain.manager.performance.handler;
+
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import com.smppw.analysis.domain.dto.performance.WinParams;
+import com.smppw.analysis.domain.dto.performance.WinVO;
+import com.smppw.analysis.domain.manager.performance.AbstractSingleSecPerformance;
+import com.smppw.analysis.domain.manager.performance.PerformanceConstants;
+import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
+import com.smppw.analysis.domain.service.BaseInfoService;
+import com.smppw.analysis.infrastructure.consts.WinRateBmk;
+import com.smppw.analysis.infrastructure.exception.APIException;
+import com.smppw.common.pojo.dto.CompoundRet;
+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.enums.DateIntervalType;
+import com.smppw.common.pojo.enums.Indicator;
+import com.smppw.constants.Consts;
+import com.smppw.utils.BigDecimalUtils;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Component(PerformanceConstants.WIN)
+public class WinHandler extends AbstractSingleSecPerformance<WinParams, WinVO> {
+    public WinHandler(BaseInfoService baseInfoService, BaseIndicatorServiceV2 baseIndicatorServiceV2) {
+        super(baseInfoService, baseIndicatorServiceV2);
+    }
+
+    @Override
+    protected void checkParams(WinParams params) {
+        super.checkParams(params);
+        if (params.getRefIds().size() > 1) {
+            logger.warn("多标的不支持胜率分析!");
+        }
+    }
+
+    @Override
+    protected CalcMultipleSecMultipleTimeRangeIndicatorReq buildCalcReq(WinParams params, DateIntervalType dateIntervalType) {
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = super.buildCalcReq(params, dateIntervalType);
+        req.setIndicatorList(ListUtil.toList(Indicator.IntervalReturn, Indicator.WinRate));
+        boolean winZero = params.getWinRateBmk() == WinRateBmk.Zero;
+        req.setRiskOfFreeId(Consts.RISK_OF_FREE);
+        req.setIndexIdList(ListUtil.empty());
+        req.setNeedRet(true);
+        req.setNeedExtraRet(true);
+        if (!winZero) {
+            req.setGeoExtraindicatorList(ListUtil.toList(Indicator.WinRate));
+        }
+        return req;
+    }
+
+    @Override
+    protected WinVO bizSecHandle(WinParams params) {
+        String fundId = params.getRefIds().get(0);
+        Indicator indicator = Indicator.WinRate;
+        boolean winZero = params.getWinRateBmk() == WinRateBmk.Zero;
+        CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, DateIntervalType.CustomInterval);
+        Map<String, List<IndicatorCalcPropertyDto>> indicatorMap = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
+        IndicatorCalcSecDataDto secData = Optional.ofNullable(indicatorMap.get(fundId)).filter(e -> !e.isEmpty()).map(e -> e.get(0))
+                .map(IndicatorCalcPropertyDto::getSecData).orElseThrow(() -> new APIException("计算错误"));
+        String winRate = winZero ? secData.getIndicatorValueMap().get(indicator.name()) : secData.getExtraGeoIndicatorValueMap().get(indicator.name());
+        List<CompoundRet> retList = secData.getRetList();
+        // 返回结果对象构建
+        WinVO.WinData winData = this.prepareWinRateData("allTime", winRate, retList, winZero);
+        Double lower = Optional.ofNullable(params.getLower()).map(Double::parseDouble).map(e -> e / 100).orElse(-0.03d);
+        Double upper = Optional.ofNullable(params.getUpper()).map(Double::parseDouble).map(e -> e / 100).orElse(0.03d);
+        List<CompoundRet> riseRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() >= upper).collect(Collectors.toList());
+        List<CompoundRet> fallRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() <= lower).collect(Collectors.toList());
+        List<CompoundRet> shockRetList = retList.stream().filter(e -> e.getRetOfBmk() != null && e.getRetOfBmk() <= upper && e.getRetOfBmk() >= lower).collect(Collectors.toList());
+        List<WinVO.WinData> marketWinData = ListUtil.list(true);
+        Map<String, List<CompoundRet>> timeMap = MapUtil.<String, List<CompoundRet>>builder(MapUtil.newHashMap(true))
+                .put("allTime", retList).put("riseTime", riseRetList).put("shockTime", shockRetList).put("fallTime", fallRetList).build();
+        if (winZero) {
+            timeMap.remove("shockTime");
+        }
+        timeMap.forEach((k, v) -> marketWinData.add(this.prepareWinRateData(k, winRate, v, winZero)));
+        return new WinVO(winData, marketWinData);
+    }
+
+    /**
+     * 胜率业务处理,从老项目迁移过来
+     *
+     * @param id      /
+     * @param winRate /
+     * @param retList /
+     * @param winZero /
+     * @return /
+     */
+    protected WinVO.WinData prepareWinRateData(String id, String winRate, List<CompoundRet> retList, boolean winZero) {
+        Map<String, String> timeMap = MapUtil.builder("allTime", "全时段").put("riseTime", "上涨周期")
+                .put("fallTime", "下跌周期").put("shockTime", "震荡周期").build();
+        List<Double> fundList = ListUtil.list(false);
+        List<Double> bmkList = ListUtil.list(false);
+        int winItem = 0;
+        int lossItem = 0;
+        int totalItem = 0;
+        for (CompoundRet compoundRet : retList) {
+            if (compoundRet.getRetOfBmk() == null) {
+                if (winZero && compoundRet.getRetOfFund() != null) {
+                    compoundRet.setRetOfBmk(0.d);
+                } else {
+                    continue;
+                }
+            }
+            fundList.add(compoundRet.getRetOfFund());
+            bmkList.add(compoundRet.getRetOfBmk());
+            if (winZero) {
+                if (compoundRet.getRetOfFund() != null) {
+                    if ((compoundRet.getRetOfFund() - 0) > 0) {
+                        winItem++;
+                    } else {
+                        lossItem++;
+                    }
+                    totalItem++;
+                }
+            } else {
+                if (compoundRet.getRetOfFund() != null && compoundRet.getRetOfBmk() != null) {
+                    if (compoundRet.getRetOfFund() - compoundRet.getRetOfBmk() > 0) {
+                        winItem++;
+                    } else {
+                        lossItem++;
+                    }
+                    totalItem++;
+                }
+            }
+        }
+
+        String rate = winRate;
+        if (!"allTime".equals(id)) {
+            rate = totalItem == 0 ? "0" : BigDecimalUtils.divide(new BigDecimal(winItem), new BigDecimal(totalItem))
+                    .setScale(4, RoundingMode.HALF_UP).toString();
+        }
+        Double meanFundRet = meanRetCal(fundList);
+        Double meanBenchmarkRet = meanRetCal(bmkList);
+        Double excessMeanRet = null;
+        if (null != meanFundRet && null != meanBenchmarkRet) {
+            excessMeanRet = meanFundRet - meanBenchmarkRet;
+        }
+        return WinVO.WinData.builder().dateType(timeMap.get(id))
+                .totalItem(String.valueOf(totalItem))
+                .winItem(String.valueOf(winItem))
+                .lossItem(String.valueOf(lossItem))
+                .meanRet(StrUtil.toStringOrNull(meanFundRet))
+                .benchmarkMeanRet(StrUtil.toStringOrNull(meanBenchmarkRet))
+                .excessMeanRet(StrUtil.toStringOrNull(excessMeanRet))
+                .winRate(rate)
+                .build();
+    }
+
+    private Double meanRetCal(List<Double> list) {
+        double sum = 0.0;
+        int couter = 0;
+
+        for (Double d : list) {
+            if (null != d) {
+                sum += d;
+                couter++;
+            }
+        }
+
+        if (couter < 1) {
+            return null;
+        }
+
+        return sum / couter;
+    }
+}

+ 0 - 5
src/main/java/com/smppw/analysis/domain/manager/performance/package-info.java

@@ -1,5 +0,0 @@
-package com.smppw.analysis.domain.manager.performance;
-
-/*
-   这里重新实现业绩表现的接口
- */

+ 2 - 1
src/main/java/com/smppw/analysis/domain/manager/position/AbstractBizHandler.java

@@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
+import org.springframework.lang.NonNull;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -46,7 +47,7 @@ public abstract class AbstractBizHandler<P extends BaseParams, R> implements Biz
     }
 
     @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
     }
 

+ 3 - 3
src/main/java/com/smppw/analysis/domain/manager/position/BizHandlerFactor.java

@@ -8,11 +8,11 @@ import org.springframework.stereotype.Component;
 import java.util.Map;
 
 @Component
-public class BizHandlerFactor {
+public class BizHandlerFactory {
     private static final BizHandler<BaseParams, Object> EMPTY = p -> null;
-    private static final Map<String, BizHandler<? extends BaseParams, ?>> BIZ_HANDLER_STRATEGY = MapUtil.newHashMap(32);
+    private static final Map<String, BizHandler<? extends BaseParams, ?>> BIZ_HANDLER_STRATEGY = MapUtil.newHashMap(16);
 
-    public BizHandlerFactor(Map<String, BizHandler<? extends BaseParams, ?>> bizHandlerMap) {
+    public BizHandlerFactory(Map<String, BizHandler<? extends BaseParams, ?>> bizHandlerMap) {
         BIZ_HANDLER_STRATEGY.putAll(bizHandlerMap);
     }
 

+ 4 - 4
src/main/java/com/smppw/analysis/domain/manager/position/PositionLoadFactory.java

@@ -39,9 +39,9 @@ public class PositionLoadFactory {
      */
     public PositionLoad getPositionLoadInstance(String fundId) {
         List<String> supportTypes = ListUtil.of(SecType.PUBLICLY_OFFERED_FUNDS, SecType.PRIVATE_FUND);
-        String fundType = this.secTypeService.getFundType(fundId);
-        if (fundType == null || !supportTypes.contains(fundType)) {
-            LOGGER.warn(String.format("fundType[%s-%s] not find positionLoad strategy.", fundId, fundType));
+        String secType = this.secTypeService.getSecType(fundId);
+        if (secType == null || !supportTypes.contains(secType)) {
+            LOGGER.warn(String.format("secType[%s-%s] not find positionLoad strategy.", fundId, secType));
             return new PositionLoad() {
                 @Override
                 public <P extends BaseParams> List<FundPositionBaseInfo> getFundPositionBaseInfo(P params) {
@@ -53,7 +53,7 @@ public class PositionLoadFactory {
                 }
             };
         } else {
-            return LOAD_STRATEGY.get(fundType);
+            return LOAD_STRATEGY.get(secType);
         }
     }
 }

+ 3 - 3
src/main/java/com/smppw/analysis/domain/manager/position/stock/IndustryAllocationPreferenceComponent.java

@@ -8,7 +8,7 @@ import com.smppw.analysis.domain.dto.position.stock.IndustryAllocationPreference
 import com.smppw.analysis.domain.dto.position.stock.StockAllocationParams;
 import com.smppw.analysis.domain.dto.position.stock.StockAllocationVO;
 import com.smppw.analysis.domain.manager.position.BizHandler;
-import com.smppw.analysis.domain.manager.position.BizHandlerFactor;
+import com.smppw.analysis.domain.manager.position.BizHandlerFactory;
 import com.smppw.common.pojo.ValueLabelVO;
 import org.springframework.stereotype.Component;
 
@@ -28,9 +28,9 @@ import static com.smppw.analysis.domain.manager.position.BizHandlerConstants.IND
  */
 @Component
 public class IndustryAllocationPreferenceComponent {
-    private final BizHandlerFactor factor;
+    private final BizHandlerFactory factor;
 
-    public IndustryAllocationPreferenceComponent(BizHandlerFactor factor) {
+    public IndustryAllocationPreferenceComponent(BizHandlerFactory factor) {
         this.factor = factor;
     }
 

+ 15 - 2
src/main/java/com/smppw/analysis/domain/service/BaseIndicatorServiceV2.java

@@ -1,7 +1,9 @@
 package com.smppw.analysis.domain.service;
 
 import com.smppw.common.pojo.IStrategy;
+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.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
 import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
 import com.smppw.common.pojo.enums.*;
@@ -14,7 +16,18 @@ public interface BaseIndicatorServiceV2 {
     Map<String, List<IndicatorCalcPropertyDto>> calcMultipleSecMultipleTimeRangeIndicator(CalcMultipleSecMultipleTimeRangeIndicatorReq req);
 
     Map<String, List<IndicatorCalcPropertyDto>> getMultipleSecTrend(List<String> mainSecIdList, Map<String, String> secBenchmarkIdMap, List<String> indexIdList,
-                                                                    DateIntervalDto dateIntervalDto, Frequency frequency, BigDecimal fixedIncome, BigDecimal initValue, RaiseType raiseType,
-                                                                    IStrategy strategy, Visibility visibility, NavType navType, List<TrendType> trendTypeV2List);
+                                                                    DateIntervalDto dateIntervalDto, Frequency frequency, BigDecimal fixedIncome, BigDecimal initValue,
+                                                                    Visibility visibility, NavType navType, List<TrendType> trendTypeV2List);
 
+    List<IndicatorCalcTimeRangeDto> getSecTimeRange(String mainSecId, Visibility visibility);
+
+    Map<String, List<IndicatorCalcPropertyDto>> getMultiSecRetListNew(List<String> mainSecIdList, List<String> indexIds, Frequency frequency,
+                                                                      Frequency rollingFrequency, String startDate, String endDate, boolean ifExcessReturn,
+                                                                      String benchmarkId, RaiseType raiseType, IStrategy strategy,
+                                                                      Visibility visible, NavType navType);
+
+    Map<String, List<IndicatorCalcPropertyDto>> getMultiSecRetListNew(List<String> mainSecIdList, List<String> indexIds, Frequency frequency,
+                                                                      Frequency rollingFrequency, String startDate, String endDate, boolean ifExcessReturn,
+                                                                      String benchmarkId, RaiseType raiseType, IStrategy strategy,
+                                                                      Visibility visible, NavType navType, Map<String, List<DateValue>> allNavMap);
 }

+ 11 - 2
src/main/java/com/smppw/analysis/domain/service/BaseInfoService.java

@@ -1,5 +1,8 @@
 package com.smppw.analysis.domain.service;
 
+import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
+import com.smppw.common.pojo.enums.Indicator;
+
 import java.util.List;
 import java.util.Map;
 
@@ -9,11 +12,17 @@ import java.util.Map;
  * @description 基础信息服务
  */
 public interface BaseInfoService {
-    String getFundType(String fundId);
+    String getLatestRankRat();
+
+    String getSecType(String secId);
 
     Map<String, List<String>> getTypeSecMap(List<String> secIdList);
 
-    Map<String, String> querySecType(List<String> secIdList);
+    Map<String, String> querySecsType(List<String> secIdList);
 
     Map<String, String> querySecName(List<String> allSecIdList);
+
+    List<MonetaryFundProfitDO> queryMonetaryFund(String fundId);
+
+    List<Map<String, Object>> getFundRank(String rankDate, String fundId, List<String> indexIds, Indicator indicator);
 }

+ 3 - 5
src/main/java/com/smppw/analysis/domain/service/NavService.java

@@ -1,7 +1,6 @@
 package com.smppw.analysis.domain.service;
 
 import com.smppw.common.pojo.dto.DateValue;
-import com.smppw.common.pojo.enums.Frequency;
 import com.smppw.common.pojo.enums.NavType;
 import com.smppw.common.pojo.enums.Visibility;
 
@@ -9,12 +8,11 @@ import java.util.List;
 import java.util.Map;
 
 public interface NavService {
-    Map<String, List<DateValue>> getSecIdDateValueNavListMapFromRedisAndDB(List<String> mainSecIdList, List<String> benchmarkIdList, List<String> indexList, String startDate, String endDate
-            , NavType navType, Visibility visibility, Integer curveTypeId, Integer strategyId, Map<String, Frequency> secFrequencyMap, boolean getRedisData);
+    Map<String, List<DateValue>> getSecIdDateValueNavListMapFromRedisAndDB(List<String> mainSecIdList, List<String> benchmarkIdList, List<String> indexList,
+                                                                           String startDate, String endDate, NavType navType, Visibility visibility);
 
     Map<String, List<DateValue>> getSecIdDateValueNavListMapByDb(List<String> allSecIdList, String startDate, String endDate
-            , Integer curveTypeId, Integer strategyId, Visibility visibility, NavType navType, Map<String, Frequency> secFrequencyMap
-            , Map<String, Boolean> secIfExtractMap);
+            , Visibility visibility, NavType navType, Map<String, Boolean> secIfExtractMap);
 
     Map<String, List<DateValue>> getRongzhiIndexNavMap(List<String> rongzhiIndexIdList, String startDate, String endDate, NavType navType);
 

+ 34 - 9
src/main/java/com/smppw/analysis/domain/service/impl/BaseIndicatorServiceV2Impl.java

@@ -1,5 +1,6 @@
 package com.smppw.analysis.domain.service.impl;
 
+import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.util.StrUtil;
 import com.smppw.analysis.domain.dao.FundInformationDao;
 import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
@@ -7,6 +8,7 @@ import com.smppw.analysis.domain.service.NavService;
 import com.smppw.common.pojo.IStrategy;
 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.dto.indicator.CalcMultipleSecMultipleTimeRangeIndicatorReq;
 import com.smppw.common.pojo.dto.indicator.DateIntervalDto;
 import com.smppw.common.pojo.enums.*;
@@ -14,7 +16,6 @@ import com.smppw.core.IndicatorService;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -34,19 +35,15 @@ public class BaseIndicatorServiceV2Impl implements BaseIndicatorServiceV2 {
         List<String> mainSecIdList = req.getMainSecIdList();
         Map<String, String> secBenchmarkIdMap = req.getSecBenchmarkIdMap();
         List<String> indexIdList = req.getIndexIdList();
-        RaiseType raiseType = req.getRaiseType();
-        IStrategy strategy = req.getStrategy();
         Visibility visibility = req.getVisibility();
         NavType navType = req.getNavType();
         String riskOfFreeId = req.getRiskOfFreeId();
-
         List<String> benchmarkIdList = secBenchmarkIdMap.values().stream().distinct().collect(Collectors.toList());
-        CurveType curveType = CurveType.getCurveType(raiseType, strategy);
         if (StrUtil.isNotEmpty(riskOfFreeId)) {
             benchmarkIdList.add(riskOfFreeId);
         }
         Map<String, List<DateValue>> allNavMap = navService.getSecIdDateValueNavListMapFromRedisAndDB(mainSecIdList, benchmarkIdList, indexIdList,
-                null, null, navType, visibility, curveType.getId(), strategy.getStrategyId(), new HashMap<>(), false);
+                null, null, navType, visibility);
         Map<String, Frequency> secFreqMap = this.fundInformationDao.getNavFrequency(mainSecIdList);
         return IndicatorService.getInstance().calcMultipleSecMultipleTimeRangeIndicator(req, allNavMap, secFreqMap);
     }
@@ -54,14 +51,42 @@ public class BaseIndicatorServiceV2Impl implements BaseIndicatorServiceV2 {
     @Override
     public Map<String, List<IndicatorCalcPropertyDto>> getMultipleSecTrend(List<String> mainSecIdList, Map<String, String> secBenchmarkIdMap,
                                                                            List<String> indexIdList, DateIntervalDto dateIntervalDto, Frequency frequency,
-                                                                           BigDecimal fixedIncome, BigDecimal initValue, RaiseType raiseType, IStrategy strategy,
+                                                                           BigDecimal fixedIncome, BigDecimal initValue,
                                                                            Visibility visibility, NavType navType, List<TrendType> trendTypeV2List) {
         List<String> benchmarkIdList = secBenchmarkIdMap.values().stream().distinct().collect(Collectors.toList());
-        CurveType curveType = CurveType.getCurveType(raiseType, strategy);
         Map<String, List<DateValue>> allNavMap = navService.getSecIdDateValueNavListMapFromRedisAndDB(mainSecIdList, benchmarkIdList, indexIdList,
-                null, null, navType, visibility, curveType.getId(), strategy.getStrategyId(), new HashMap<>(), false);
+                null, null, navType, visibility);
         Map<String, Frequency> secFreqMap = this.fundInformationDao.getNavFrequency(mainSecIdList);
         return IndicatorService.getInstance().getMultipleSecTrend(mainSecIdList, secBenchmarkIdMap, indexIdList, dateIntervalDto, fixedIncome,
                 initValue, frequency, trendTypeV2List, secFreqMap, allNavMap);
     }
+
+    @Override
+    public List<IndicatorCalcTimeRangeDto> getSecTimeRange(String mainSecId, Visibility visibility) {
+        List<String> secIds = ListUtil.of(mainSecId);
+        Map<String, Frequency> navFrequency = this.fundInformationDao.getNavFrequency(secIds);
+        Map<String, List<DateValue>> allNavMap = navService.getSecIdDateValueNavListMapFromRedisAndDB(secIds, ListUtil.empty(), ListUtil.empty(),
+                null, null, NavType.All, visibility);
+        return IndicatorService.getInstance().getSecTimeRange(mainSecId, navFrequency.get(mainSecId), allNavMap);
+    }
+
+    @Override
+    public Map<String, List<IndicatorCalcPropertyDto>> getMultiSecRetListNew(List<String> mainSecIdList, List<String> indexIds, Frequency frequency, Frequency rollingFrequency,
+                                                                             String startDate, String endDate, boolean ifExcessReturn, String benchmarkId, RaiseType raiseType,
+                                                                             IStrategy strategy, Visibility visible, NavType navType) {
+        Map<String, List<DateValue>> allNavMap = navService.getSecIdDateValueNavListMapFromRedisAndDB(mainSecIdList, ListUtil.of(benchmarkId), indexIds,
+                startDate, endDate, navType, visible);
+        Map<String, Frequency> secFreqMap = this.fundInformationDao.getNavFrequency(mainSecIdList);
+        return IndicatorService.getInstance().getMultiSecRetListNew(mainSecIdList, indexIds, frequency, rollingFrequency, startDate, endDate, ifExcessReturn,
+                benchmarkId, raiseType, strategy, visible, navType, allNavMap, secFreqMap);
+    }
+
+    @Override
+    public Map<String, List<IndicatorCalcPropertyDto>> getMultiSecRetListNew(List<String> mainSecIdList, List<String> indexIds, Frequency frequency, Frequency rollingFrequency,
+                                                                             String startDate, String endDate, boolean ifExcessReturn, String benchmarkId, RaiseType raiseType, IStrategy strategy,
+                                                                             Visibility visible, NavType navType, Map<String, List<DateValue>> allNavMap) {
+        Map<String, Frequency> secFreqMap = this.fundInformationDao.getNavFrequency(mainSecIdList);
+        return IndicatorService.getInstance().getMultiSecRetListNew(mainSecIdList, indexIds, frequency, rollingFrequency, startDate, endDate, ifExcessReturn,
+                benchmarkId, raiseType, strategy, visible, navType, allNavMap, secFreqMap);
+    }
 }

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

@@ -7,17 +7,21 @@ import cn.hutool.core.util.StrUtil;
 import com.smppw.analysis.domain.dao.FundInformationDao;
 import com.smppw.analysis.domain.dao.IndexesProfileDao;
 import com.smppw.analysis.domain.dao.RongzhiIndexNavDao;
+import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
 import com.smppw.analysis.domain.event.SaveCacheEvent;
 import com.smppw.analysis.domain.gateway.CacheFactory;
 import com.smppw.analysis.domain.gateway.CacheGateway;
 import com.smppw.analysis.domain.service.BaseInfoService;
 import com.smppw.analysis.infrastructure.config.AnalysisProperty;
+import com.smppw.analysis.infrastructure.consts.RedisConst;
 import com.smppw.common.cache.CaffeineLocalCache;
+import com.smppw.common.pojo.enums.Indicator;
 import com.smppw.common.pojo.enums.strategy.Strategy;
 import com.smppw.constants.SecType;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
+import org.springframework.lang.NonNull;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -56,55 +60,61 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
     }
 
     @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
         this.applicationContext = applicationContext;
     }
 
     @Override
-    public String getFundType(String fundId) {
-        if (fundId == null) {
+    public String getLatestRankRat() {
+        // todo 排名期
+        return null;
+    }
+
+    @Override
+    public String getSecType(String secId) {
+        if (secId == null) {
             return null;
         }
-        if (fundId.startsWith(HF)) {
+        if (secId.startsWith(HF)) {
             return SecType.PRIVATELY_OFFERED_FUND;
-        } else if (fundId.startsWith(MF)) {
+        } else if (secId.startsWith(MF)) {
             return SecType.PUBLICLY_OFFERED_FUNDS;
-        } else if (fundId.startsWith(CF)) {
+        } else if (secId.startsWith(CF)) {
             return SecType.PRIVATE_FUND;
-        } else if (fundId.startsWith(FA)) {
+        } else if (secId.startsWith(FA)) {
             return SecType.FACTOR;
-        } else if (fundId.startsWith(CI)) {
+        } else if (secId.startsWith(CI)) {
             return SecType.UDF_INDEX;
-        } else if (fundId.startsWith(CO)) {
+        } else if (secId.startsWith(CO)) {
             return SecType.COMPANY;
-        } else if (fundId.startsWith(PL)) {
+        } else if (secId.startsWith(PL)) {
             return SecType.MANAGER;
-        } else if (fundId.startsWith(PO)) {
+        } else if (secId.startsWith(PO)) {
             return SecType.COMBINATION;
-        } else if (StrUtil.isNumeric(fundId)) {
-            if (Strategy.isStrategy(fundId)) {
+        } else if (StrUtil.isNumeric(secId)) {
+            if (Strategy.isStrategy(secId)) {
                 return SecType.STRATEGY;
             }
-        } else if (fundId.startsWith(IN)) {
+        } else if (secId.startsWith(IN)) {
             List<String> thirdIndexes = CaffeineLocalCache.getThirdIndexes();
-            if (thirdIndexes != null && thirdIndexes.contains(fundId)) {
+            if (thirdIndexes != null && thirdIndexes.contains(secId)) {
                 return SecType.THIRD_INDEX_FUND;
             }
             List<String> riskOfFreeIdList = CaffeineLocalCache.getRiskOfFreeId();
-            if (riskOfFreeIdList != null && riskOfFreeIdList.contains(fundId)) {
+            if (riskOfFreeIdList != null && riskOfFreeIdList.contains(secId)) {
                 return SecType.RISK_OF_FREE;
             }
-            Boolean isExist = INDEX_EXIST.get(fundId);
+            Boolean isExist = INDEX_EXIST.get(secId);
             if (isExist == null) {
-                isExist = rongzhiIndexNavDao.isExist(fundId);
-                INDEX_EXIST.put(fundId, isExist);
+                isExist = rongzhiIndexNavDao.isExist(secId);
+                INDEX_EXIST.put(secId, isExist);
             }
             if (isExist) {
                 return SecType.INDEX_FUND;
             } else {
                 return SecType.RONGZHI_INDEX;
             }
-        } else if (fundId.startsWith(AP)) {
+        } else if (secId.startsWith(AP)) {
             return SecType.ADVISORY_POOL_CURVE;
         }
         return null;
@@ -114,7 +124,7 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
     public Map<String, List<String>> getTypeSecMap(List<String> secIdList) {
         Map<String, List<String>> secIdTypeMap = new HashMap<>(10);
         for (String secId : secIdList) {
-            String secIdType = getFundType(secId);
+            String secIdType = getSecType(secId);
             if (secIdTypeMap.containsKey(secIdType)) {
                 List<String> list = secIdTypeMap.get(secIdType);
                 list.add(secId);
@@ -128,11 +138,11 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
     }
 
     @Override
-    public Map<String, String> querySecType(List<String> secIdList) {
+    public Map<String, String> querySecsType(List<String> secIdList) {
         if (CollUtil.isEmpty(secIdList)) {
             return MapUtil.newHashMap(8);
         }
-        return secIdList.stream().collect(Collectors.toMap(e -> e, this::getFundType));
+        return secIdList.stream().collect(Collectors.toMap(e -> e, this::getSecType));
     }
 
     @Override
@@ -141,7 +151,7 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
             return MapUtil.empty();
         }
         int size = allSecIdList.size();
-        String key = "info:secName";
+        String key = RedisConst.INFO_NAME;
         Map<String, Object> hget = this.cacheGateway.hget(key);
         Map<Boolean, List<String>> redisSecMap = allSecIdList.stream().collect(Collectors.groupingBy(hget::containsKey));
         List<String> redisSecIds = redisSecMap.get(Boolean.TRUE);
@@ -166,7 +176,6 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
                 Map<String, String> marketFundIdNameMap = indexesProfileDao.getFundIdNameMap(marketIndexIds);
                 secNameMap.putAll(marketFundIdNameMap);
             }
-            // todo 其他(机构、经理、组合)
             // 推送事件,存缓存
             SaveCacheEvent<Map<String, Object>> event = new SaveCacheEvent<>(this, secNameMap, t -> {
                 this.cacheGateway.hset(key, t);
@@ -182,4 +191,16 @@ public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextA
         }
         return result;
     }
+
+    @Override
+    public List<MonetaryFundProfitDO> queryMonetaryFund(String fundId) {
+        // todo
+        return null;
+    }
+
+    @Override
+    public List<Map<String, Object>> getFundRank(String rankDate, String fundId, List<String> indexIds, Indicator indicator) {
+        // todo
+        return null;
+    }
 }

+ 4 - 5
src/main/java/com/smppw/analysis/domain/service/impl/NavServiceImpl.java

@@ -130,8 +130,8 @@ public class NavServiceImpl implements NavService {
     }
 
     @Override
-    public Map<String, List<DateValue>> getSecIdDateValueNavListMapFromRedisAndDB(List<String> mainSecIdList, List<String> benchmarkIdList, List<String> indexList
-            , String startDate, String endDate, NavType navType, Visibility visibility, Integer curveTypeId, Integer strategyId, Map<String, Frequency> secFrequencyMap, boolean getRedisData) {
+    public Map<String, List<DateValue>> getSecIdDateValueNavListMapFromRedisAndDB(List<String> mainSecIdList, List<String> benchmarkIdList, List<String> indexList,
+                                                                                  String startDate, String endDate, NavType navType, Visibility visibility) {
 
         //全部的标的集合
         Map<String, Boolean> secIfExtractMap = new HashMap<>();
@@ -151,7 +151,7 @@ public class NavServiceImpl implements NavService {
         Map<String, List<DateValue>> allSecNavListMap = new HashMap<>();
 
         //取DB
-        Map<String, List<DateValue>> secNavListMapDbData = getSecIdDateValueNavListMapByDb(secIds, startDate, endDate, curveTypeId, strategyId, visibility, navType, secFrequencyMap, secIfExtractMap);
+        Map<String, List<DateValue>> secNavListMapDbData = getSecIdDateValueNavListMapByDb(secIds, startDate, endDate, visibility, navType, secIfExtractMap);
         allSecNavListMap.putAll(secNavListMapDbData);
 
         //将取DB的标的的净值存进redis
@@ -162,8 +162,7 @@ public class NavServiceImpl implements NavService {
 
     @Override
     public Map<String, List<DateValue>> getSecIdDateValueNavListMapByDb(List<String> allSecIdList, String startDate, String endDate
-            , Integer curveTypeId, Integer strategyId, Visibility visibility, NavType navType, Map<String, Frequency> secFrequencyMap
-            , Map<String, Boolean> secIfExtractMap) {
+            ,Visibility visibility, NavType navType, Map<String, Boolean> secIfExtractMap) {
 
         Map<String, List<DateValue>> allNavMap = new HashMap<>();
 

+ 18 - 0
src/main/java/com/smppw/analysis/infrastructure/config/AnalysisProperty.java

@@ -11,8 +11,18 @@ import org.springframework.context.annotation.Configuration;
 @Configuration
 @ConfigurationProperties(prefix = "smppw.data.analysis")
 public class AnalysisProperty {
+    /**
+     * 远程调用的python接口地址
+     */
     private String pyUrl = "http://localhost:8088/";
+    /**
+     * 缓存类型,支持memory、redis,默认memory
+     */
     private String cacheType = "memory";
+    /**
+     * 签名校验是否可用
+     */
+    private Boolean enableSign = Boolean.FALSE;
 
     public String getPyUrl() {
         return pyUrl;
@@ -29,4 +39,12 @@ public class AnalysisProperty {
     public void setCacheType(String cacheType) {
         this.cacheType = cacheType;
     }
+
+    public Boolean getEnableSign() {
+        return enableSign;
+    }
+
+    public void setEnableSign(Boolean enableSign) {
+        this.enableSign = enableSign;
+    }
 }

+ 2 - 3
src/main/java/com/smppw/analysis/infrastructure/consts/RedisConst.java

@@ -35,6 +35,8 @@ public final class RedisConst {
      */
     public static final String PORTFOLIO_NAV_TASK_KEY = "portfolio:nav:task:";
 
+    public static final String INFO_NAME = "info:secName";
+
 
     // -------------- 基金持仓分析key 和 超时时间 -------------------------------
 
@@ -45,17 +47,14 @@ public final class RedisConst {
 
     /**
      * (沪深300、中证500和中证1000)成分股占比,原则上每月更新一次,目前先设置超时时间28天
-     * todo 提供接口在成分股更新时刷新缓存
      */
     public static final String POSITION_INDEX_WEIGHT_KEY = "position:index:weight:";
     /**
      * 所有股票与行业对应关系,每天都有更新,设置超时时间1天
-     * todo 做一个定时任务每天预缓存该数据
      */
     public static final String POSITION_STOCK_INDUSTRY_KEY = "position:stock:industry";
     /**
      * 估值表详情信息
-     * todo 基金估值表解析时要更新
      */
     public static final String POSITION_DETAIL_KEY = "position:detail:";
     /**

+ 50 - 6
src/main/java/com/smppw/analysis/infrastructure/gatewayimpl/InMemoryCacheGateway.java

@@ -1,68 +1,112 @@
 package com.smppw.analysis.infrastructure.gatewayimpl;
 
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
 import com.smppw.analysis.domain.gateway.CacheFactory;
 import com.smppw.analysis.domain.gateway.CacheGateway;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
+import javax.naming.OperationNotSupportedException;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+/**
+ * @author wangzaijun
+ * @date 2023/8/8 9:13
+ * @description 简单内存缓存,不支持设置超时时间,限制内存容量为 1 << 5
+ */
 @Component(CacheFactory.MEMORY)
 public class InMemoryCacheGateway implements CacheGateway<Object> {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+    private static final Map<String, Object> CACHE_MAP = MapUtil.newConcurrentHashMap();
+
     @Override
     public Boolean hasKey(String key) {
-        return null;
+        return CACHE_MAP.containsKey(key);
     }
 
     @Override
     public boolean expire(String key, long ttl, TimeUnit timeUnit) {
-
+        this.logger.warn(StrUtil.format("memory cache key:{} no support set ttl!", key));
         return false;
     }
 
     @Override
     public boolean set(String key, Object value) {
+        if (this.addable()) {
+            CACHE_MAP.put(key, value);
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean set(String key, Object value, long ttl, TimeUnit timeUnit) {
+        if (this.addable()) {
+            CACHE_MAP.put(key, value);
+            this.logger.warn(StrUtil.format("memory cache key:{} no support set ttl!", key));
+            return true;
+        }
         return false;
     }
 
     @Override
     public Object get(String key) {
-        return null;
+        return CACHE_MAP.get(key);
     }
 
     @Override
     public void delete(List<String> keys) {
-
+        CACHE_MAP.keySet().removeIf(keys::contains);
     }
 
     @Override
     public boolean hset(String key, Map<String, Object> values) {
+        if (this.addable()) {
+            CACHE_MAP.put(key, values);
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean hset(String key, String item, Object value) {
+        if (this.addable()) {
+            Map<String, Object> data = MapUtil.<String, Object>builder().put(item, value).build();
+            CACHE_MAP.put(key, data);
+            return true;
+        }
         return false;
     }
 
     @Override
     public boolean hset(String key, String item, Object value, long ttl, TimeUnit timeUnit) {
+        if (this.addable()) {
+            Map<String, Object> data = MapUtil.<String, Object>builder().put(item, value).build();
+            CACHE_MAP.put(key, data);
+            this.logger.warn(StrUtil.format("memory cache key:{} no support set ttl!", key));
+            return true;
+        }
         return false;
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public Map<String, Object> hget(String key) {
-        return null;
+        return MapUtil.get(CACHE_MAP, key, Map.class);
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public Object hget(String key, String item) {
-        return null;
+        Map<String, Object> data = MapUtil.get(CACHE_MAP, key, Map.class);
+        return data.get(item);
+    }
+
+    private boolean addable() {
+        return CACHE_MAP.size() <= 1 << 5;
     }
 }

+ 11 - 0
src/main/java/com/smppw/analysis/infrastructure/persistence/MonetaryFundProfitMapper.java

@@ -0,0 +1,11 @@
+package com.smppw.analysis.infrastructure.persistence;
+
+import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface MonetaryFundProfitMapper {
+    List<MonetaryFundProfitDO> queryByFundId(String fundId);
+}