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