package com.simuwang.manage.task; import cn.hutool.core.date.DateUtil; import com.simuwang.base.common.enums.DeletionType; import com.simuwang.base.common.enums.DistributeType; import com.simuwang.base.common.enums.Frequency; import com.simuwang.base.common.util.DateUtils; import com.simuwang.base.common.util.StringUtil; import com.simuwang.base.mapper.*; import com.simuwang.base.pojo.dos.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /** * FileName: FundDeletionTask * Author: chenjianhua * Date: 2024/9/18 22:43 * Description: ${DESCRIPTION} */ @EnableScheduling @Component public class FundDeletionTask { @Autowired private NavMapper navMapper; @Autowired private AssetMapper assetMapper; @Autowired private FundInfoMapper fundInfoMapper; @Autowired private FundReportFrequencyMapper fundReportFrequencyMapper; @Autowired private TradeDateMapper tradeDateMapper; @Autowired private DeletionInfoMapper deletionInfoMapper; @Autowired private DistributionMapper distributionMapper; // @Scheduled(cron = "0 0 5,12,18 * * ?") public void computeDeletion(){ List fundIdList = navMapper.getAllFundId(); for(String fundId : fundIdList){ String inceptionDate = fundInfoMapper.getInceptionDateByFundId(fundId); if(inceptionDate == null){ continue; } String today = DateUtils.getAroundToday(0); //获取基金对应的净值报送频率 FundReportFrequencyDO fundReportFrequencyDO = fundReportFrequencyMapper.getFrequencyByFundId(fundId); if(StringUtil.isNull(fundReportFrequencyDO)){ continue; } List navDOList = navMapper.selectNavByFundId(fundId); List assetDOList = assetMapper.selectAssetByFundId(fundId); //查询成立日到今天为止的交易日集合 List tradeDateDOList = tradeDateMapper.selectTradeDate(inceptionDate,today); //延迟天数为3天 tradeDateDOList = tradeDateDOList.subList(0,tradeDateDOList.size()-3); navDeletion(fundId,navDOList,tradeDateDOList,fundReportFrequencyDO); assetDeletion(fundId,assetDOList,tradeDateDOList,fundReportFrequencyDO); distributionDeletion(fundId,navDOList); } } private void distributionDeletion(String fundId, List navDOList) { if(navDOList.size() < 1){ return; } //查询是否存在拆分 List distributionDOS = distributionMapper.getDistributionByFundId(fundId, DistributeType.DIVIDENDS_SPLIT); if(distributionDOS.size() > 0){ //存在拆分,不做分红缺失计算,同时把以往的数据添加备注 deletionInfoMapper.updateRemark(fundId,DeletionType.ASSET_DELETION.getCode(),null,DeletionType.EXIST_SPLIT.getInfo()); return; } BigDecimal threshold = new BigDecimal(0.0035); BigDecimal preDifference = new BigDecimal(0); for(int navIdx=0;navIdx < navDOList.size() ;navIdx++){ NavDO navDO = navDOList.get(navIdx); //获取当前净值日期下的分红总和 BigDecimal sumDistribute = distributionMapper.getSumDistributeByFundId(navDO.getFundId(),DateUtils.format(navDO.getPriceDate(),DateUtils.YYYY_MM_DD)); BigDecimal nav = navDO.getNav(); BigDecimal cumulativeNavWithdrawal = navDO.getCumulativeNavWithdrawal(); if(sumDistribute == null){ sumDistribute = new BigDecimal(0); } //不存在分红的时候,判断当前的差值是否符合要求 BigDecimal difference = cumulativeNavWithdrawal.subtract(nav.add(sumDistribute)); if(difference.compareTo(threshold) > 0){ //存在缺失 String tradeDate = null; if(navIdx == 0 || navDOList.size() ==1){ //有且仅有一条数据 tradeDate = DateUtils.format(navDO.getPriceDate(),DateUtils.YYYY_MM_DD)+"~"+DateUtils.format(navDO.getPriceDate(),DateUtils.YYYY_MM_DD); }else{ //判断前一条的差值与当前是否一致,一致就不处理 if(difference.compareTo(preDifference) == 0){ continue; } tradeDate = DateUtils.format(navDOList.get(navIdx-1).getPriceDate(),DateUtils.YYYY_MM_DD)+"~"+DateUtils.format(navDO.getPriceDate(),DateUtils.YYYY_MM_DD); } saveDeletionInfoDO(fundId,tradeDate,DeletionType.DISTRIBUTION_DELETION.getCode()); } preDifference = difference; } } private void assetDeletion(String fundId, List assetDOList, List tradeDateDOList, FundReportFrequencyDO fundReportFrequencyDO) { if(Frequency.DAY == Frequency.getFrequencyByCode(fundReportFrequencyDO.getAssetFrequency())){ Map> navListMap = assetDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getTradeDate(),DateUtils.YYYY_MM_DD))); for(String tradeDate : tradeListMap.keySet()){ if(navListMap.containsKey(tradeDate)){ deletionInfoMapper.updateRemark(fundId,DeletionType.ASSET_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.ASSET_DELETION.getCode()); } } if(Frequency.WEEK == Frequency.getFrequencyByCode(fundReportFrequencyDO.getAssetFrequency())){ Map> navListMap = assetDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); TreeMap> weekNavListMap = new TreeMap<>(); //按周数整合 for(String priceDate : navListMap.keySet()){ Integer weekOfYear = DateUtil.weekOfYear(DateUtils.parse(priceDate,DateUtils.YYYY_MM_DD)); if(weekNavListMap.containsKey(weekOfYear)){ List assetDOS = weekNavListMap.get(weekOfYear); assetDOS.addAll(navListMap.get(priceDate)); weekNavListMap.put(weekOfYear,assetDOS); }else{ List navDOS = new ArrayList<>(); navDOS.addAll(navListMap.get(priceDate)); weekNavListMap.put(weekOfYear,navDOS); } } Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> e.getWeekOfYear())); for(Integer weekOfYear : tradeListMap.keySet()){ if(weekNavListMap.containsKey(weekOfYear)){ List assetDOS = weekNavListMap.get(weekOfYear); String tradeDate = DateUtils.format(assetDOS.get(assetDOS.size()-1).getPriceDate(),DateUtils.YYYY_MM_DD); deletionInfoMapper.updateRemark(fundId,DeletionType.ASSET_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //不包含的话,默认取每周的最后一个交易日作为周净值日期 List tradeDateDOS = tradeListMap.get(weekOfYear); String tradeDate = null; if(tradeDateDOS.size() > 0){ tradeDate = DateUtils.format(tradeDateDOS.get(tradeDateDOS.size()-1).getTradeDate(),DateUtils.YYYY_MM_DD); } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.NAV_DELETION.getCode()); } } if(Frequency.MONTH == Frequency.getFrequencyByCode(fundReportFrequencyDO.getAssetFrequency())){ Map> navListMap = assetDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); TreeMap> monthNavListMap = new TreeMap<>(); //按周数整合 for(String priceDate : navListMap.keySet()){ String yearMonth = priceDate.substring(0,7); if(monthNavListMap.containsKey(yearMonth)){ List navDOS = monthNavListMap.get(yearMonth); navDOS.addAll(navListMap.get(priceDate)); monthNavListMap.put(yearMonth,navDOS); }else{ List navDOS = new ArrayList<>(); navDOS.addAll(navListMap.get(priceDate)); monthNavListMap.put(yearMonth,navDOS); } } Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> e.getYearmonth())); for(String yearMonth : tradeListMap.keySet()){ if(monthNavListMap.containsKey(yearMonth)){ List assetDOS = monthNavListMap.get(yearMonth); String tradeDate = DateUtils.format(assetDOS.get(assetDOS.size()-1).getPriceDate(),DateUtils.YYYY_MM_DD); deletionInfoMapper.updateRemark(fundId,DeletionType.ASSET_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //不包含的话,默认取每周的最后一个交易日作为周净值日期 List tradeDateDOS = tradeListMap.get(yearMonth); String tradeDate = null; if(tradeDateDOS.size() > 0){ tradeDate = DateUtils.format(tradeDateDOS.get(tradeDateDOS.size()-1).getTradeDate(),DateUtils.YYYY_MM_DD); } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.ASSET_DELETION.getCode()); } } } private void navDeletion(String fundId,List navDOList, List tradeDateDOList,FundReportFrequencyDO fundReportFrequencyDO) { //只处理日月季频率 if(Frequency.DAY == Frequency.getFrequencyByCode(fundReportFrequencyDO.getNavFrequency())){ Map> navListMap = navDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getTradeDate(),DateUtils.YYYY_MM_DD))); for(String tradeDate : tradeListMap.keySet()){ if(navListMap.containsKey(tradeDate)){ deletionInfoMapper.updateRemark(fundId,DeletionType.NAV_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.NAV_DELETION.getCode()); } } if(Frequency.WEEK == Frequency.getFrequencyByCode(fundReportFrequencyDO.getNavFrequency())){ Map> navListMap = navDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); TreeMap> weekNavListMap = new TreeMap<>(); //按周数整合 for(String priceDate : navListMap.keySet()){ Integer weekOfYear = DateUtil.weekOfYear(DateUtils.parse(priceDate,DateUtils.YYYY_MM_DD)); if(weekNavListMap.containsKey(weekOfYear)){ List navDOS = weekNavListMap.get(weekOfYear); navDOS.addAll(navListMap.get(priceDate)); weekNavListMap.put(weekOfYear,navDOS); }else{ List navDOS = new ArrayList<>(); navDOS.addAll(navListMap.get(priceDate)); weekNavListMap.put(weekOfYear,navDOS); } } Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> e.getWeekOfYear())); for(Integer weekOfYear : tradeListMap.keySet()){ if(weekNavListMap.containsKey(weekOfYear)){ List navDOS = weekNavListMap.get(weekOfYear); String tradeDate = DateUtils.format(navDOS.get(navDOS.size()-1).getPriceDate(),DateUtils.YYYY_MM_DD); deletionInfoMapper.updateRemark(fundId,DeletionType.NAV_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //不包含的话,默认取每周的最后一个交易日作为周净值日期 List tradeDateDOS = tradeListMap.get(weekOfYear); String tradeDate = null; if(tradeDateDOS.size() > 0){ tradeDate = DateUtils.format(tradeDateDOS.get(tradeDateDOS.size()-1).getTradeDate(),DateUtils.YYYY_MM_DD); } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.NAV_DELETION.getCode()); } } if(Frequency.MONTH == Frequency.getFrequencyByCode(fundReportFrequencyDO.getNavFrequency())){ Map> navListMap = navDOList.stream().collect(Collectors.groupingBy(e -> DateUtils.format(e.getPriceDate(),DateUtils.YYYY_MM_DD))); TreeMap> monthNavListMap = new TreeMap<>(); //按周数整合 for(String priceDate : navListMap.keySet()){ String yearMonth = priceDate.substring(0,7); if(monthNavListMap.containsKey(yearMonth)){ List navDOS = monthNavListMap.get(yearMonth); navDOS.addAll(navListMap.get(priceDate)); monthNavListMap.put(yearMonth,navDOS); }else{ List navDOS = new ArrayList<>(); navDOS.addAll(navListMap.get(priceDate)); monthNavListMap.put(yearMonth,navDOS); } } Map> tradeListMap = tradeDateDOList.stream().collect(Collectors.groupingBy(e -> e.getYearmonth())); for(String yearMonth : tradeListMap.keySet()){ if(monthNavListMap.containsKey(yearMonth)){ List navDOS = monthNavListMap.get(yearMonth); String tradeDate = DateUtils.format(navDOS.get(navDOS.size()-1).getPriceDate(),DateUtils.YYYY_MM_DD); deletionInfoMapper.updateRemark(fundId,DeletionType.NAV_DELETION.getCode(),tradeDate,DeletionType.NO_DELETION.getInfo()); continue; } //不包含的话,默认取每周的最后一个交易日作为周净值日期 List tradeDateDOS = tradeListMap.get(yearMonth); String tradeDate = null; if(tradeDateDOS.size() > 0){ tradeDate = DateUtils.format(tradeDateDOS.get(tradeDateDOS.size()-1).getTradeDate(),DateUtils.YYYY_MM_DD); } //写入缺失信息表 saveDeletionInfoDO(fundId,tradeDate,DeletionType.NAV_DELETION.getCode()); } } } private void saveDeletionInfoDO(String fundId, String tradeDate, Integer code) { if(tradeDate == null){ return; } DeletionInfoDO deletionInfoDO = new DeletionInfoDO(); deletionInfoDO.setFundId(fundId); deletionInfoDO.setDeletionDate(tradeDate); deletionInfoDO.setDeletionType(code); DeletionInfoDO oldDeletionDO = deletionInfoMapper.getDeletionInfoDO(deletionInfoDO); if(StringUtil.isNull(oldDeletionDO)){ deletionInfoDO.setIsvalid(1); deletionInfoDO.setIsSend(0); deletionInfoDO.setUpdateTime(DateUtils.getNowDate()); deletionInfoDO.setCreateTime(DateUtils.getNowDate()); deletionInfoMapper.saveDeletionInfoDO(deletionInfoDO); } } }