|
@@ -0,0 +1,324 @@
|
|
|
+package com.smppw.analysis.domain.service.impl;
|
|
|
+
|
|
|
+import com.smppw.analysis.domain.dao.*;
|
|
|
+import com.smppw.analysis.domain.service.NavService;
|
|
|
+import com.smppw.analysis.domain.service.SecTypeService;
|
|
|
+import com.smppw.analysis.infrastructure.utils.DateValueUtil;
|
|
|
+import com.smppw.common.pojo.dto.DateValue;
|
|
|
+import com.smppw.common.pojo.dto.NavDto;
|
|
|
+import com.smppw.common.pojo.enums.Frequency;
|
|
|
+import com.smppw.common.pojo.enums.NavType;
|
|
|
+import com.smppw.common.pojo.enums.Visibility;
|
|
|
+import com.smppw.constants.SecType;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class NavServiceImpl implements NavService {
|
|
|
+
|
|
|
+ private static final Integer REDIS_PIPE_QUERY_SIZE = 50;
|
|
|
+ // @Autowired
|
|
|
+// private JedisDataUtil jedisData;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private RedissonClient redissonClient;
|
|
|
+//
|
|
|
+ @Autowired
|
|
|
+ private SecTypeService secTypeService;
|
|
|
+ //
|
|
|
+// @Autowired
|
|
|
+// private FundInformationDao fundInformationDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CmAdvisoryPoolCurveInfoDao cmAdvisoryPoolCurveInfoDao;
|
|
|
+//
|
|
|
+ @Autowired
|
|
|
+ private PrivatelyOfferedFundNavDao privatelyOfferedFundNavDao;
|
|
|
+ @Autowired
|
|
|
+ private PubliclyOfferedFundNavDao publiclyOfferedFundNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CombinationNavDao combinationNavDao;
|
|
|
+ //
|
|
|
+// @Autowired
|
|
|
+// private PrivateFundNavDao privateFundNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private FactorNavDao factorNavDao;
|
|
|
+//
|
|
|
+ @Autowired
|
|
|
+ private MarketIndexNavDao marketIndexNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private UdfIndexNavDao udfIndexNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CompanyNavDao companyNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private ManagerNavDao managerNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CmAdvisoryPoolCurveWeeklyDao cmAdvisoryPoolCurveWeeklyDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private ThirdIndexNavDao thirdIndexNavDao;
|
|
|
+ @Autowired
|
|
|
+ private RongzhiIndexNavDao rongzhiIndexNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CmFittedAccruedCurveDao cmFittedAccruedCurveDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CmCombinationFundAccruedNavDao cmCombinationFundAccruedNavDao;
|
|
|
+//
|
|
|
+// @Autowired
|
|
|
+// private CmAccruedNavDao cmAccruedNavDao;
|
|
|
+ @Autowired
|
|
|
+ private RiskOfFreeNavDao riskOfFreeNavDao;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param dateValueList 从小到大的净值序列
|
|
|
+ * @param date 日期
|
|
|
+ * @return 小于等于 date 的 日期最大的 日期
|
|
|
+ */
|
|
|
+ public static Integer getMostLeftLess(List<DateValue> dateValueList, String date) {
|
|
|
+ if (dateValueList == null || dateValueList.size() == 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ int L = 0;
|
|
|
+ int R = dateValueList.size() - 1;
|
|
|
+ int ans = -1;
|
|
|
+ while (L <= R) {
|
|
|
+ int mid = (L + R) / 2;
|
|
|
+ if (dateValueList.get(mid) != null && dateValueList.get(mid).getDate().compareTo(date) <= 0) {
|
|
|
+ ans = mid;
|
|
|
+ L = mid + 1;
|
|
|
+ } else {
|
|
|
+ R = mid - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ans;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param dateValueList 从小到大的净值序列
|
|
|
+ * @param date 日期
|
|
|
+ * @return 大于等于 date 的 日期最小的 日期
|
|
|
+ */
|
|
|
+ public static Integer getMostRightThan(List<DateValue> dateValueList, String date) {
|
|
|
+ if (dateValueList == null || Objects.requireNonNull(dateValueList).size() == 0) {
|
|
|
+ return -1;
|
|
|
+ } else if (dateValueList.get(dateValueList.size() - 1).getDate().compareTo(date) < 0) {
|
|
|
+ return dateValueList.size() - 1;
|
|
|
+ }
|
|
|
+ int low = 0;
|
|
|
+ int high = dateValueList.size() - 1;
|
|
|
+ while (low < high) {
|
|
|
+ //防止溢出
|
|
|
+ int mid = low + (high - low) / 2;
|
|
|
+ if (dateValueList.get(mid).getDate().compareTo(date) < 0) {
|
|
|
+ low = mid + 1;
|
|
|
+ } else {
|
|
|
+ high = mid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return low;
|
|
|
+ }
|
|
|
+
|
|
|
+ @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) {
|
|
|
+
|
|
|
+ //全部的标的集合
|
|
|
+ Map<String, Boolean> secIfExtractMap = new HashMap<>();
|
|
|
+ List<String> secIds = new ArrayList<>();
|
|
|
+ secIds.addAll(mainSecIdList);
|
|
|
+ secIds.addAll(benchmarkIdList);
|
|
|
+ secIds.addAll(indexList);
|
|
|
+// if (extractNavServiceReq != null && extractNavServiceReq.isIfExtract()) {
|
|
|
+// for (String mainSecId : mainSecIdList) {
|
|
|
+// secIfExtractMap.put(mainSecId, true);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ List<String> dbSecIds = new ArrayList<>();
|
|
|
+ Map<String, String> secKeyMap = new HashMap<>();
|
|
|
+
|
|
|
+ Map<String, List<DateValue>> allSecNavListMap = new HashMap<>();
|
|
|
+
|
|
|
+ //取DB
|
|
|
+ Map<String, List<DateValue>> secNavListMapDbData = getSecIdDateValueNavListMapByDb(dbSecIds, startDate, endDate, curveTypeId, strategyId, visibility, navType, secFrequencyMap, secIfExtractMap);
|
|
|
+ allSecNavListMap.putAll(secNavListMapDbData);
|
|
|
+
|
|
|
+ //将取DB的标的的净值存进redis
|
|
|
+// cacheNavDataToRedis(dbSecIds, secKeyMap, curveTypeId, strategyId, visibility, navType, secFrequencyMap);
|
|
|
+
|
|
|
+ return allSecNavListMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ @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) {
|
|
|
+
|
|
|
+ Map<String, List<DateValue>> allNavMap = new HashMap<>();
|
|
|
+
|
|
|
+ //对secId进行分类
|
|
|
+ Map<String, List<String>> secIdTypeMap = secTypeService.getSecIdTypeMap(allSecIdList);
|
|
|
+
|
|
|
+ //1.市场私募净值
|
|
|
+ List<String> marketPrivateFundIdList = secIdTypeMap.get(SecType.PRIVATELY_OFFERED_FUND);
|
|
|
+ if (marketPrivateFundIdList != null && marketPrivateFundIdList.size() > 0) {
|
|
|
+ Map<String, List<DateValue>> privatelyOfferedFundNavMap = getPrivatelyOfferedFundNavMap(marketPrivateFundIdList, startDate, endDate, navType, visibility, secIfExtractMap);
|
|
|
+ allNavMap.putAll(privatelyOfferedFundNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ //2.市场公募净值
|
|
|
+ List<String> marketPublicFundIdList = secIdTypeMap.get(SecType.PUBLICLY_OFFERED_FUNDS);
|
|
|
+ if (marketPublicFundIdList != null && marketPublicFundIdList.size() > 0) {
|
|
|
+ Map<String, List<DateValue>> marketPubliclyOfferedFundNavMap = getPubliclyOfferedFundNavMap(marketPublicFundIdList, startDate, endDate, navType, visibility);
|
|
|
+ allNavMap.putAll(marketPubliclyOfferedFundNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ //5.市场指数行情
|
|
|
+ List<String> marketIndexIdList = secIdTypeMap.get(SecType.INDEX_FUND);
|
|
|
+ if (marketIndexIdList != null && marketIndexIdList.size() > 0) {
|
|
|
+ Map<String, List<DateValue>> marketIndexNavMap = getMarketIndexNavMap(marketIndexIdList, startDate, endDate, navType);
|
|
|
+ allNavMap.putAll(marketIndexNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ //7.融智指数行情
|
|
|
+ List<String> rongzhiIndexIdList = secIdTypeMap.get(SecType.RONGZHI_INDEX);
|
|
|
+ if (rongzhiIndexIdList != null && rongzhiIndexIdList.size() > 0) {
|
|
|
+ Map<String, List<DateValue>> rongzhiIndexIdNavMap = getRongzhiIndexNavMap(rongzhiIndexIdList, startDate, endDate, navType);
|
|
|
+ allNavMap.putAll(rongzhiIndexIdNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ //13.无风险收益
|
|
|
+ List<String> riskOfFree = secIdTypeMap.get(SecType.RISK_OF_FREE);
|
|
|
+ if (riskOfFree != null && riskOfFree.size() > 0) {
|
|
|
+ Map<String, List<DateValue>> riskOfFreeNavMap = getRiskOfFreeNavMap(riskOfFree, startDate, endDate, navType);
|
|
|
+ allNavMap.putAll(riskOfFreeNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ return allNavMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, List<DateValue>> getRiskOfFreeNavMap(List<String> riskOfFree, String startDate, String endDate, NavType navType) {
|
|
|
+ Map<String, List<NavDto>> riskOfFreeNavMap = riskOfFreeNavDao.getNav(riskOfFree, startDate, endDate, false);
|
|
|
+ return SecNavDtoListMapToSecDateValueListMap(navType, riskOfFreeNavMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, List<DateValue>> getRongzhiIndexNavMap(List<String> rongzhiIndexIdList, String startDate, String endDate, NavType navType) {
|
|
|
+ Map<String, List<NavDto>> rongzhiIndexIdNavDtoListMap = rongzhiIndexNavDao.getNav(rongzhiIndexIdList, startDate, endDate, false);
|
|
|
+ return SecNavDtoListMapToSecDateValueListMap(navType, rongzhiIndexIdNavDtoListMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, List<DateValue>> getMarketIndexNavMap(List<String> marketIndexIdList, String startDate, String endDate, NavType navType) {
|
|
|
+ Map<String, List<NavDto>> indexIdNavDtoListMap = marketIndexNavDao.getNav(marketIndexIdList, startDate, endDate, false);
|
|
|
+ return SecNavDtoListMapToSecDateValueListMap(navType, indexIdNavDtoListMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, List<DateValue>> getPubliclyOfferedFundNavMap(List<String> fundIdList, String startDate, String endDate, NavType navType, Visibility visibility) {
|
|
|
+ Map<String, List<NavDto>> fundIdNavDtoListMap = publiclyOfferedFundNavDao.getNav(fundIdList, startDate, endDate, navType, false);
|
|
|
+ return SecNavDtoListMapToSecDateValueListMap(navType, fundIdNavDtoListMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Map<String, List<DateValue>> getPrivatelyOfferedFundNavMap(List<String> fundIdList, String startDate, String endDate, NavType navType, Visibility visibility
|
|
|
+ , Map<String, Boolean> secIfExtractMap) {
|
|
|
+
|
|
|
+ //不取费后净值的ID
|
|
|
+ List<String> notAccfilterFundIdList = new ArrayList<>();
|
|
|
+ //取费后净值的ID
|
|
|
+ List<String> accfilterFundIdList = new ArrayList<>();
|
|
|
+ Map<String, List<NavDto>> allFundIdNavDtoListMap = new HashMap<>();
|
|
|
+
|
|
|
+// for (String fundId : fundIdList) {
|
|
|
+// Boolean secIfExtract = secIfExtractMap.get(fundId);
|
|
|
+// if (secIfExtract != null && secIfExtract) {
|
|
|
+// accfilterFundIdList.add(fundId);
|
|
|
+// } else {
|
|
|
+// notAccfilterFundIdList.add(fundId);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ //取非费后净值
|
|
|
+ if (notAccfilterFundIdList.size() > 0) {
|
|
|
+ Map<String, List<NavDto>> fundIdNavDtoListMap = privatelyOfferedFundNavDao.getNav(notAccfilterFundIdList, startDate, endDate, navType, false);
|
|
|
+ allFundIdNavDtoListMap.putAll(fundIdNavDtoListMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ return SecNavDtoListMapToSecDateValueListMap(navType, allFundIdNavDtoListMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Map<String, List<DateValue>> SecNavDtoListMapToSecDateValueListMap(NavType navType, Map<String, List<NavDto>> secIdNavDtoListMap) {
|
|
|
+ Map<String, List<DateValue>> secIdDateValueListMap = new HashMap<>();
|
|
|
+ for (Map.Entry<String, List<NavDto>> fundIdNavDtoListEntry : secIdNavDtoListMap.entrySet()) {
|
|
|
+ List<NavDto> navDtoList = fundIdNavDtoListEntry.getValue();
|
|
|
+ String fundId = fundIdNavDtoListEntry.getKey();
|
|
|
+ List<DateValue> dateValueList = DateValueUtil.convertNavList(navDtoList, navType);
|
|
|
+ secIdDateValueListMap.put(fundId, dateValueList);
|
|
|
+ }
|
|
|
+ return secIdDateValueListMap;
|
|
|
+ }
|
|
|
+
|
|
|
+// private void cacheNavDataToRedis(List<String> dbSecIds, Map<String, String> secKeyMap, Integer curveType, Integer strategy, Visibility visibility, NavType navType, Map<String, Frequency> secFrequencyMap) {
|
|
|
+//
|
|
|
+//// if (extractNavServiceReq != null && extractNavServiceReq.isIfExtract()) {
|
|
|
+//// return;
|
|
|
+//// }
|
|
|
+//
|
|
|
+// List<String> needCacheSecIdList = new ArrayList<>();
|
|
|
+// for (String dbSecId : dbSecIds) {
|
|
|
+// String key = secKeyMap.get(dbSecId);
|
|
|
+// if (StringUtil.isNotEmpty(key)) {
|
|
|
+// needCacheSecIdList.add(dbSecId);
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// if (dbSecIds.size() != 0) {
|
|
|
+// taskExecutor.execute(()-> {
|
|
|
+// // 确保取出全量数据DB数据
|
|
|
+// Map<String, List<DateValue>> secNavListMapDbData = getSecIdDateValueNavListMapByDb(needCacheSecIdList, null, null, curveType, strategy, visibility, navType, secFrequencyMap, extractNavServiceReq, new HashMap<>());
|
|
|
+// for (String needCacheSecId : needCacheSecIdList) {
|
|
|
+//
|
|
|
+// String secType = secTypeService.getFundType(needCacheSecId);
|
|
|
+//
|
|
|
+// String redisKey = secKeyMap.get(needCacheSecId);
|
|
|
+// List<DateValue> dateValueList = secNavListMapDbData.get(needCacheSecId);
|
|
|
+// Map<String, Double> dateNavMap = new HashMap<>();
|
|
|
+// for (DateValue dateValue : dateValueList) {
|
|
|
+// dateNavMap.put(dateValue.getDate(), dateValue.getValue());
|
|
|
+// }
|
|
|
+//
|
|
|
+// RLock lock = redissonClient.getLock(RedisUtils.getHashLockKey(needCacheSecId, redisKey));
|
|
|
+// try{
|
|
|
+// if (lock.tryLock(1,10, TimeUnit.SECONDS)) {
|
|
|
+// String dateNavMapJsonString = JSON.toJSONString(dateNavMap);
|
|
|
+// RMap<String, String> secMap = redissonClient.getMap(needCacheSecId);
|
|
|
+// secMap.put(redisKey, dateNavMapJsonString);
|
|
|
+// if (SecType.PRIVATE_FUND.equals(secType)) {
|
|
|
+// secMap.expire(15,TimeUnit.SECONDS);
|
|
|
+// }
|
|
|
+// } else {
|
|
|
+// log.error("redis write nav error, get lock failed.key: {}", redisKey);
|
|
|
+// }
|
|
|
+// }catch(Exception e){
|
|
|
+// log.error("redis write nav error: {}", e.getMessage(), e);
|
|
|
+// }finally{
|
|
|
+// lock.unlock();
|
|
|
+// }
|
|
|
+// }
|
|
|
+// });
|
|
|
+// }
|
|
|
+// }
|
|
|
+}
|