123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package com.smppw.analysis.domain.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.collection.ListUtil;
- import cn.hutool.core.map.MapUtil;
- import cn.hutool.core.util.NumberUtil;
- import cn.hutool.core.util.StrUtil;
- import com.smppw.analysis.domain.dao.FundInformationDao;
- import com.smppw.analysis.domain.dao.IndexesProfileDao;
- import com.smppw.analysis.domain.dao.RongzhiIndexNavDao;
- import com.smppw.analysis.domain.dataobject.FundSimilarDo;
- import com.smppw.analysis.domain.dataobject.MonetaryFundProfitDO;
- import com.smppw.analysis.domain.dto.info.FundSimilarParams;
- import com.smppw.analysis.domain.event.SaveCacheEvent;
- import com.smppw.analysis.domain.gateway.CacheFactory;
- import com.smppw.analysis.domain.gateway.CacheGateway;
- import com.smppw.analysis.domain.service.BaseInfoService;
- import com.smppw.analysis.infrastructure.config.AnalysisProperty;
- import com.smppw.analysis.infrastructure.consts.RedisConst;
- import com.smppw.common.cache.CaffeineLocalCache;
- import com.smppw.common.pojo.IStrategy;
- import com.smppw.common.pojo.enums.Frequency;
- import com.smppw.common.pojo.enums.Indicator;
- import com.smppw.common.pojo.enums.strategy.Strategy;
- import com.smppw.constants.SecType;
- import com.smppw.utils.StrategyHandleUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeansException;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.ApplicationContextAware;
- import org.springframework.lang.NonNull;
- import org.springframework.stereotype.Service;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.TimeUnit;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- @Service
- public class BaseInfoServiceImpl implements BaseInfoService, ApplicationContextAware {
- public static final String HF = "HF";
- public static final String MF = "MF";
- public static final String CF = "CF";
- public static final String FA = "FA";
- public static final String CI = "CI";
- public static final String CO = "CO";
- public static final String PL = "PL";
- public static final String PO = "PO";
- public static final String IN = "IN";
- public static final String AP = "AP";
- private static final Map<String, Boolean> INDEX_EXIST = MapUtil.newConcurrentHashMap();
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
- private final CacheGateway<Object> cacheGateway;
- private final IndexesProfileDao indexesProfileDao;
- private final RongzhiIndexNavDao rongzhiIndexNavDao;
- private final FundInformationDao fundInformationDao;
- private ApplicationContext applicationContext;
- public BaseInfoServiceImpl(AnalysisProperty property, CacheFactory factory,
- IndexesProfileDao indexesProfileDao, RongzhiIndexNavDao rongzhiIndexNavDao, FundInformationDao fundInformationDao) {
- this.cacheGateway = factory.getCacheGateway(property.getCacheType());
- this.indexesProfileDao = indexesProfileDao;
- this.rongzhiIndexNavDao = rongzhiIndexNavDao;
- this.fundInformationDao = fundInformationDao;
- }
- @Override
- public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
- @Override
- public String getLatestRankRat() {
- // todo 排名期
- return "2023-07";
- }
- @Override
- public String getSecType(String secId) {
- if (secId == null) {
- return null;
- }
- if (secId.startsWith(HF)) {
- return SecType.PRIVATELY_OFFERED_FUND;
- } else if (secId.startsWith(MF)) {
- return SecType.PUBLICLY_OFFERED_FUNDS;
- } else if (secId.startsWith(CF)) {
- return SecType.PRIVATE_FUND;
- } else if (secId.startsWith(FA)) {
- return SecType.FACTOR;
- } else if (secId.startsWith(CI)) {
- return SecType.UDF_INDEX;
- } else if (secId.startsWith(CO)) {
- return SecType.COMPANY;
- } else if (secId.startsWith(PL)) {
- return SecType.MANAGER;
- } else if (secId.startsWith(PO)) {
- return SecType.COMBINATION;
- } else if (StrUtil.isNumeric(secId)) {
- if (Strategy.isStrategy(secId)) {
- return SecType.STRATEGY;
- }
- } else if (secId.startsWith(IN)) {
- List<String> thirdIndexes = CaffeineLocalCache.getThirdIndexes();
- if (thirdIndexes != null && thirdIndexes.contains(secId)) {
- return SecType.THIRD_INDEX_FUND;
- }
- List<String> riskOfFreeIdList = CaffeineLocalCache.getRiskOfFreeId();
- if (riskOfFreeIdList != null && riskOfFreeIdList.contains(secId)) {
- return SecType.RISK_OF_FREE;
- }
- Boolean isExist = INDEX_EXIST.get(secId);
- if (isExist == null) {
- isExist = rongzhiIndexNavDao.isExist(secId);
- INDEX_EXIST.put(secId, isExist);
- }
- if (isExist) {
- return SecType.INDEX_FUND;
- } else {
- return SecType.RONGZHI_INDEX;
- }
- } else if (secId.startsWith(AP)) {
- return SecType.ADVISORY_POOL_CURVE;
- }
- return null;
- }
- @Override
- public Map<String, List<String>> getTypeSecMap(List<String> secIdList) {
- Map<String, List<String>> secIdTypeMap = new HashMap<>(10);
- for (String secId : secIdList) {
- String secIdType = getSecType(secId);
- if (secIdTypeMap.containsKey(secIdType)) {
- List<String> list = secIdTypeMap.get(secIdType);
- list.add(secId);
- } else {
- List<String> list = new ArrayList<>();
- list.add(secId);
- secIdTypeMap.put(secIdType, list);
- }
- }
- return secIdTypeMap;
- }
- @Override
- public Map<String, String> querySecsType(List<String> secIdList) {
- if (CollUtil.isEmpty(secIdList)) {
- return MapUtil.newHashMap(8);
- }
- return secIdList.stream().collect(Collectors.toMap(e -> e, this::getSecType));
- }
- @Override
- public Frequency getNavFrequency(String secId) {
- Frequency frequency;
- String fundType = this.getSecType(secId);
- if (SecType.MANAGER.equals(fundType) || SecType.COMPANY.equals(fundType)) {
- frequency = Frequency.Monthly;
- } else if (SecType.PRIVATELY_OFFERED_FUND.equals(fundType) ||
- SecType.PUBLICLY_OFFERED_FUNDS.equals(fundType) ||
- SecType.INDEX_FUND.equals(fundType) ||
- SecType.RONGZHI_INDEX.equals(fundType)) {
- String freq = this.fundInformationDao.getNavFrequencyByFundId(secId);
- if ("天".equals(freq)) {
- frequency = Frequency.Daily;
- } else if ("周".equals(freq)) {
- frequency = Frequency.Weekly;
- } else {
- frequency = Frequency.Monthly;
- }
- } else {
- frequency = Frequency.Daily;
- }
- return frequency;
- }
- @Override
- public Map<String, String> querySecName(List<String> allSecIdList) {
- if (CollUtil.isEmpty(allSecIdList)) {
- return MapUtil.empty();
- }
- int size = allSecIdList.size();
- String key = RedisConst.INFO_NAME;
- Map<String, Object> hget = this.cacheGateway.hget(key);
- if (MapUtil.isEmpty(hget)) {
- hget = MapUtil.empty();
- }
- Map<Boolean, List<String>> redisSecMap = allSecIdList.stream().collect(Collectors.groupingBy(hget::containsKey));
- List<String> redisSecIds = redisSecMap.getOrDefault(Boolean.TRUE, ListUtil.empty());
- List<String> noRedisSecIds = redisSecMap.getOrDefault(Boolean.FALSE, ListUtil.empty());
- Map<String, Object> secNameMap = MapUtil.newHashMap(size, false);
- if (CollUtil.isNotEmpty(noRedisSecIds)) {
- Map<String, List<String>> typeSecMap = this.getTypeSecMap(noRedisSecIds);
- // 市场基金
- List<String> marketFundIds = ListUtil.of(SecType.PRIVATELY_OFFERED_FUND, SecType.PUBLICLY_OFFERED_FUNDS);
- this.loadNameMap(secNameMap, typeSecMap, marketFundIds, this.fundInformationDao::getMarketFundIdNameMap);
- // 市场指数
- List<String> marketIndexIds = ListUtil.of(SecType.INDEX_FUND, SecType.RONGZHI_INDEX, SecType.THIRD_INDEX_FUND);
- this.loadNameMap(secNameMap, typeSecMap, marketIndexIds, this.indexesProfileDao::getFundIdNameMap);
- // 推送事件,存缓存
- SaveCacheEvent<Map<String, Object>> event = new SaveCacheEvent<>(key, secNameMap, t -> {
- this.cacheGateway.hset(key, t);
- return this.cacheGateway.expire(key, 1, TimeUnit.DAYS);
- });
- this.applicationContext.publishEvent(event);
- }
- // 解决乱序问题
- Map<String, String> result = MapUtil.newHashMap(size, true);
- for (String secId : allSecIdList) {
- String name = redisSecIds.contains(secId) ? MapUtil.getStr(hget, secId) : MapUtil.getStr(secNameMap, secId);
- result.put(secId, name);
- }
- return result;
- }
- @Override
- public List<MonetaryFundProfitDO> queryMonetaryFund(String fundId) {
- return this.fundInformationDao.queryMonetaryFund(fundId);
- }
- @Override
- public List<Map<String, Object>> getFundRank(String rankDate, String fundId, List<String> indexIds, Indicator indicator) {
- return this.fundInformationDao.getFundRank(rankDate, fundId, indexIds, indicator);
- }
- @Override
- public List<FundSimilarDo> getFundSimilarList(FundSimilarParams params) {
- if (StrUtil.isBlank(params.getThreshold()) || !NumberUtil.isNumber(params.getThreshold())) {
- logger.warn(String.format("相关性阈值 %s 设置错误,提供默认值:%s", params.getThreshold(), FundSimilarParams.DEFAULT_THRESHOLD));
- params.setThreshold(FundSimilarParams.DEFAULT_THRESHOLD);
- }
- IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
- String rankDate = this.getLatestRankRat();
- List<FundSimilarDo> tempList = ListUtil.list(true);
- if (params.getCalcType() == 2) {
- Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId())
- .put("tableName", "rz_hfdb_core.nav").put("trustId", params.getTrustId()).put("rankDate", rankDate).build();
- tempList.addAll(this.fundInformationDao.getSameCompanyFundIds(req));
- } else {
- Map<String, Object> req = MapUtil.<String, Object>builder().put("strategy", strategy.getStrategyId()).put("rankNum", 50)
- .put("tableName", "rz_hfdb_core.fund_indicator_ranking").put("fundId", params.getRefId()).put("rankDate", rankDate).build();
- tempList.addAll(this.fundInformationDao.getSameStrategyFundIds(req));
- }
- List<FundSimilarDo> dataList = ListUtil.list(true);
- // 过滤当前基金
- dataList.addAll(tempList.stream().filter(e -> !params.getRefId().equals(e.getFundId())).collect(Collectors.toList()));
- return dataList;
- }
- /**
- * 把指定类型的标的的名称映射查询出来
- *
- * @param secNameMap 保存的map
- * @param typeSecMap 指定类型对应的标的
- * @param types 指定类型列表
- * @param function 查询操作封装
- */
- private void loadNameMap(Map<String, Object> secNameMap, Map<String, List<String>> typeSecMap,
- List<String> types, Function<List<String>, Map<String, String>> function) {
- List<String> refIds = ListUtil.list(true);
- for (String type : types) {
- CollUtil.addAllIfNotContains(refIds, typeSecMap.getOrDefault(type, ListUtil.empty()));
- }
- if (CollUtil.isNotEmpty(refIds)) {
- secNameMap.putAll(function.apply(refIds));
- }
- }
- }
|