BaseInfoServiceImpl.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package com.smppw.analysis.domain.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.collection.ListUtil;
  4. import cn.hutool.core.map.MapUtil;
  5. import cn.hutool.core.util.NumberUtil;
  6. import cn.hutool.core.util.StrUtil;
  7. import com.smppw.analysis.domain.dao.*;
  8. import com.smppw.analysis.domain.dao.rank.RankDao;
  9. import com.smppw.analysis.domain.dao.rank.RankFactory;
  10. import com.smppw.analysis.domain.dataobject.FundArchivesInfoDO;
  11. import com.smppw.analysis.domain.dataobject.FundSimilarDo;
  12. import com.smppw.analysis.domain.dataobject.ManualFundNoticeInfoDO;
  13. import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
  14. import com.smppw.analysis.domain.dataobject.*;
  15. import com.smppw.analysis.domain.dto.info.FundSimilarParams;
  16. import com.smppw.analysis.domain.event.SaveCacheEvent;
  17. import com.smppw.analysis.domain.gateway.CacheFactory;
  18. import com.smppw.analysis.domain.gateway.CacheGateway;
  19. import com.smppw.analysis.domain.mapper.core.CommonIndexMapper;
  20. import com.smppw.analysis.domain.service.BaseInfoService;
  21. import com.smppw.analysis.infrastructure.config.AnalysisProperty;
  22. import com.smppw.analysis.infrastructure.consts.RedisConst;
  23. import com.smppw.common.cache.CaffeineLocalCache;
  24. import com.smppw.common.pojo.IStrategy;
  25. import com.smppw.common.pojo.ValueLabelVO;
  26. import com.smppw.common.pojo.enums.Frequency;
  27. import com.smppw.common.pojo.enums.Indicator;
  28. import com.smppw.common.pojo.enums.strategy.Strategy;
  29. import com.smppw.constants.SecType;
  30. import com.smppw.utils.StrategyHandleUtils;
  31. import org.slf4j.Logger;
  32. import org.slf4j.LoggerFactory;
  33. import org.springframework.beans.BeansException;
  34. import org.springframework.beans.factory.annotation.Autowired;
  35. import org.springframework.context.ApplicationContext;
  36. import org.springframework.context.ApplicationContextAware;
  37. import org.springframework.lang.NonNull;
  38. import org.springframework.stereotype.Service;
  39. import java.util.ArrayList;
  40. import java.util.HashMap;
  41. import java.util.List;
  42. import java.util.Map;
  43. import java.util.concurrent.TimeUnit;
  44. import java.util.function.Function;
  45. import java.util.stream.Collectors;
  46. @Service
  47. public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextAware {
  48. public static final String HF = "HF";
  49. public static final String MF = "MF";
  50. public static final String CF = "CF";
  51. public static final String FA = "FA";
  52. public static final String CI = "CI";
  53. public static final String CO = "CO";
  54. public static final String PL = "PL";
  55. public static final String PO = "PO";
  56. public static final String IN = "IN";
  57. public static final String AP = "AP";
  58. private static final Map<String, Boolean> INDEX_EXIST = MapUtil.newConcurrentHashMap();
  59. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  60. private final RankDao rankDao;
  61. private final CacheGateway<Object> cacheGateway;
  62. private final IndexesProfileDao indexesProfileDao;
  63. private final RongzhiIndexNavDao rongzhiIndexNavDao;
  64. private final FundInformationDao fundInformationDao;
  65. private final FundAnnounceDao fundAnnounceDao;
  66. private final FundArchivesDao fundArchivesDao;
  67. private ApplicationContext applicationContext;
  68. @Autowired
  69. private CommonIndexMapper commonIndexMapper;
  70. public BaseInfoServiceImpl(AnalysisProperty property, CacheFactory factory, RankFactory rankFactory,
  71. IndexesProfileDao indexesProfileDao, RongzhiIndexNavDao rongzhiIndexNavDao,
  72. FundInformationDao fundInformationDao, FundAnnounceDao fundAnnounceDao, FundArchivesDao fundArchivesDao) {
  73. this.rankDao = rankFactory.getInstance(property.getDataSource());
  74. this.cacheGateway = factory.getCacheGateway(property.getCacheType());
  75. this.indexesProfileDao = indexesProfileDao;
  76. this.rongzhiIndexNavDao = rongzhiIndexNavDao;
  77. this.fundInformationDao = fundInformationDao;
  78. this.fundAnnounceDao = fundAnnounceDao;
  79. this.fundArchivesDao = fundArchivesDao;
  80. }
  81. @Override
  82. public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
  83. this.applicationContext = applicationContext;
  84. }
  85. @Override
  86. public List<ValueLabelVO> getCommonIndexList() {
  87. List<CommonIndexDO> dataList = this.commonIndexMapper.selectList();
  88. return dataList.stream().map(e -> new ValueLabelVO(e.getIndexId(), e.getIndexName())).collect(Collectors.toList());
  89. }
  90. @Override
  91. public String getLatestRankRat() {
  92. return this.rankDao.getRankDate();
  93. }
  94. @Override
  95. public String getLatestRankRat(String refId) {
  96. return this.rankDao.getRankDate(refId);
  97. }
  98. @Override
  99. public String getSecType(String secId) {
  100. if (secId == null) {
  101. return null;
  102. }
  103. if (secId.startsWith(HF)) {
  104. return SecType.PRIVATELY_OFFERED_FUND;
  105. } else if (secId.startsWith(MF)) {
  106. return SecType.PUBLICLY_OFFERED_FUNDS;
  107. } else if (secId.startsWith(CF)) {
  108. return SecType.PRIVATE_FUND;
  109. } else if (secId.startsWith(FA)) {
  110. return SecType.FACTOR;
  111. } else if (secId.startsWith(CI)) {
  112. return SecType.UDF_INDEX;
  113. } else if (secId.startsWith(CO)) {
  114. return SecType.COMPANY;
  115. } else if (secId.startsWith(PL)) {
  116. return SecType.MANAGER;
  117. } else if (secId.startsWith(PO)) {
  118. return SecType.COMBINATION;
  119. } else if (StrUtil.isNumeric(secId)) {
  120. if (Strategy.isStrategy(secId)) {
  121. return SecType.STRATEGY;
  122. }
  123. } else if (secId.startsWith(IN)) {
  124. List<String> thirdIndexes = CaffeineLocalCache.getThirdIndexes();
  125. if (thirdIndexes != null && thirdIndexes.contains(secId)) {
  126. return SecType.THIRD_INDEX_FUND;
  127. }
  128. List<String> riskOfFreeIdList = CaffeineLocalCache.getRiskOfFreeId();
  129. if (riskOfFreeIdList != null && riskOfFreeIdList.contains(secId)) {
  130. return SecType.RISK_OF_FREE;
  131. }
  132. Boolean isExist = INDEX_EXIST.get(secId);
  133. if (isExist == null) {
  134. isExist = rongzhiIndexNavDao.isExist(secId);
  135. INDEX_EXIST.put(secId, isExist);
  136. }
  137. if (isExist) {
  138. return SecType.INDEX_FUND;
  139. } else {
  140. return SecType.RONGZHI_INDEX;
  141. }
  142. } else if (secId.startsWith(AP)) {
  143. return SecType.ADVISORY_POOL_CURVE;
  144. }
  145. return null;
  146. }
  147. @Override
  148. public Map<String, List<String>> getTypeSecMap(List<String> secIdList) {
  149. Map<String, List<String>> secIdTypeMap = new HashMap<>(10);
  150. for (String secId : secIdList) {
  151. String secIdType = getSecType(secId);
  152. if (secIdTypeMap.containsKey(secIdType)) {
  153. List<String> list = secIdTypeMap.get(secIdType);
  154. list.add(secId);
  155. } else {
  156. List<String> list = new ArrayList<>();
  157. list.add(secId);
  158. secIdTypeMap.put(secIdType, list);
  159. }
  160. }
  161. return secIdTypeMap;
  162. }
  163. @Override
  164. public Map<String, String> querySecsType(List<String> secIdList) {
  165. if (CollUtil.isEmpty(secIdList)) {
  166. return MapUtil.newHashMap(8);
  167. }
  168. return secIdList.stream().collect(Collectors.toMap(e -> e, this::getSecType));
  169. }
  170. @Override
  171. public Frequency getNavFrequency(String secId) {
  172. Frequency frequency;
  173. String fundType = this.getSecType(secId);
  174. if (SecType.MANAGER.equals(fundType) || SecType.COMPANY.equals(fundType)) {
  175. frequency = Frequency.Monthly;
  176. } else if (SecType.PRIVATELY_OFFERED_FUND.equals(fundType) ||
  177. SecType.PUBLICLY_OFFERED_FUNDS.equals(fundType) ||
  178. SecType.INDEX_FUND.equals(fundType) ||
  179. SecType.RONGZHI_INDEX.equals(fundType)) {
  180. String freq = this.fundInformationDao.getNavFrequencyByFundId(secId);
  181. if ("天".equals(freq)) {
  182. frequency = Frequency.Daily;
  183. } else if ("周".equals(freq)) {
  184. frequency = Frequency.Weekly;
  185. } else {
  186. frequency = Frequency.Monthly;
  187. }
  188. } else {
  189. frequency = Frequency.Daily;
  190. }
  191. return frequency;
  192. }
  193. @Override
  194. public Map<String, String> querySecName(List<String> allSecIdList) {
  195. if (CollUtil.isEmpty(allSecIdList)) {
  196. return MapUtil.empty();
  197. }
  198. int size = allSecIdList.size();
  199. String key = RedisConst.INFO_NAME;
  200. Map<String, Object> hget = this.cacheGateway.hget(key);
  201. if (MapUtil.isEmpty(hget)) {
  202. hget = MapUtil.empty();
  203. }
  204. Map<Boolean, List<String>> redisSecMap = allSecIdList.stream().collect(Collectors.groupingBy(hget::containsKey));
  205. List<String> redisSecIds = redisSecMap.getOrDefault(Boolean.TRUE, ListUtil.empty());
  206. List<String> noRedisSecIds = redisSecMap.getOrDefault(Boolean.FALSE, ListUtil.empty());
  207. Map<String, Object> secNameMap = MapUtil.newHashMap(size, false);
  208. if (CollUtil.isNotEmpty(noRedisSecIds)) {
  209. Map<String, List<String>> typeSecMap = this.getTypeSecMap(noRedisSecIds);
  210. // 市场基金
  211. List<String> marketFundIds = ListUtil.of(SecType.PRIVATELY_OFFERED_FUND, SecType.PUBLICLY_OFFERED_FUNDS);
  212. this.loadNameMap(secNameMap, typeSecMap, marketFundIds, this.fundInformationDao::getMarketFundIdNameMap);
  213. // 市场指数
  214. List<String> marketIndexIds = ListUtil.of(SecType.INDEX_FUND, SecType.RONGZHI_INDEX, SecType.THIRD_INDEX_FUND);
  215. this.loadNameMap(secNameMap, typeSecMap, marketIndexIds, this.indexesProfileDao::getFundIdNameMap);
  216. // 推送事件,存缓存
  217. SaveCacheEvent<Map<String, Object>> event = new SaveCacheEvent<>(key, secNameMap, t -> {
  218. this.cacheGateway.hset(key, t);
  219. return this.cacheGateway.expire(key, 1, TimeUnit.DAYS);
  220. });
  221. this.applicationContext.publishEvent(event);
  222. }
  223. // 解决乱序问题
  224. Map<String, String> result = MapUtil.newHashMap(size, true);
  225. for (String secId : allSecIdList) {
  226. String name = redisSecIds.contains(secId) ? MapUtil.getStr(hget, secId) : MapUtil.getStr(secNameMap, secId);
  227. result.put(secId, name);
  228. }
  229. return result;
  230. }
  231. @Override
  232. public List<MonetaryFundProfitDO> queryMonetaryFund(String fundId) {
  233. return this.fundInformationDao.queryMonetaryFund(fundId);
  234. }
  235. @Override
  236. public List<Map<String, Object>> getFundRank(String rankDate, String fundId, List<String> indexIds, Indicator indicator) {
  237. return this.fundInformationDao.getFundRank(rankDate, fundId, indexIds, indicator);
  238. }
  239. @Override
  240. public List<FundSimilarDo> getFundSimilarList(FundSimilarParams params) {
  241. if (StrUtil.isBlank(params.getThreshold()) || !NumberUtil.isNumber(params.getThreshold())) {
  242. logger.warn(String.format("相关性阈值 %s 设置错误,提供默认值:%s", params.getThreshold(), FundSimilarParams.DEFAULT_THRESHOLD));
  243. params.setThreshold(FundSimilarParams.DEFAULT_THRESHOLD);
  244. }
  245. IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
  246. String rankDate = this.getLatestRankRat();
  247. List<FundSimilarDo> tempList = ListUtil.list(true);
  248. if (params.getCalcType() == 2) {
  249. Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId()).put("startDate", params.getStartDate())
  250. .put("tableName", "rz_hfdb_core.nav").put("trustId", params.getTrustId()).put("rankDate", rankDate).build();
  251. tempList.addAll(this.fundInformationDao.getSameCompanyFundIds(req));
  252. } else {
  253. Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId()).put("rankNum", 50)
  254. .put("tableName", "rz_hfdb_core.fund_indicator_ranking").put("fundId", params.getRefId()).put("rankDate", rankDate).build();
  255. tempList.addAll(this.fundInformationDao.getSameStrategyFundIds(req));
  256. }
  257. List<FundSimilarDo> dataList = ListUtil.list(true);
  258. // 过滤当前基金
  259. dataList.addAll(tempList.stream().filter(e -> !params.getRefId().equals(e.getFundId())).collect(Collectors.toList()));
  260. return dataList;
  261. }
  262. @Override
  263. public List<ManualFundNoticeInfoDO> queryFundAnnounce(String fundId, List<String> typeList, String title) {
  264. return fundAnnounceDao.queryFundAnnounce(fundId, typeList, title);
  265. }
  266. @Override
  267. public FundArchivesInfoDO queryFundArchives(String fundId) {
  268. return fundArchivesDao.getFundArchives(fundId);
  269. }
  270. @Override
  271. public FundFeeDo getFundFee(String fundId) {
  272. return fundInformationDao.getFundFee(fundId);
  273. }
  274. /**
  275. * 把指定类型的标的的名称映射查询出来
  276. *
  277. * @param secNameMap 保存的map
  278. * @param typeSecMap 指定类型对应的标的
  279. * @param types 指定类型列表
  280. * @param function 查询操作封装
  281. */
  282. private void loadNameMap(Map<String, Object> secNameMap, Map<String, List<String>> typeSecMap,
  283. List<String> types, Function<List<String>, Map<String, String>> function) {
  284. List<String> refIds = ListUtil.list(true);
  285. for (String type : types) {
  286. CollUtil.addAllIfNotContains(refIds, typeSecMap.getOrDefault(type, ListUtil.empty()));
  287. }
  288. if (CollUtil.isNotEmpty(refIds)) {
  289. secNameMap.putAll(function.apply(refIds));
  290. }
  291. }
  292. }