package com.smppw.analysis.application.service.style; 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.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONUtil; import com.smppw.analysis.domain.dataobject.FundStyleStatsDO; import com.smppw.analysis.domain.dto.style.*; import com.smppw.analysis.domain.dto.style.py.PyReq; import com.smppw.analysis.domain.dto.style.py.PyReqBody; import com.smppw.analysis.domain.dto.style.py.PyReqParam; import com.smppw.analysis.domain.dto.style.py.PyResBody; import com.smppw.analysis.domain.service.BaseInfoService; import com.smppw.analysis.domain.service.FundStyleService; import com.smppw.analysis.infrastructure.config.AnalysisProperty; import com.smppw.analysis.infrastructure.consts.*; import com.smppw.analysis.infrastructure.exception.APIException; import com.smppw.common.pojo.IStrategy; import com.smppw.common.pojo.enums.CurveType; import com.smppw.common.pojo.enums.Frequency; import com.smppw.common.pojo.enums.RaiseType; import com.smppw.common.pojo.enums.strategy.Strategy; import com.smppw.constants.Consts; import com.smppw.utils.StrategyHandleUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.nio.charset.Charset; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @Service public class StyleServiceImpl implements StyleService { private static final Logger logger = LoggerFactory.getLogger(StyleServiceImpl.class); private static final Map FREQ_MAPPER = MapUtil.newHashMap(); private static final Map RBSA_MAPPER = MapUtil.newHashMap(); private static final Map> RBSA_INDEX_PROD_MAPPER = MapUtil.newHashMap(); private static final Map CAL_RANGE_MAPPER = MapUtil.newHashMap(); static { FREQ_MAPPER.put(Frequency.Default, "D"); FREQ_MAPPER.put(Frequency.Daily, "D"); FREQ_MAPPER.put(Frequency.Weekly, "W"); FREQ_MAPPER.put(Frequency.Monthly, "M"); FREQ_MAPPER.put(Frequency.Quarterly, "Q"); FREQ_MAPPER.put(Frequency.Annually, "Y"); RBSA_MAPPER.put(ValueGrowthType.CNI6Style, RBSAIndexType.CNI7Style); RBSA_MAPPER.put(ValueGrowthType.CNI2Style, RBSAIndexType.CNI3Style); RBSA_MAPPER.put(ValueGrowthType.CNI6Strategy, RBSAIndexType.CNI7Strategy); RBSA_MAPPER.put(IndustryType.CITIC5, RBSAIndexType.CITIC6); RBSA_MAPPER.put(IndustryType.CSI10, RBSAIndexType.CSI11); RBSA_MAPPER.put(IndustryType.ShenWan, RBSAIndexType.ShenWan); RBSA_MAPPER.put(AssetStyleType.MultiAsset, RBSAIndexType.Large4Assets); RBSA_MAPPER.put(AssetStyleType.RongZhiStrategy, RBSAIndexType.RZ5Strategy); RBSA_MAPPER.put(AssetStyleType.SegmentationAsset, RBSAIndexType.SegmentationAsset); // 成长价值 // 巨潮风格 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI7Style, MapUtil.builder(MapUtil.newHashMap(true)).put("beta1", "大盘成长") .put("beta2", "大盘价值").put("beta3", "中盘成长").put("beta4", "中盘价值") .put("beta5", "小盘成长").put("beta6", "小盘价值").build() ); // 国证风格 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI3Style, MapUtil.builder(MapUtil.newHashMap(true)).put("beta1", "成长").put("beta2", "价值").build()); // 国证策略 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI7Strategy, MapUtil.builder(MapUtil.newHashMap(true)).put("beta1", "大盘低贝") .put("beta2", "大盘高贝").put("beta3", "中盘低贝").put("beta4", "中盘高贝") .put("beta5", "小盘低贝").put("beta6", "小盘高贝").build()); // 行业配置 // 申万一级行业 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.ShenWan, MapUtil.builder(MapUtil.newHashMap(true)) .put("beta1", "美容护理") .put("beta2", "环保") .put("beta3", "石油石化") .put("beta4", "煤炭") .put("beta5", "机械设备") .put("beta6", "汽车") .put("beta7", "非银金融") .put("beta8", "银行") .put("beta9", "通信") .put("beta10", "传媒") .put("beta11", "计算机") .put("beta12", "国防军工") .put("beta13", "电力设备") .put("beta14", "建筑装饰") .put("beta15", "建筑材料") .put("beta16", "综合") .put("beta17", "社会服务") .put("beta18", "商贸零售") .put("beta19", "房地产") .put("beta20", "交通运输") .put("beta21", "公用事业") .put("beta22", "医药生物") .put("beta23", "轻工制造") .put("beta24", "纺织服饰") .put("beta25", "食品饮料") .put("beta26", "家用电器") .put("beta27", "电子") .put("beta28", "有色金属") .put("beta29", "钢铁") .put("beta30", "基础化工") .put("beta31", "农林牧渔") .build()); // 中证行业 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CSI11, MapUtil.builder(MapUtil.newHashMap(true)) .put("beta1", "中证材料") .put("beta2", "中证电信") .put("beta3", "中证工业") .put("beta4", "中证公用") .put("beta5", "中证金融") .put("beta6", "中证可选") .put("beta7", "中证能源") .put("beta8", "中证消费") .put("beta9", "中证信息") .put("beta10", "中证医药") .build()); // 中信行业风格 RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CITIC6, MapUtil.builder(MapUtil.newHashMap(true)) .put("beta1", "金融") .put("beta2", "周期") .put("beta3", "消费") .put("beta4", "成长") .put("beta5", "稳定") .build()); CAL_RANGE_MAPPER.put("3", "ret_3m"); CAL_RANGE_MAPPER.put("6", "ret_6m"); CAL_RANGE_MAPPER.put("12", "ret_1y"); CAL_RANGE_MAPPER.put("24", "ret_2y"); CAL_RANGE_MAPPER.put("36", "ret_3y"); CAL_RANGE_MAPPER.put("60", "ret_5y"); CAL_RANGE_MAPPER.put("120", "ret_10y"); } private final String pyBaseUrl; private final BaseInfoService baseInfoService; private final FundStyleService fundStyleService; public StyleServiceImpl(AnalysisProperty property, BaseInfoService baseInfoService, FundStyleService fundStyleService) { this.pyBaseUrl = property.getPyUrl(); this.baseInfoService = baseInfoService; this.fundStyleService = fundStyleService; } /** * 参数检查 * * @param params 请求参数 * @param

类型参数 */ private

void checkParams(P params) { if (StrUtil.isBlank(params.getSecId())) { throw new APIException("secId 不能为空!"); } if (StrUtil.isBlank(params.getWinlen()) || !NumberUtil.isInteger(params.getWinlen()) || params.getWinlen().length() > 10) { throw new APIException("窗口参数非法!"); } if (StrUtil.isBlank(params.getStep()) || !NumberUtil.isInteger(params.getStep()) || Integer.parseInt(params.getStep()) > 100) { throw new APIException("步长参数非法!"); } IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy()); if (strategy == null) { strategy = Strategy.All; params.setStrategy(strategy.getStrategyOriginName()); } if (params.getRaiseType() == null) { params.setRaiseType(RaiseType.Both); } // CurveType curveType = CurveType.getCurveType(params.getRaiseType(), strategy); // Map> allNavMap = this.navService.getSecIdDateValueNavListMapFromRedisAndDB(ListUtil.toList(params.getSecId()), ListUtil.empty(), ListUtil.empty(), // null, null, NavType.CumulativeNav, Visibility.Both, curveType.getId(), strategy.getStrategyId(), // MapUtil.empty(), false, null); // Integer navLen = Optional.ofNullable(allNavMap).map(e -> e.get(params.getSecId())).map(List::size).orElse(0); // if (Integer.parseInt(params.getWinlen()) > navLen) { // throw new DataException("净值数量小于窗口期要求数量,无法计算"); // } } /** * python 请求异步处理,后续考虑用一个线程池,这里极端情况下可能会导致OOM * * @param reqs 请求 * @return / */ private Map> parallelReqPy(List reqs) { ExecutorService executorService = Executors.newFixedThreadPool(reqs.size()); List>>> futures = ListUtil.list(false); for (PyReq req : reqs) { String taskId = StrUtil.toString(req.getTaskId()); Future>> future = executorService.submit(() -> { String body; String url = this.pyBaseUrl + req.getApi(); if ("get".equalsIgnoreCase(req.getMethod())) { String encodeParams = HttpUtil.toParams(req.getParams(), Charset.defaultCharset()); body = HttpUtil.get(url + "?" + encodeParams); } else { body = req.getJson() ? HttpUtil.post(url, JSONUtil.toJsonStr(req.getParams())) : HttpUtil.post(url, req.getParams()); } return MapUtil.>builder(taskId, JSONUtil.parseArray(body)).build(); }); futures.add(future); } Map> result = MapUtil.newHashMap(); for (Future>> future : futures) { try { result.putAll(future.get()); } catch (Exception e) { logger.warn("当前任务执行异常:" + e.getMessage()); } } executorService.shutdown(); return result; } /** * 基于数据从高到低给因子排序 * * @param mapper 因子名称 * @param dataset 因子数据 * @param isDesc 是否倒序 * @return / */ private Map sortMapper(Map mapper, Map dataset, boolean isDesc) { Map temp = MapUtil.newHashMap(); List nullKeys = ListUtil.list(false); dataset.forEach((k, v) -> { if (!"date".equals(k)) { if (v != null) { temp.put(k, Double.parseDouble(StrUtil.toString(v))); } else { nullKeys.add(k); } } }); Map doubleMap = MapUtil.sortByValue(temp, isDesc); for (String nullKey : nullKeys) { doubleMap.putIfAbsent(nullKey, null); } Map result = MapUtil.newHashMap(true); doubleMap.forEach((k, v) -> { if (mapper.containsKey(k)) { result.put(k, mapper.get(k)); } }); return result; } /** * 基于数据从高到低给因子排序,默认升序 * * @param mapper 因子名称 * @param dataset 因子数据 * @return / */ private Map sortMapperAsc(Map mapper, Map dataset) { return this.sortMapper(mapper, dataset, false); } /** * 发起python请求并处理返回结果 * * @param params 参数 * @param extParams 扩展参数 * @param pyReqs / * @param

类型参数 * @return / */ private

PyResBody initiateRequest(P params, Map extParams, List pyReqs) { PyReqBody body = PyReqBody.builder().fundIds(params.getSecId()).startDate(params.getStartDate()).endDate(params.getEndDate()) .freq(FREQ_MAPPER.get(params.getFrequency())).step(params.getStep()).winLen(params.getWinlen()).build(); List reqs = ListUtil.list(false); pyReqs.forEach(e -> { Map extReq = MapUtil.builder(JSONUtil.parseObj(body)).putAll(extParams).put("control", e.getControl()).putAll(e.getExt()).build(); PyReq pyReq = PyReq.builder().taskId(e.getTaskId()).json(e.getJson()).api(e.getApi()).method(e.getMethod()).params(extReq).build(); reqs.add(pyReq); }); Map> data = this.parallelReqPy(reqs); PyResBody resBody = new PyResBody(); // 总的区间内模型回归结果 String holisticKey = pyReqs.stream().filter(e -> ObjectUtil.equals(e.getControl(), 0)).map(PyReqParam::getTaskId).findFirst().orElse(null); resBody.setHolistic(Optional.ofNullable(holisticKey).map(data::remove).orElse(ListUtil.list(false)).stream().map(JSONUtil::parseObj).findFirst().orElse(null)); // 滚动区间内模型回归结果 String sequentialKey = pyReqs.stream().filter(e -> ObjectUtil.equals(e.getControl(), 1)).map(PyReqParam::getTaskId).findFirst().orElse(null); resBody.setSequential(Optional.ofNullable(sequentialKey).map(data::remove).orElse(ListUtil.list(false)).stream().map(JSONUtil::parseObj).collect(Collectors.toList())); // 其他 Map>> extBody = MapUtil.newHashMap(); data.forEach((k, v) -> extBody.put(k, v.stream().map(JSONUtil::parseObj).collect(Collectors.toList()))); resBody.setExtBody(extBody); return resBody; } /** * 发起python请求并处理返回结果 * * @param api 接口 * @param params 公共请求参数 * @param extParams 接口扩展参数 * @param

类型参数 * @return / */ private

PyResBody initiateRequest(String api, P params, Map extParams) { Map controls = MapUtil.builder(0, "holistic").put(1, "sequential").build(); return this.initiateRequest(api, params, extParams, controls); } /** * 发起python请求并处理返回结果 * * @param api 接口 * @param params 公共请求参数 * @param extParams 接口扩展参数 * @param controls 同一个接口请求的参数,就control参数变化 * @param

类型参数 * @return / */ private

PyResBody initiateRequest(String api, P params, Map extParams, Map controls) { List pyReqs = ListUtil.list(false); controls.forEach((k, v) -> pyReqs.add(PyReqParam.builder().api(api).control(k).taskId(v).build())); return this.initiateRequest(params, extParams, pyReqs); } @Override public Map stockAttribution(StockAttributionParams params) { this.checkParams(params); try { // 太丑陋,要优化一下下 String indexIds = "FA000000MK_FA00000SMB_FA00000VMG_FA000000MT_FA000000RV"; // 五因子 Map chartMapper12 = MapUtil.builder(MapUtil.newHashMap(true)) .put("beta1", "市场因子").put("beta2", "规模因子").put("beta3", "价值因子").put("beta4", "动量因子").put("beta5", "反转因子").build(); Map chartMapper34 = MapUtil.builder(MapUtil.newHashMap(true)) .putAll(chartMapper12).put("epsi", "残差").put("alpha", "超额收益").build(); Map tableMapper1 = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", "因子系数(%)").putAll(chartMapper12).put("rSquared", "R2").build(); Map tableMapper3 = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", "贡献度(%)").putAll(chartMapper34).put("rSquared", "R2").build(); Map extParams = MapUtil.builder().put("indexIds", indexIds).put("winlen", params.getWinlen()) .put("strategy", 1).put("curve_type", 2).put("returnNo", "None").build(); PyResBody resBody = this.initiateRequest("GetPerformanceAttribution", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); Map betaList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("end_date")) .put("beta1", holisticMap.get("beta1")) .put("beta2", holisticMap.get("beta2")) .put("beta3", holisticMap.get("beta3")) .put("beta4", holisticMap.get("beta4")) .put("beta5", holisticMap.get("beta5")) .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared"))) .build(); Map contList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("end_date")) .put("beta1", holisticMap.get("cont1")) .put("beta2", holisticMap.get("cont2")) .put("beta3", holisticMap.get("cont3")) .put("beta4", holisticMap.get("cont4")) .put("beta5", holisticMap.get("cont5")) .put("epsi", holisticMap.get("tepsi")) .put("alpha", holisticMap.get("alpha")) .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared"))) .build(); AtomicReference intervalYieldRate = new AtomicReference<>((double) 0); List rateKeys = ListUtil.toList("cont1", "cont2", "cont3", "cont4", "cont5", "tepsi", "alpha"); holisticMap.forEach((k, v) -> { if (rateKeys.contains(k)) { intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v))); } }); Map chart2 = MapUtil.builder("dataset", betaList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper12, betaList)) .put("intervalYieldRate", intervalYieldRate).build(); Map chart4 = MapUtil.builder("dataset", contList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper34, contList)).build(); List> betaList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("end_date")) .put("beta1", e.get("beta1")) .put("beta2", e.get("beta2")) .put("beta3", e.get("beta3")) .put("beta4", e.get("beta4")) .put("beta5", e.get("beta5")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .build()).collect(Collectors.toList()); List> contList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("end_date")) .put("beta1", e.get("cont1")) .put("beta2", e.get("cont2")) .put("beta3", e.get("cont3")) .put("beta4", e.get("cont4")) .put("beta5", e.get("cont5")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .put("epsi", e.get("epsi")) .put("alpha", e.get("alpha")) .build()).collect(Collectors.toList()); Map chart1 = MapUtil.builder("dataset", betaList1) .put("chartProductNameMapping", chartMapper12).put("tableProductNameMapping", tableMapper1).build(); Map chart3 = MapUtil.builder("dataset", contList1) .put("chartProductNameMapping", chartMapper34).put("tableProductNameMapping", tableMapper3).build(); return MapUtil.builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build(); } catch (Exception e) { logger.error("因子归因计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public Map bondAttribution(BondAttributionParams params) { this.checkParams(params); try { Map chartMapper12 = MapUtil.builder(MapUtil.newHashMap(true)) .put("duration", "久期").put("structure", "期限结构") .put("convex", "凸性管理").put("credit", "信用利差").put("hyield", "高收益利差").put("conv", "可转债").build(); Map chartMapper34 = MapUtil.builder(MapUtil.newHashMap(true)) .putAll(chartMapper12).put("epsi", "残差").put("alpha", "超额收益").build(); Map tableMapper1 = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", "因子系数(%)").putAll(chartMapper12).put("rSquared", "R2").build(); Map tableMapper3 = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", "贡献度(%)").putAll(chartMapper34).put("rSquared", "R2").build(); Map extParams = MapUtil.builder().put("winlen", params.getWinlen()) .put("strategy", 1).put("curve_type", 2).build(); PyResBody resBody = this.initiateRequest("GetBondAttribution", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); Map betaList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("Date")) .put("duration", holisticMap.get("TDuration")) .put("structure", holisticMap.get("TStructure")) .put("convex", holisticMap.get("TConvex")) .put("credit", holisticMap.get("TCredit")) .put("hyield", holisticMap.get("THYield")) .put("conv", holisticMap.get("TConv")) .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared"))) .build(); Map contList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("Date")) .put("duration", holisticMap.get("Duration")) .put("structure", holisticMap.get("Structure")) .put("convex", holisticMap.get("Convex")) .put("credit", holisticMap.get("Credit")) .put("hyield", holisticMap.get("HYield")) .put("conv", holisticMap.get("Conv")) .put("epsi", holisticMap.get("Tepsi")) .put("alpha", holisticMap.get("Talpha")) .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared"))) .build(); AtomicReference intervalYieldRate = new AtomicReference<>(0.); List rateKeys = ListUtil.toList("TDuration", "TStructure", "TConvex", "TCredit", "THYield", "TConv", "Tepsi", "Talpha"); holisticMap.forEach((k, v) -> { if (rateKeys.contains(k)) { intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v))); } }); Map chart2 = MapUtil.builder("dataset", betaList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper12, betaList)) .put("intervalYieldRate", intervalYieldRate).build(); Map chart4 = MapUtil.builder("dataset", contList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper34, contList)).build(); List> betaList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("Date")) .put("duration", e.get("TDuration")) .put("structure", e.get("TStructure")) .put("convex", e.get("TConvex")) .put("credit", e.get("TCredit")) .put("hyield", e.get("THYield")) .put("conv", e.get("TConv")) .put("epsi", e.get("epsi")) .put("alpha", e.get("Alpha")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .build()).collect(Collectors.toList()); List> contList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("Date")) .put("duration", e.get("Duration")) .put("structure", e.get("Structure")) .put("convex", e.get("Convex")) .put("credit", e.get("Credit")) .put("hyield", e.get("HYield")) .put("conv", e.get("Conv")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .build()).collect(Collectors.toList()); Map chart1 = MapUtil.builder("dataset", contList1) .put("chartProductNameMapping", chartMapper12).put("tableProductNameMapping", tableMapper1).build(); Map chart3 = MapUtil.builder("dataset", betaList1) .put("chartProductNameMapping", chartMapper34).put("tableProductNameMapping", tableMapper3).build(); return MapUtil.builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build(); } catch (Exception e) { logger.error("债券业绩归因计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public Map relativeAttribution(RelativeAttributionParams params) { this.checkParams(params); try { Map chartMapper2 = MapUtil.builder(MapUtil.newHashMap(true)) .put("market", "市场").put("size", "市值").put("bookToPriceRatio", "账面市值比") .put("growvalue", "成长").put("hedge", "升贴水").build(); Map chartMapper1 = MapUtil.builder(MapUtil.newHashMap(true)).putAll(chartMapper2).put("rSquared", "R2").build(); Map chartMapper4 = MapUtil.builder(MapUtil.newHashMap(true)).putAll(chartMapper2).put("epsi", "残差").put("alpha", "超额收益").build(); Map chartMapper3 = MapUtil.builder(MapUtil.newHashMap(true)).putAll(chartMapper4).put("rSquared", "R2").build(); Map tableMapper1 = MapUtil.builder(MapUtil.newHashMap(true)).put("date", "因子系数(%)").putAll(chartMapper1).build(); Map tableMapper2 = MapUtil.builder(MapUtil.newHashMap(true)).put("date", "").putAll(chartMapper1).build(); Map tableMapper3 = MapUtil.builder(MapUtil.newHashMap(true)).put("date", "贡献度(%)").putAll(chartMapper3).build(); Map tableMapper4 = MapUtil.builder(MapUtil.newHashMap(true)).put("date", "").putAll(chartMapper3).build(); Map extParams = MapUtil.builder().put("winlen", params.getWinlen()).put("rw", 0) .put("returnNo", "None").put("strategy", 5).put("curve_type", 2).build(); PyResBody resBody = this.initiateRequest("GetRelAttribution", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); Map betaList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("end_date")) .put("market", holisticMap.get("TMarket")) .put("size", holisticMap.get("TSize")) .put("growvalue", holisticMap.get("TGrowvalue")) .put("hedge", holisticMap.get("THedge")) .put("bookToPriceRatio", holisticMap.get("TBookToPriceRatio")) .put("epsi", holisticMap.get("Tepsi")) .put("alpha", holisticMap.get("Talpha")) .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared"))) .build(); Map contList = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", holisticMap.get("end_date")) .put("market", holisticMap.get("Market")) .put("size", holisticMap.get("Size")) .put("growvalue", holisticMap.get("Growvalue")) .put("hedge", holisticMap.get("Hedge")) .put("bookToPriceRatio", holisticMap.get("BookToPriceRatio")) .build(); AtomicReference intervalYieldRate = new AtomicReference<>(0.); List rateKeys = ListUtil.toList("TMarket", "TSize", "TGrowvalue", "THedge", "TBookToPriceRatio", "Tepsi", "Talpha"); holisticMap.forEach((k, v) -> { if (rateKeys.contains(k)) { intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v))); } }); tableMapper2.put("date", holisticMap.get("Dateini") + "~" + holisticMap.get("end_date")); tableMapper4.put("date", holisticMap.get("Dateini") + "~" + holisticMap.get("end_date")); Map chart2 = MapUtil.builder("dataset", betaList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper2, betaList)) .put("tableProductNameMapping", tableMapper2).put("intervalYieldRate", intervalYieldRate).build(); Map chart4 = MapUtil.builder("dataset", contList) .put("chartProductNameMapping", this.sortMapperAsc(chartMapper4, contList)).put("tableProductNameMapping", tableMapper4).build(); List> betaList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("end_date")) .put("market", e.get("TMarket")) .put("size", e.get("TSize")) .put("growvalue", e.get("TGrowvalue")) .put("hedge", e.get("THedge")) .put("bookToPriceRatio", e.get("TBookToPriceRatio")) .put("epsi", e.get("epsi")) .put("alpha", e.get("Alpha")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .put("tmarket", e.get("TMarket")) .put("tsize", e.get("TSize")) .put("tgrowvalue", e.get("TGrowvalue")) .put("thedge", e.get("THedge")) .put("tbookToPriceRatio", e.get("TBookToPriceRatio")) .put("tepsi", e.get("epsi")) .put("talpha", e.get("Alpha")) .put("trSquared", this.rsquaredConstraint(e.get("R_squared"))) .build()).collect(Collectors.toList()); List> contList1 = sequential.stream().map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("date", e.get("end_date")) .put("market", e.get("Market")) .put("size", e.get("Size")) .put("growvalue", e.get("Growvalue")) .put("hedge", e.get("Hedge")) .put("bookToPriceRatio", e.get("BookToPriceRatio")) .put("rSquared", this.rsquaredConstraint(e.get("R_squared"))) .put("tmarket", e.get("Market")) .put("tsize", e.get("Size")) .put("tgrowvalue", e.get("Growvalue")) .put("thedge", e.get("Hedge")) .put("tbookToPriceRatio", e.get("BookToPriceRatio")) .put("trSquared", this.rsquaredConstraint(e.get("R_squared"))) .build()).collect(Collectors.toList()); Map chart1 = MapUtil.builder("dataset", contList1) .put("chartProductNameMapping", chartMapper1).put("tableProductNameMapping", tableMapper1).build(); Map chart3 = MapUtil.builder("dataset", betaList1) .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build(); return MapUtil.builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build(); } catch (Exception e) { logger.error("相对价值业绩归因计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public FundStyleVO growthValue(GrowthValueParams params) { this.checkParams(params); try { RBSAIndexType indexType = RBSA_MAPPER.get(params.getAllocationIndex()); return getFundStyleVO(params, indexType, params.getConstraint().getId()); } catch (Exception e) { logger.error("成长价值风格计算错误" + e.getMessage()); return null; } } @Override public FundStyleVO industryValue(IndustryValueParams params) { this.checkParams(params); try { if (params.getIndustryIndex() == IndustryType.ShenWan && params.getWinlen().compareTo("32") < 0) { params.setWinlen("36"); } RBSAIndexType indexType = RBSA_MAPPER.get(params.getIndustryIndex()); return getFundStyleVO(params, indexType, params.getConstraint().getId()); } catch (Exception e) { logger.error("行业配置风格计算错误" + e.getMessage()); return null; } } @Override public Map futureFactor(FutureFactorParams params) { this.checkParams(params); try { Map mapper = MapUtil.newHashMap(true); Map tableMapper = MapUtil.newHashMap(true); Map tableMapper2 = MapUtil.newHashMap(true); Map tableMapper4 = MapUtil.newHashMap(true); Map tableMapper3 = MapUtil.newHashMap(true); Map chartMapper4 = MapUtil.newHashMap(true); Map chartMapper3 = MapUtil.newHashMap(true); chartMapper4.put("sp", "特质因子"); chartMapper3.put("sp", "特质因子"); mapper.put("date", "日期"); for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) { mapper.put(value.getName(), value.getCName()); chartMapper4.put(value.getName(), value.getCName()); chartMapper3.put(value.getName(), value.getCName()); } tableMapper.putAll(mapper); tableMapper3.putAll(chartMapper3); tableMapper.put("r2", "R2"); tableMapper3.put("r2", "R2"); tableMapper2.putAll(mapper); tableMapper4.put("date", "日期"); tableMapper4.putAll(chartMapper4); tableMapper4.put("r2", "R2"); Map extParams = MapUtil.builder().put("winlen", params.getWinlen()) .put("indexIds", BarrConstant.FUTURE_INDEXS).build(); PyResBody resBody = this.initiateRequest("futures/style", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); List> dataset1 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) { temp.put("date", e.get("date")); temp.put(value.getName(), e.get("beta" + value.getNum())); temp.put("r2", this.rsquaredConstraint(e.get("nav_r_squared"))); } return temp; }).collect(Collectors.toList()); Map chart1 = MapUtil.builder("dataset", dataset1) .put("chartProductNameMapping", mapper).put("tableProductNameMapping", tableMapper).build(); Map dataset20 = MapUtil.newHashMap(); Map dataset41 = MapUtil.newHashMap(); Map dataset42 = MapUtil.newHashMap(); for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) { dataset41.put(value.getName(), holisticMap.get("nav_coef" + value.getNum())); dataset42.put(value.getName(), holisticMap.get("vol_coef" + value.getNum())); dataset20.put(value.getName(), holisticMap.get("beta" + value.getNum())); } dataset41.put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared"))); dataset41.put("sp", holisticMap.get("nav_sp")); dataset42.put("r2", this.rsquaredConstraint(holisticMap.get("vol_r_squared"))); dataset42.put("sp", holisticMap.get("vol_sp")); dataset20.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date")); dataset41.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date")); dataset42.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date")); tableMapper2.put("date", "统计区间"); tableMapper4.put("date", "统计区间"); Map profit4 = MapUtil.builder("dataset", dataset41) .put("chartProductNameMapping", this.sortMapper(chartMapper4, dataset41, true)) .put("tableProductNameMapping", tableMapper4).build(); Map risk4 = MapUtil.builder("dataset", dataset42) .put("chartProductNameMapping", this.sortMapper(chartMapper4, dataset42, true)) .put("tableProductNameMapping", tableMapper4).build(); Map chart4 = MapUtil.builder("profit", profit4).put("risk", risk4).build(); Map chart2 = MapUtil.builder("dataset", dataset20) .put("chartProductNameMapping", this.sortMapper(mapper, dataset20, true)) .put("tableProductNameMapping", tableMapper2).put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared"))).build(); List> dataset31 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", e.get("date")); temp.put("sp", e.get("nav_sp")); temp.put("r2", this.rsquaredConstraint(e.get("nav_r_squared"))); for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) { temp.put(value.getName(), e.get("nav_coef" + value.getNum())); } return temp; }).collect(Collectors.toList()); List> dataset32 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", e.get("date")); temp.put("sp", e.get("vol_sp")); temp.put("r2", this.rsquaredConstraint(e.get("vol_r_squared"))); for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) { temp.put(value.getName(), e.get("vol_coef" + value.getNum())); } return temp; }).collect(Collectors.toList()); Map profit3 = MapUtil.builder("dataset", dataset31) .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build(); Map risk3 = MapUtil.builder("dataset", dataset32) .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build(); Map chart3 = MapUtil.builder("profit", profit3).put("risk", risk3).build(); return MapUtil.builder("chart1", chart1).put("chart2", chart2).put("chart4", chart4).put("chart3", chart3).build(); } catch (Exception e) { logger.error("期货风格归因计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public CustomRbsaVO customRbsa(CustomRbsaParams params) { this.checkParams(params); try { List ids = params.getIndexIds(); String rfIndex = params.getExcess() == 0 ? "None" : Consts.RISK_OF_FREE; String indexIds = String.join("_", ids); String up = ids.stream().map(e -> "1").collect(Collectors.joining("_")); String down = ids.stream().map(e -> "0").collect(Collectors.joining("_")); Map extParams = MapUtil.builder() .put("indexIds", indexIds) .put("upbounds", up) .put("downbounds", down) .put("boundswitch", params.getConstraint().getId()) .put("rfIndex", rfIndex) .put("rfValue", "None") .put("constraintvalue", params.getConstraintType() == 1 ? up : up.replaceAll("1", "0")) .put("constrainttype", params.getConstraintType()) .put("alphacontrol", 0) .put("style", "F0") .put("winlen", params.getWinlen()) .put("rw", 0) .put("dataType", 1) .put("returnNo", "None") .put("strategy", 1) .put("curve_type", 2) .put("freq", FREQ_MAPPER.get(params.getFrequency())) .build(); PyReqParam holisticExt = PyReqParam.builder().api("GetCustomRbsa").control(0).taskId("holistic") .ext(MapUtil.builder("freq", FREQ_MAPPER.get(Frequency.Weekly)).build()).build(); PyReqParam sequentialExt = PyReqParam.builder().api("GetCustomRbsa").control(1).taskId("sequential").build(); List pyReqs = ListUtil.of(holisticExt, sequentialExt); PyResBody resBody = this.initiateRequest(params, extParams, pyReqs); Map holisticMap = resBody.getHolistic(); List> sequential = resBody.getSequential(); Map indexProMap = this.baseInfoService.querySecName(ids); Map risk = MapUtil.newHashMap(true); Map profit = MapUtil.newHashMap(true); indexProMap.forEach((k, v) -> { int i = ids.indexOf(k) + 1; risk.put("date", holisticMap.get("date")); profit.put("date", holisticMap.get("date")); risk.put(k, MapUtil.getStr(holisticMap, "beta" + i)); profit.put(k, MapUtil.getStr(holisticMap, "cont" + i)); }); CustomRbsaVO.DataSet dataset = new CustomRbsaVO.DataSet(risk, profit); CustomRbsaVO.Chart2 chart2 = CustomRbsaVO.Chart2.builder().dataset(dataset).chartProductNameMapping(indexProMap) .r2(this.rsquaredConstraint(MapUtil.getStr(holisticMap, "r_squared"))).build(); List> dataset1 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(true); temp.put("date", e.get("date")); temp.put("r2", this.rsquaredConstraint(e.get("r_squared"))); indexProMap.forEach((k, v) -> { int i = ids.indexOf(k) + 1; temp.put(k, MapUtil.getStr(e, "beta" + i)); }); return temp; }).collect(Collectors.toList()); CustomRbsaVO.Chart1 chart1 = CustomRbsaVO.Chart1.builder().dataset(dataset1).chartProductNameMapping(indexProMap).build(); return CustomRbsaVO.builder().chart1(chart1).chart2(chart2).build(); } catch (Exception e) { logger.error("自定义风格计算错误" + e.getMessage()); return null; } } @Override public Map barraOverview(BarraStyleParams params) { this.checkParams(params); try { Map mapper = MapUtil.newHashMap(true); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { mapper.put(value.getName(), value.getYName()); } Map extParams = MapUtil.builder().put("winlen", params.getWinlen()).put("benchmarkId", params.getBenchmarkId()) .put("indexIds", BarrConstant.BARRA_FACTOR_INDEXS).put("poolCode", BarrConstant.POOL_CACHE_ALL).put("excess", params.getExcess()).build(); PyReqParam holisticExt = PyReqParam.builder().api("GetBarraSensitivity").control(0).taskId("holistic").build(); PyReqParam sequentialExt = PyReqParam.builder().api("GetBarraSensitivity").control(1).taskId("sequential").build(); PyReqParam factorTrendExt = PyReqParam.builder().api("GetBarraSensitivity").control(2).taskId("factorTrend").build(); List pyReqs = ListUtil.of(holisticExt, sequentialExt, factorTrendExt); PyResBody resBody = this.initiateRequest(params, extParams, pyReqs); Map holisticMap = resBody.getHolistic(); List> sequential = resBody.getSequential(); List> factorTrend = resBody.getExtBody().get("factorTrend"); List> dataset1 = ListUtil.list(true); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { Map temp = MapUtil.newHashMap(); temp.put("name", value.getCName()); temp.put("product", holisticMap.get("coef" + value.getNum())); temp.put("standardError", holisticMap.get("std_err" + value.getNum())); temp.put("t", holisticMap.get("t" + value.getNum())); temp.put("pt", holisticMap.get("pt" + value.getNum())); dataset1.add(temp); } dataset1.sort((o1, o2) -> MapUtil.getDouble(o2, "product").compareTo(MapUtil.getDouble(o1, "product"))); Map mapper1 = MapUtil.builder(MapUtil.newHashMap(true)) .put("name", "名称") .put("product", "产品敏感度") .put("standardError", "标准误差") .put("t", "t") .put("pt", "p>|t|") .build(); Map chart1 = MapUtil.builder("dataset", dataset1).put("tableProductNameMapping", mapper1) .put("r2", this.rsquaredConstraint(holisticMap.get("r_squared"))).build(); Map tableMapper23 = new LinkedHashMap<>(); tableMapper23.put("date", "时段"); tableMapper23.putAll(mapper); tableMapper23.put("r2", "R2"); List> dataset2 = factorTrend.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", "custom".equals(e.get("dateini")) ? "当前区间" : e.get("dateini") + "年"); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { temp.put(value.getName(), e.get("coef" + value.getNum())); } temp.put("r2", this.rsquaredConstraint(e.get(BarrConstant.R_SQUARED))); return temp; }).collect(Collectors.toList()); Map chart2 = MapUtil.builder("dataset", dataset2).put("tableProductNameMapping", tableMapper23) .put("chartProductNameMapping", mapper).build(); List> dataset3 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", e.get("end_date")); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { temp.put(value.getName(), e.get("coef" + value.getNum())); } temp.put("r2", this.rsquaredConstraint(e.get("r_squared"))); return temp; }).collect(Collectors.toList()); Map chart3 = MapUtil.builder("dataset", dataset3).put("tableProductNameMapping", tableMapper23) .put("chartProductNameMapping", mapper).build(); return MapUtil.builder().put("chart1", chart1).put("chart2", chart2).put("chart3", chart3).build(); } catch (Exception e) { logger.error("barra概览计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public Map barraRiskProfit(BarraStyleParams params) { this.checkParams(params); try { Map mapper = MapUtil.newHashMap(true); Map mapperForTable = MapUtil.newHashMap(true); mapperForTable.put("r2", "R2值"); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { mapper.put(value.getName(), value.getCName()); mapperForTable.put(value.getName(), value.getCName()); } Map tableMapper1 = MapUtil.newHashMap(true); for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) { tableMapper1.put(value.getKey(), value.getProfit()); } Map chartMapper1 = new LinkedHashMap<>(tableMapper1); chartMapper1.remove("r2"); Map tableMapper3 = MapUtil.newHashMap(true); tableMapper3.put("date", "时段"); for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) { tableMapper3.put(value.getKey(), value.getRisk()); } Map chartMapper3 = new LinkedHashMap<>(tableMapper3); chartMapper3.remove("r2"); Map extParams = MapUtil.builder().put("winlen", params.getWinlen()).put("benchmarkId", params.getBenchmarkId()) .put("indexIds", BarrConstant.BARRA_FACTOR_INDEXS).put("poolCode", BarrConstant.POOL_CACHE_ALL).put("excess", params.getExcess()).build(); PyResBody resBody = this.initiateRequest("GetBarraNavAttribution", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); // chart1 List> dataset1 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", e.get("end_date")); temp.put("r2", this.rsquaredConstraint(e.get("r_squared"))); for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) { temp.put(value.getKey(), e.get("nav_" + value.getCode())); } return temp; }).collect(Collectors.toList()); Map chart1 = MapUtil.builder("dataset", dataset1).put("chartProductNameMapping", chartMapper1).put("tableProductNameMapping", tableMapper1).build(); // chart2 List> dataset2 = ListUtil.list(true); Map temp2 = MapUtil.newHashMap(); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { temp2.put(value.getName(), holisticMap.get("nav_cont" + value.getNum())); } dataset2.add(temp2); Map chart2 = MapUtil.builder("dataset", dataset2).put("chartProductNameMapping", this.sortMapperAsc(mapper, dataset2.get(0))) .put("tableProductNameMapping", mapperForTable).put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared"))).build(); // chart3 List> dataset3 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(); temp.put("date", e.get("end_date")); temp.put("r2", this.rsquaredConstraint(e.get("r_squared"))); for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) { temp.put(value.getKey(), e.get("vol_" + value.getCode())); } return temp; }).collect(Collectors.toList()); Map chart3 = MapUtil.builder("dataset", dataset3).put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build(); // chart4 List> dataset4 = ListUtil.list(true); Map temp4 = MapUtil.newHashMap(); for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) { temp4.put(value.getName(), holisticMap.get("vol_cont" + value.getNum())); } dataset4.add(temp4); Map chart4 = MapUtil.builder("dataset", dataset4).put("chartProductNameMapping", this.sortMapperAsc(mapper, dataset4.get(0))) .put("tableProductNameMapping", mapperForTable).build(); return MapUtil.builder().put("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build(); } catch (Exception e) { logger.error("barra风格计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override public Map selectionTiming(SelectionTimingParams params) { try { if (!CAL_RANGE_MAPPER.containsKey(params.getWinlen())) throw new APIException("窗口参数非法"); Map mapper = MapUtil.builder(MapUtil.newHashMap(true)) .put("alpha", "选股能力").put("beta", "择时能力").build(); Map mapper1 = MapUtil.builder(MapUtil.newHashMap(true)) .put("range", "统计周期") .put("alpha", "Alpha(%)") .put("testAlpha", "T检验(Alpha)") .put("selectionAlpha", "选股能力(Alpha)") .put("beta2", "Beta2") .put("testBeta2", "T检验(Beta2)") .put("timingBeta2", "择时能力(Beta2)") .build(); Map extParams = MapUtil.builder().put("model", params.getModel()).put("benchmarkId", params.getBenchmarkId()) .put("calRange", CAL_RANGE_MAPPER.get(params.getWinlen())).build(); PyReqParam holisticExt = PyReqParam.builder().api("GetIndicatorStatsLine").method("get").taskId("holistic").build(); PyReqParam sequentialExt = PyReqParam.builder().api("GetIndicatorStatsTable").method("get").taskId("sequential").control(1).build(); List pyReqs = ListUtil.of(holisticExt, sequentialExt); PyResBody resBody = this.initiateRequest(params, extParams, pyReqs); List> sequential = resBody.getSequential(); List> holistic = resBody.getExtBody().get("holistic"); List> dataset = holistic.stream().map(e -> MapUtil.builder("date", e.get("range_perid")) .put("alpha", e.get("alpha_value")).put("beta", e.get("beta2_value")).build()).collect(Collectors.toList()); List> dataset1 = sequential.stream().filter(e -> !"成立以来".equals(e.get("range_perid"))).map(e -> MapUtil.builder(MapUtil.newHashMap(true)) .put("range", e.get("range_perid")) .put("alpha", e.get("alpha")) .put("testAlpha", e.get("alpha_pvalue")) .put("selectionAlpha", e.get("stock_selection_ability")) .put("beta2", e.get("beta2")) .put("testBeta2", e.get("beta2_pvalue")) .put("timingBeta2", e.get("market_timing_ability")) .build()).collect(Collectors.toList()); Map chart = MapUtil.builder().put("dataset", dataset).put("productNameMapping", mapper).build(); Map table = MapUtil.builder().put("dataset", dataset1).put("productNameMapping", mapper1).build(); return MapUtil.builder().put("chart", chart).put("table", table).build(); } catch (Exception e) { logger.error("选股择时能力计算错误" + e.getMessage()); return MapUtil.empty(); } } @Override @SuppressWarnings("unchecked") public Map rzStyle(RzStyleParams params) { try { List fundStyleStatsList = fundStyleService.listFundStyleOverview(params.getSecId()); List> dataset = ListUtil.list(true); for (FundStyleStatsDO fundStyleStatsDO : fundStyleStatsList) { Map tempMap = MapUtil.newHashMap(); tempMap.put("date", fundStyleStatsDO.getEndDate()); tempMap.put("upside", fundStyleStatsDO.getUpsideCaptureRatio1y()); tempMap.put("downside",fundStyleStatsDO.getDownsideCaptureRatio1y()); tempMap.put("style", handleFundStyle(fundStyleStatsDO.getUpsideCaptureRatio1y(),fundStyleStatsDO.getDownsideCaptureRatio1y())); dataset.add(tempMap); } Map mapper = MapUtil.builder(MapUtil.newHashMap(true)) .put("date", "时间").put("upside", "进攻能力").put("downside", "防御能力").put("style", "风格").build(); Map chart1 = MapUtil.builder().put("dataset", dataset) .put("chartProductNameMapping", mapper).put("tableProductNameMapping", mapper).build(); List secIdList = ListUtil.list(true); List fundBenchmarkList = ListUtil.toList(params.getSecId(), params.getBenchmarkId()); List unionIds = CollUtil.addAllIfNotContains(fundBenchmarkList, secIdList); return MapUtil.builder().put("chart1", chart1).build(); } catch (Exception e) { logger.error("风格总览计算错误" + e.getMessage()); return MapUtil.empty(); } } private String handleFundStyle(BigDecimal upside, BigDecimal downside) { String style; BigDecimal standardLevel = BigDecimal.valueOf(0.5); if (standardLevel.compareTo(upside) <= 0 && standardLevel.compareTo(downside) >= 0) { style = "攻守兼备型"; } else if (standardLevel.compareTo(upside) > 0 && standardLevel.compareTo(downside) > 0) { style = "防御型"; } else if (standardLevel.compareTo(upside) < 0 && standardLevel.compareTo(downside) < 0) { style = "进攻型"; } else { style = "风格不明显"; } return style; } /** * 成长价值和行业配置接口重构,支持基金、机构、经理、组合等 * * @param params 请求参数 * @param indexType 因子 * @param boundSwitch 多空或多头 * @param

类型参数 * @return / */ private

FundStyleVO getFundStyleVO(P params, RBSAIndexType indexType, Integer boundSwitch) { CurveType curveType = CurveType.getCurveType(params.getRaiseType(), StrategyHandleUtils.getStrategy(params.getStrategy())); List strategyList = ListUtil.of(CurveType.PrivateSubstratgy, CurveType.PublicSubstrategy, CurveType.BothSubstratgy); int curveTypeId = strategyList.contains(curveType) ? curveType.getId() : 2; String indexIds = String.join("_", RBSAIndexTypeMap.getInstance().getIndexIds(indexType)); Map extParams = MapUtil.builder().put("boundSwitch", boundSwitch) .put("indexIds", indexIds).put("strategy", 1).put("curveType", curveTypeId).build(); PyResBody resBody = this.initiateRequest("fund/style", params, extParams); List> sequential = resBody.getSequential(); Map holisticMap = resBody.getHolistic(); Map indexProMap = RBSA_INDEX_PROD_MAPPER.get(indexType); Map risk = MapUtil.newHashMap(true); Map profit = MapUtil.newHashMap(true); indexProMap.forEach((k, v) -> { risk.put("date", holisticMap.get("date")); risk.put(k, MapUtil.getStr(holisticMap, k)); }); for (int i = 0; i < indexProMap.size(); i++) { profit.put("date", holisticMap.get("date")); profit.put("beta" + (i + 1), MapUtil.getStr(holisticMap, "cont" + (i + 1))); } FundStyleVO.DataSet dataset = new FundStyleVO.DataSet(risk, profit); FundStyleVO.Chart2 chart2 = FundStyleVO.Chart2.builder().dataset(dataset).chartProductNameMapping(indexProMap) .r2(this.rsquaredConstraint(MapUtil.getStr(holisticMap, "r_squared"))).build(); List> dataset1 = sequential.stream().map(e -> { Map temp = MapUtil.newHashMap(true); temp.put("date", e.get("date")); temp.put("r2", this.rsquaredConstraint(e.get("r_squared"))); indexProMap.forEach((k, v) -> temp.put(k, MapUtil.getStr(e, k))); return temp; }).collect(Collectors.toList()); FundStyleVO.Chart1 chart1 = FundStyleVO.Chart1.builder().dataset(dataset1).chartProductNameMapping(indexProMap).build(); return FundStyleVO.builder().chart1(chart1).chart2(chart2).build(); } /** * 对r2做一个简单的约束,[-1, 1] 之间 * * @param r2 / * @return / */ private String rsquaredConstraint(Object r2) { if (r2 == null) { return null; } double v = Double.parseDouble(StrUtil.toString(r2)); if (v < -1d) { v = -1d; } else if (v > 1d) { v = 1d; } return String.valueOf(v); } }