BaseInfoServiceImpl.java 17 KB

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