FundNavService.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package com.simuwang.manage.service.competition;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.map.MapUtil;
  5. import com.simuwang.base.common.conts.DateConst;
  6. import com.simuwang.base.common.util.NavDataUtil;
  7. import com.simuwang.base.mapper.*;
  8. import com.simuwang.base.pojo.dos.*;
  9. import com.simuwang.base.pojo.dto.FundNavDataDTO;
  10. import com.simuwang.base.pojo.dto.FundNavDeletionDTO;
  11. import com.simuwang.base.pojo.dto.TradeDateDTO;
  12. import com.simuwang.base.pojo.dto.competition.CompetitionBaseResultDTO;
  13. import org.springframework.stereotype.Service;
  14. import java.math.BigDecimal;
  15. import java.math.RoundingMode;
  16. import java.util.Comparator;
  17. import java.util.Date;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.stream.Collectors;
  21. @Service
  22. public class FundNavService {
  23. private final NavMapper navMapper;
  24. private final FundInfoMapper fundInfoMapper;
  25. private final AssetMapper assetMapper;
  26. private final DeletionInfoMapper deletionInfoMapper;
  27. private final TradeDateMapper tradeDateMapper;
  28. private final CompetitionFactory competitionFactory;
  29. public FundNavService(NavMapper navMapper, FundInfoMapper fundInfoMapper,
  30. AssetMapper assetMapper, DeletionInfoMapper deletionInfoMapper,
  31. TradeDateMapper tradeDateMapper, CompetitionFactory competitionFactory) {
  32. this.navMapper = navMapper;
  33. this.fundInfoMapper = fundInfoMapper;
  34. this.assetMapper = assetMapper;
  35. this.deletionInfoMapper = deletionInfoMapper;
  36. this.tradeDateMapper = tradeDateMapper;
  37. this.competitionFactory = competitionFactory;
  38. }
  39. public List<FundNavDataDTO> getFungNavData(Integer competitionId) {
  40. List<FundNavDataDTO> navDataDTOList = CollUtil.newArrayList();
  41. List<NavDO> navDOList = navMapper.queryAllNav(competitionId);
  42. if (CollUtil.isEmpty(navDOList)) {
  43. return navDataDTOList;
  44. }
  45. // 过滤出周频的净值点
  46. String toDay = DateUtil.format(new Date(), DateConst.YYYY_MM_DD);
  47. List<TradeDateDO> tradeDateDOList = tradeDateMapper.listAllTradeDate(toDay);
  48. navDOList = NavDataUtil.filterWeekFrequencyNav(navDOList, tradeDateDOList);
  49. List<String> fundIdList = navDOList.stream().map(NavDO::getFundId).distinct().toList();
  50. List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId);
  51. Map<String, FundAndCompanyInfoDO> fundIdCompanyNameMap = fundInfoCompanyNameList.stream().collect(Collectors.toMap(FundAndCompanyInfoDO::getFundId, v -> v));
  52. List<AssetDO> assetDOList = assetMapper.queryAssetByFundId(fundIdList);
  53. Map<String, List<AssetDO>> fundIdAssetMap = MapUtil.newHashMap();
  54. if (CollUtil.isNotEmpty(assetDOList)) {
  55. fundIdAssetMap = assetDOList.stream().collect(Collectors.groupingBy(AssetDO::getFundId));
  56. }
  57. Map<String, List<NavDO>> fundIdNavMap = navDOList.stream().collect(Collectors.groupingBy(NavDO::getFundId));
  58. for (Map.Entry<String, List<NavDO>> fundIdNavEntry : fundIdNavMap.entrySet()) {
  59. String fundId = fundIdNavEntry.getKey();
  60. List<NavDO> fundNavDoList = fundIdNavEntry.getValue();
  61. List<AssetDO> fundAssetDoList = fundIdAssetMap.get(fundId);
  62. FundAndCompanyInfoDO fundInfoDO = fundIdCompanyNameMap.get(fundId);
  63. List<FundNavDataDTO> fundNavDataDTOList = buildFundNavDataDTO(fundInfoDO, fundNavDoList, fundAssetDoList);
  64. navDataDTOList.addAll(fundNavDataDTOList);
  65. }
  66. return navDataDTOList;
  67. }
  68. public List<FundNavDeletionDTO> getFundNavDeletion(Integer competitionId, String endDate) {
  69. List<FundNavDeletionDTO> navDeletionDTOList = CollUtil.newArrayList();
  70. // 缺失类型-1对应全部,1-净值缺失,2-对应规模缺失,3-对应分红缺失,5-估值缺失
  71. List<FundDeletionInfoDO> deletionInfoDOList = deletionInfoMapper.getFundNavDeletionNew(1, competitionId, endDate);
  72. if (CollUtil.isEmpty(deletionInfoDOList)) {
  73. return navDeletionDTOList;
  74. }
  75. Map<String, List<FundDeletionInfoDO>> fundIdDeletionInfoMap = deletionInfoDOList.stream().collect(Collectors.groupingBy(FundDeletionInfoDO::getFundId));
  76. // 基金信息和对应的管理人信息
  77. List<FundAndCompanyInfoDO> fundInfoCompanyNameList = fundInfoMapper.queryFundAndTrustByFundId(competitionId);
  78. if (CollUtil.isEmpty(fundInfoCompanyNameList)) {
  79. return navDeletionDTOList;
  80. }
  81. // 得到存在基金完整的基金id
  82. List<String> allFundIdList = navMapper.getAllFundId();
  83. // 得到基金净值缺失的基金Id
  84. List<String> deletionFundIdList = getDeletionFundId(fundInfoCompanyNameList, fundIdDeletionInfoMap);
  85. List<String> notDeletionFundIdList = allFundIdList.stream().filter(e -> !deletionFundIdList.contains(e)).toList();
  86. // 过滤掉净值没有缺失的基金Id
  87. fundInfoCompanyNameList = fundInfoCompanyNameList.stream().filter(e -> !notDeletionFundIdList.contains(e.getFundId())).toList();
  88. for (FundAndCompanyInfoDO fundAndCompanyInfoDO : fundInfoCompanyNameList) {
  89. String fundId = fundAndCompanyInfoDO.getFundId();
  90. String entryDate = DateUtil.format(fundAndCompanyInfoDO.getEntryDate(), DateConst.YYYY_MM_DD);
  91. // 获取净值日期所在年和所在周
  92. Map<String, TradeDateDTO> tradeDateDoMap = getYearAndWeekOfDate(entryDate, endDate);
  93. List<FundDeletionInfoDO> fundDeletionInfoDOList = fundIdDeletionInfoMap.get(fundId);
  94. if (CollUtil.isNotEmpty(fundDeletionInfoDOList)) {
  95. fundDeletionInfoDOList = fundDeletionInfoDOList.stream().filter(e -> e.getDeletionDate().compareTo(entryDate) >= 0).toList();
  96. }
  97. List<FundNavDeletionDTO> fundNavDataDTOList = buildFundNavDeletionDTO(fundAndCompanyInfoDO, fundDeletionInfoDOList, tradeDateDoMap);
  98. navDeletionDTOList.addAll(fundNavDataDTOList);
  99. }
  100. return navDeletionDTOList;
  101. }
  102. private List<String> getDeletionFundId(List<FundAndCompanyInfoDO> fundInfoCompanyNameList, Map<String, List<FundDeletionInfoDO>> fundIdDeletionInfoMap) {
  103. List<String> deletionFundIdList = CollUtil.newArrayList();
  104. for (FundAndCompanyInfoDO fundAndCompanyInfoDO : fundInfoCompanyNameList) {
  105. String fundId = fundAndCompanyInfoDO.getFundId();
  106. String entryDate = DateUtil.format(fundAndCompanyInfoDO.getEntryDate(), DateConst.YYYY_MM_DD);
  107. List<FundDeletionInfoDO> fundDeletionInfoDOList = fundIdDeletionInfoMap.get(fundId);
  108. if (CollUtil.isEmpty(fundDeletionInfoDOList)) {
  109. continue;
  110. }
  111. long count = fundDeletionInfoDOList.stream().filter(e -> e.getDeletionDate().compareTo(entryDate) >= 0).count();
  112. if (count != 0) {
  113. deletionFundIdList.add(fundId);
  114. }
  115. }
  116. return deletionFundIdList;
  117. }
  118. public List<? extends CompetitionBaseResultDTO> getCompetitionResult(Integer competitionId, String period) {
  119. List<? extends CompetitionBaseResultDTO> dataList = CollUtil.newArrayList();
  120. AbstractCompetitionResultService competitionResult = competitionFactory.getInstance(competitionId);
  121. if (competitionResult == null) {
  122. return dataList;
  123. }
  124. return competitionResult.getCompetitionResult(competitionId, period);
  125. }
  126. private List<FundNavDeletionDTO> buildFundNavDeletionDTO(FundAndCompanyInfoDO fundAndCompanyInfoDO, List<FundDeletionInfoDO> fundDeletionInfoDOList, Map<String, TradeDateDTO> tradeDateDoMap) {
  127. String fundName = fundAndCompanyInfoDO.getFundName();
  128. String trustName = fundAndCompanyInfoDO.getCompanyName();
  129. String trustRegisterNumber = fundAndCompanyInfoDO.getCompanyRegisterNumber();
  130. String registerNumber = fundAndCompanyInfoDO.getRegisterNumber();
  131. String fundId = fundAndCompanyInfoDO.getFundId();
  132. // 净值缺失表中无该基金的数据 -> 该基金为缺失全部净值
  133. if (CollUtil.isEmpty(fundDeletionInfoDOList)) {
  134. List<FundNavDeletionDTO> navDeletionDTOList = CollUtil.newArrayList();
  135. tradeDateDoMap.forEach((k, v) -> {
  136. FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO();
  137. fundNavDeletionDTO.setTrustName(trustName);
  138. fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber);
  139. fundNavDeletionDTO.setFundId(fundId);
  140. fundNavDeletionDTO.setFundName(fundName);
  141. fundNavDeletionDTO.setRegisterNumber(registerNumber);
  142. fundNavDeletionDTO.setYear(v != null ? v.getYear() + v.getWeek() : null);
  143. fundNavDeletionDTO.setWeek(v != null ? String.valueOf(v.getWeek()) : null);
  144. // 第1周(2022-12-26至2022-12-30)
  145. String date = v != null ? v.getFirstDate() + "至" + v.getLastDate() : null;
  146. fundNavDeletionDTO.setCompetitionDate(date);
  147. fundNavDeletionDTO.setDate(k);
  148. navDeletionDTOList.add(fundNavDeletionDTO);
  149. });
  150. navDeletionDTOList.sort(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getWeek));
  151. return navDeletionDTOList;
  152. }
  153. return fundDeletionInfoDOList.stream().map(e -> {
  154. FundNavDeletionDTO fundNavDeletionDTO = new FundNavDeletionDTO();
  155. fundNavDeletionDTO.setTrustName(trustName);
  156. fundNavDeletionDTO.setTrustRegisterNumber(trustRegisterNumber);
  157. fundNavDeletionDTO.setFundId(fundId);
  158. fundNavDeletionDTO.setFundName(fundName);
  159. fundNavDeletionDTO.setRegisterNumber(registerNumber);
  160. TradeDateDTO tradeDateDTO = tradeDateDoMap.get(e.getDeletionDate());
  161. fundNavDeletionDTO.setYear(tradeDateDTO != null ? tradeDateDTO.getYear() + tradeDateDTO.getWeek() : null);
  162. fundNavDeletionDTO.setWeek(tradeDateDTO != null ? String.valueOf(tradeDateDTO.getWeek()) : null);
  163. // 第1周(2022-12-26至2022-12-30)
  164. String date = tradeDateDTO != null ? tradeDateDTO.getFirstDate() + "至" + tradeDateDTO.getLastDate() : null;
  165. fundNavDeletionDTO.setCompetitionDate(date);
  166. fundNavDeletionDTO.setDate(e.getDeletionDate());
  167. return fundNavDeletionDTO;
  168. }).sorted(Comparator.comparing(FundNavDeletionDTO::getFundName).thenComparing(FundNavDeletionDTO::getWeek)).toList();
  169. }
  170. private List<FundNavDataDTO> buildFundNavDataDTO(FundAndCompanyInfoDO fundInfoDO, List<NavDO> fundNavDoList, List<AssetDO> fundAssetDoList) {
  171. String fundName = fundInfoDO.getFundName();
  172. String registerNumber = fundInfoDO.getRegisterNumber();
  173. String trustName = fundInfoDO.getCompanyName();
  174. String trustRegisterNumber = fundInfoDO.getCompanyRegisterNumber();
  175. Map<String, BigDecimal> priceDateAssetMap = MapUtil.newHashMap();
  176. if (CollUtil.isNotEmpty(fundAssetDoList)) {
  177. priceDateAssetMap = fundAssetDoList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getPriceDate(), DateConst.YYYY_MM_DD), AssetDO::getAssetNet));
  178. }
  179. Map<String, BigDecimal> finalPriceDateAssetMap = priceDateAssetMap;
  180. return fundNavDoList.stream().map(e -> {
  181. FundNavDataDTO fundNavDataDTO = new FundNavDataDTO();
  182. fundNavDataDTO.setTrustName(trustName);
  183. fundNavDataDTO.setTrustRegisterNumber(trustRegisterNumber);
  184. fundNavDataDTO.setFundId(e.getFundId());
  185. fundNavDataDTO.setFundName(fundName);
  186. fundNavDataDTO.setRegisterNumber(registerNumber);
  187. String priceDate = e.getPriceDate() != null ? DateUtil.format(e.getPriceDate(), DateConst.YYYY_MM_DD) : null;
  188. fundNavDataDTO.setPriceDate(priceDate);
  189. fundNavDataDTO.setNav(e.getNav() != null ? String.valueOf(e.getNav()) : null);
  190. fundNavDataDTO.setCumulativeNavWithdrawal(e.getCumulativeNavWithdrawal() != null ? String.valueOf(e.getCumulativeNavWithdrawal()) : null);
  191. BigDecimal asset = finalPriceDateAssetMap.get(priceDate) != null ? finalPriceDateAssetMap.get(priceDate).setScale(2, RoundingMode.HALF_UP) : null;
  192. fundNavDataDTO.setAsset(asset != null ? String.valueOf(asset) : null);
  193. return fundNavDataDTO;
  194. }).sorted(Comparator.comparing(FundNavDataDTO::getFundName).thenComparing(FundNavDataDTO::getPriceDate)).toList();
  195. }
  196. private Map<String, TradeDateDTO> getYearAndWeekOfDate(String startDate, String endDate) {
  197. Map<String, TradeDateDTO> tradeDateDoMap = MapUtil.newHashMap();
  198. List<TradeDateDO> tradeDateDOList = tradeDateMapper.selectTradeDate(startDate, endDate);
  199. if (CollUtil.isEmpty(tradeDateDOList)) {
  200. return tradeDateDoMap;
  201. }
  202. List<Integer> yearWeekList = tradeDateDOList.stream().map(TradeDateDO::getYearWeek).distinct().toList();
  203. Map<String, TradeDateDO> dateMap = tradeDateDOList.stream().collect(Collectors.toMap(k -> DateUtil.format(k.getTradeDate(), DateConst.YYYY_MM_DD), v -> v));
  204. Map<Integer, List<TradeDateDO>> yearWeekDateMap = tradeDateDOList.stream().collect(Collectors.groupingBy(TradeDateDO::getYearWeek));
  205. // 得到startDate~endDate的最后一个交易日
  206. List<String> dateList = CollUtil.newArrayList();
  207. yearWeekDateMap.forEach((k, v) -> {
  208. String date = v.stream().max(Comparator.comparing(TradeDateDO::getTradeDate)).map(e -> DateUtil.format(e.getTradeDate(), DateConst.YYYY_MM_DD)).orElse(null);
  209. dateList.add(date);
  210. });
  211. for (String date : dateList) {
  212. TradeDateDO tradeDateDO = dateMap.get(date);
  213. Integer yearWeek = tradeDateDO.getYearWeek();
  214. TradeDateDTO tradeDateDTO = new TradeDateDTO();
  215. tradeDateDTO.setWeek(tradeDateDO.getWeekOfYear());
  216. tradeDateDTO.setYear(tradeDateDO.getEndYear());
  217. String firstDate = yearWeekDateMap.get(yearWeek).stream()
  218. .min(Comparator.comparing(TradeDateDO::getTradeDate)).map(e -> DateUtil.format(e.getTradeDate(), DateConst.YYYY_MM_DD)).orElse(null);
  219. tradeDateDTO.setFirstDate(firstDate);
  220. tradeDateDTO.setLastDate(date);
  221. int competitionWeek = (int) yearWeekList.stream().filter(e -> e.compareTo(yearWeek) < 0).count() + 1;
  222. tradeDateDTO.setCompetitionWeek(competitionWeek);
  223. tradeDateDoMap.put(date, tradeDateDTO);
  224. }
  225. return tradeDateDoMap;
  226. }
  227. }