StyleServiceImpl.java 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. package com.smppw.analysis.application.service.style;
  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.ObjectUtil;
  7. import cn.hutool.core.util.StrUtil;
  8. import cn.hutool.http.HttpUtil;
  9. import cn.hutool.json.JSONUtil;
  10. import com.smppw.analysis.domain.dataobject.FundStyleStatsDO;
  11. import com.smppw.analysis.domain.dto.style.*;
  12. import com.smppw.analysis.domain.dto.style.py.PyReq;
  13. import com.smppw.analysis.domain.dto.style.py.PyReqBody;
  14. import com.smppw.analysis.domain.dto.style.py.PyReqParam;
  15. import com.smppw.analysis.domain.dto.style.py.PyResBody;
  16. import com.smppw.analysis.domain.service.BaseInfoService;
  17. import com.smppw.analysis.domain.service.FundStyleService;
  18. import com.smppw.analysis.infrastructure.config.AnalysisProperty;
  19. import com.smppw.analysis.infrastructure.consts.*;
  20. import com.smppw.analysis.infrastructure.exception.APIException;
  21. import com.smppw.common.pojo.IStrategy;
  22. import com.smppw.common.pojo.enums.CurveType;
  23. import com.smppw.common.pojo.enums.Frequency;
  24. import com.smppw.common.pojo.enums.RaiseType;
  25. import com.smppw.common.pojo.enums.strategy.Strategy;
  26. import com.smppw.constants.Consts;
  27. import com.smppw.utils.StrategyHandleUtils;
  28. import org.slf4j.Logger;
  29. import org.slf4j.LoggerFactory;
  30. import org.springframework.stereotype.Service;
  31. import java.math.BigDecimal;
  32. import java.nio.charset.Charset;
  33. import java.util.LinkedHashMap;
  34. import java.util.List;
  35. import java.util.Map;
  36. import java.util.Optional;
  37. import java.util.concurrent.ExecutorService;
  38. import java.util.concurrent.Executors;
  39. import java.util.concurrent.Future;
  40. import java.util.concurrent.atomic.AtomicReference;
  41. import java.util.stream.Collectors;
  42. @Service
  43. public class StyleServiceImpl implements StyleService {
  44. private static final Logger logger = LoggerFactory.getLogger(StyleServiceImpl.class);
  45. private static final Map<Frequency, String> FREQ_MAPPER = MapUtil.newHashMap();
  46. private static final Map<Object, RBSAIndexType> RBSA_MAPPER = MapUtil.newHashMap();
  47. private static final Map<RBSAIndexType, Map<String, String>> RBSA_INDEX_PROD_MAPPER = MapUtil.newHashMap();
  48. private static final Map<String, String> CAL_RANGE_MAPPER = MapUtil.newHashMap();
  49. static {
  50. FREQ_MAPPER.put(Frequency.Default, "D");
  51. FREQ_MAPPER.put(Frequency.Daily, "D");
  52. FREQ_MAPPER.put(Frequency.Weekly, "W");
  53. FREQ_MAPPER.put(Frequency.Monthly, "M");
  54. FREQ_MAPPER.put(Frequency.Quarterly, "Q");
  55. FREQ_MAPPER.put(Frequency.Annually, "Y");
  56. RBSA_MAPPER.put(ValueGrowthType.CNI6Style, RBSAIndexType.CNI7Style);
  57. RBSA_MAPPER.put(ValueGrowthType.CNI2Style, RBSAIndexType.CNI3Style);
  58. RBSA_MAPPER.put(ValueGrowthType.CNI6Strategy, RBSAIndexType.CNI7Strategy);
  59. RBSA_MAPPER.put(IndustryType.CITIC5, RBSAIndexType.CITIC6);
  60. RBSA_MAPPER.put(IndustryType.CSI10, RBSAIndexType.CSI11);
  61. RBSA_MAPPER.put(IndustryType.ShenWan, RBSAIndexType.ShenWan);
  62. RBSA_MAPPER.put(AssetStyleType.MultiAsset, RBSAIndexType.Large4Assets);
  63. RBSA_MAPPER.put(AssetStyleType.RongZhiStrategy, RBSAIndexType.RZ5Strategy);
  64. RBSA_MAPPER.put(AssetStyleType.SegmentationAsset, RBSAIndexType.SegmentationAsset);
  65. // 成长价值
  66. // 巨潮风格
  67. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI7Style, MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("beta1", "大盘成长")
  68. .put("beta2", "大盘价值").put("beta3", "中盘成长").put("beta4", "中盘价值")
  69. .put("beta5", "小盘成长").put("beta6", "小盘价值").build()
  70. );
  71. // 国证风格
  72. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI3Style, MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("beta1", "成长").put("beta2", "价值").build());
  73. // 国证策略
  74. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CNI7Strategy, MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("beta1", "大盘低贝")
  75. .put("beta2", "大盘高贝").put("beta3", "中盘低贝").put("beta4", "中盘高贝")
  76. .put("beta5", "小盘低贝").put("beta6", "小盘高贝").build());
  77. // 行业配置
  78. // 申万一级行业
  79. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.ShenWan, MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  80. .put("beta1", "美容护理")
  81. .put("beta2", "环保")
  82. .put("beta3", "石油石化")
  83. .put("beta4", "煤炭")
  84. .put("beta5", "机械设备")
  85. .put("beta6", "汽车")
  86. .put("beta7", "非银金融")
  87. .put("beta8", "银行")
  88. .put("beta9", "通信")
  89. .put("beta10", "传媒")
  90. .put("beta11", "计算机")
  91. .put("beta12", "国防军工")
  92. .put("beta13", "电力设备")
  93. .put("beta14", "建筑装饰")
  94. .put("beta15", "建筑材料")
  95. .put("beta16", "综合")
  96. .put("beta17", "社会服务")
  97. .put("beta18", "商贸零售")
  98. .put("beta19", "房地产")
  99. .put("beta20", "交通运输")
  100. .put("beta21", "公用事业")
  101. .put("beta22", "医药生物")
  102. .put("beta23", "轻工制造")
  103. .put("beta24", "纺织服饰")
  104. .put("beta25", "食品饮料")
  105. .put("beta26", "家用电器")
  106. .put("beta27", "电子")
  107. .put("beta28", "有色金属")
  108. .put("beta29", "钢铁")
  109. .put("beta30", "基础化工")
  110. .put("beta31", "农林牧渔")
  111. .build());
  112. // 中证行业
  113. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CSI11, MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  114. .put("beta1", "中证材料")
  115. .put("beta2", "中证电信")
  116. .put("beta3", "中证工业")
  117. .put("beta4", "中证公用")
  118. .put("beta5", "中证金融")
  119. .put("beta6", "中证可选")
  120. .put("beta7", "中证能源")
  121. .put("beta8", "中证消费")
  122. .put("beta9", "中证信息")
  123. .put("beta10", "中证医药")
  124. .build());
  125. // 中信行业风格
  126. RBSA_INDEX_PROD_MAPPER.put(RBSAIndexType.CITIC6, MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  127. .put("beta1", "金融")
  128. .put("beta2", "周期")
  129. .put("beta3", "消费")
  130. .put("beta4", "成长")
  131. .put("beta5", "稳定")
  132. .build());
  133. CAL_RANGE_MAPPER.put("3", "ret_3m");
  134. CAL_RANGE_MAPPER.put("6", "ret_6m");
  135. CAL_RANGE_MAPPER.put("12", "ret_1y");
  136. CAL_RANGE_MAPPER.put("24", "ret_2y");
  137. CAL_RANGE_MAPPER.put("36", "ret_3y");
  138. CAL_RANGE_MAPPER.put("60", "ret_5y");
  139. CAL_RANGE_MAPPER.put("120", "ret_10y");
  140. }
  141. private final String pyBaseUrl;
  142. private final BaseInfoService baseInfoService;
  143. private final FundStyleService fundStyleService;
  144. public StyleServiceImpl(AnalysisProperty property, BaseInfoService baseInfoService, FundStyleService fundStyleService) {
  145. this.pyBaseUrl = property.getPyUrl();
  146. this.baseInfoService = baseInfoService;
  147. this.fundStyleService = fundStyleService;
  148. }
  149. /**
  150. * 参数检查
  151. *
  152. * @param params 请求参数
  153. * @param <P> 类型参数
  154. */
  155. private <P extends BaseParams> void checkParams(P params) {
  156. if (StrUtil.isBlank(params.getSecId())) {
  157. throw new APIException("secId 不能为空!");
  158. }
  159. if (StrUtil.isBlank(params.getWinlen()) || !NumberUtil.isInteger(params.getWinlen()) || params.getWinlen().length() > 10) {
  160. throw new APIException("窗口参数非法!");
  161. }
  162. if (StrUtil.isBlank(params.getStep()) || !NumberUtil.isInteger(params.getStep()) || Integer.parseInt(params.getStep()) > 100) {
  163. throw new APIException("步长参数非法!");
  164. }
  165. IStrategy strategy = StrategyHandleUtils.getStrategy(params.getStrategy());
  166. if (strategy == null) {
  167. strategy = Strategy.All;
  168. params.setStrategy(strategy.getStrategyOriginName());
  169. }
  170. if (params.getRaiseType() == null) {
  171. params.setRaiseType(RaiseType.Both);
  172. }
  173. // CurveType curveType = CurveType.getCurveType(params.getRaiseType(), strategy);
  174. // Map<String, List<DateValue>> allNavMap = this.navService.getSecIdDateValueNavListMapFromRedisAndDB(ListUtil.toList(params.getSecId()), ListUtil.empty(), ListUtil.empty(),
  175. // null, null, NavType.CumulativeNav, Visibility.Both, curveType.getId(), strategy.getStrategyId(),
  176. // MapUtil.empty(), false, null);
  177. // Integer navLen = Optional.ofNullable(allNavMap).map(e -> e.get(params.getSecId())).map(List::size).orElse(0);
  178. // if (Integer.parseInt(params.getWinlen()) > navLen) {
  179. // throw new DataException("净值数量小于窗口期要求数量,无法计算");
  180. // }
  181. }
  182. /**
  183. * python 请求异步处理,后续考虑用一个线程池,这里极端情况下可能会导致OOM
  184. *
  185. * @param reqs 请求
  186. * @return /
  187. */
  188. private Map<String, List<Object>> parallelReqPy(List<PyReq> reqs) {
  189. ExecutorService executorService = Executors.newFixedThreadPool(reqs.size());
  190. List<Future<Map<String, List<Object>>>> futures = ListUtil.list(false);
  191. for (PyReq req : reqs) {
  192. String taskId = StrUtil.toString(req.getTaskId());
  193. Future<Map<String, List<Object>>> future = executorService.submit(() -> {
  194. String body;
  195. String url = this.pyBaseUrl + req.getApi();
  196. if ("get".equalsIgnoreCase(req.getMethod())) {
  197. String encodeParams = HttpUtil.toParams(req.getParams(), Charset.defaultCharset());
  198. body = HttpUtil.get(url + "?" + encodeParams);
  199. } else {
  200. body = req.getJson() ? HttpUtil.post(url, JSONUtil.toJsonStr(req.getParams())) : HttpUtil.post(url, req.getParams());
  201. }
  202. return MapUtil.<String, List<Object>>builder(taskId, JSONUtil.parseArray(body)).build();
  203. });
  204. futures.add(future);
  205. }
  206. Map<String, List<Object>> result = MapUtil.newHashMap();
  207. for (Future<Map<String, List<Object>>> future : futures) {
  208. try {
  209. result.putAll(future.get());
  210. } catch (Exception e) {
  211. logger.warn("当前任务执行异常:" + e.getMessage());
  212. }
  213. }
  214. executorService.shutdown();
  215. return result;
  216. }
  217. /**
  218. * 基于数据从高到低给因子排序
  219. *
  220. * @param mapper 因子名称
  221. * @param dataset 因子数据
  222. * @param isDesc 是否倒序
  223. * @return /
  224. */
  225. private Map<String, String> sortMapper(Map<String, String> mapper, Map<String, Object> dataset, boolean isDesc) {
  226. Map<String, Double> temp = MapUtil.newHashMap();
  227. List<String> nullKeys = ListUtil.list(false);
  228. dataset.forEach((k, v) -> {
  229. if (!"date".equals(k)) {
  230. if (v != null) {
  231. temp.put(k, Double.parseDouble(StrUtil.toString(v)));
  232. } else {
  233. nullKeys.add(k);
  234. }
  235. }
  236. });
  237. Map<String, Double> doubleMap = MapUtil.sortByValue(temp, isDesc);
  238. for (String nullKey : nullKeys) {
  239. doubleMap.putIfAbsent(nullKey, null);
  240. }
  241. Map<String, String> result = MapUtil.newHashMap(true);
  242. doubleMap.forEach((k, v) -> {
  243. if (mapper.containsKey(k)) {
  244. result.put(k, mapper.get(k));
  245. }
  246. });
  247. return result;
  248. }
  249. /**
  250. * 基于数据从高到低给因子排序,默认升序
  251. *
  252. * @param mapper 因子名称
  253. * @param dataset 因子数据
  254. * @return /
  255. */
  256. private Map<String, String> sortMapperAsc(Map<String, String> mapper, Map<String, Object> dataset) {
  257. return this.sortMapper(mapper, dataset, false);
  258. }
  259. /**
  260. * 发起python请求并处理返回结果
  261. *
  262. * @param params 参数
  263. * @param extParams 扩展参数
  264. * @param pyReqs /
  265. * @param <P> 类型参数
  266. * @return /
  267. */
  268. private <P extends BaseParams> PyResBody initiateRequest(P params, Map<String, Object> extParams, List<PyReqParam> pyReqs) {
  269. PyReqBody body = PyReqBody.builder().fundIds(params.getSecId()).startDate(params.getStartDate()).endDate(params.getEndDate())
  270. .freq(FREQ_MAPPER.get(params.getFrequency())).step(params.getStep()).winLen(params.getWinlen()).build();
  271. List<PyReq> reqs = ListUtil.list(false);
  272. pyReqs.forEach(e -> {
  273. Map<String, Object> extReq = MapUtil.builder(JSONUtil.parseObj(body)).putAll(extParams).put("control", e.getControl()).putAll(e.getExt()).build();
  274. PyReq pyReq = PyReq.builder().taskId(e.getTaskId()).json(e.getJson()).api(e.getApi()).method(e.getMethod()).params(extReq).build();
  275. reqs.add(pyReq);
  276. });
  277. Map<String, List<Object>> data = this.parallelReqPy(reqs);
  278. PyResBody resBody = new PyResBody();
  279. // 总的区间内模型回归结果
  280. String holisticKey = pyReqs.stream().filter(e -> ObjectUtil.equals(e.getControl(), 0)).map(PyReqParam::getTaskId).findFirst().orElse(null);
  281. resBody.setHolistic(Optional.ofNullable(holisticKey).map(data::remove).orElse(ListUtil.list(false)).stream().map(JSONUtil::parseObj).findFirst().orElse(null));
  282. // 滚动区间内模型回归结果
  283. String sequentialKey = pyReqs.stream().filter(e -> ObjectUtil.equals(e.getControl(), 1)).map(PyReqParam::getTaskId).findFirst().orElse(null);
  284. resBody.setSequential(Optional.ofNullable(sequentialKey).map(data::remove).orElse(ListUtil.list(false)).stream().map(JSONUtil::parseObj).collect(Collectors.toList()));
  285. // 其他
  286. Map<String, List<Map<String, Object>>> extBody = MapUtil.newHashMap();
  287. data.forEach((k, v) -> extBody.put(k, v.stream().map(JSONUtil::parseObj).collect(Collectors.toList())));
  288. resBody.setExtBody(extBody);
  289. return resBody;
  290. }
  291. /**
  292. * 发起python请求并处理返回结果
  293. *
  294. * @param api 接口
  295. * @param params 公共请求参数
  296. * @param extParams 接口扩展参数
  297. * @param <P> 类型参数
  298. * @return /
  299. */
  300. private <P extends BaseParams> PyResBody initiateRequest(String api, P params, Map<String, Object> extParams) {
  301. Map<Integer, String> controls = MapUtil.builder(0, "holistic").put(1, "sequential").build();
  302. return this.initiateRequest(api, params, extParams, controls);
  303. }
  304. /**
  305. * 发起python请求并处理返回结果
  306. *
  307. * @param api 接口
  308. * @param params 公共请求参数
  309. * @param extParams 接口扩展参数
  310. * @param controls 同一个接口请求的参数,就control参数变化
  311. * @param <P> 类型参数
  312. * @return /
  313. */
  314. private <P extends BaseParams> PyResBody initiateRequest(String api, P params, Map<String, Object> extParams, Map<Integer, String> controls) {
  315. List<PyReqParam> pyReqs = ListUtil.list(false);
  316. controls.forEach((k, v) -> pyReqs.add(PyReqParam.builder().api(api).control(k).taskId(v).build()));
  317. return this.initiateRequest(params, extParams, pyReqs);
  318. }
  319. @Override
  320. public Map<String, Object> stockAttribution(StockAttributionParams params) {
  321. this.checkParams(params);
  322. try {
  323. // 太丑陋,要优化一下下
  324. String indexIds = "FA000000MK_FA00000SMB_FA00000VMG_FA000000MT_FA000000RV"; // 五因子
  325. Map<String, String> chartMapper12 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  326. .put("beta1", "市场因子").put("beta2", "规模因子").put("beta3", "价值因子").put("beta4", "动量因子").put("beta5", "反转因子").build();
  327. Map<String, String> chartMapper34 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  328. .putAll(chartMapper12).put("epsi", "残差").put("alpha", "超额收益").build();
  329. Map<String, String> tableMapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  330. .put("date", "因子系数(%)").putAll(chartMapper12).put("rSquared", "R2").build();
  331. Map<String, String> tableMapper3 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  332. .put("date", "贡献度(%)").putAll(chartMapper34).put("rSquared", "R2").build();
  333. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("indexIds", indexIds).put("winlen", params.getWinlen())
  334. .put("strategy", 1).put("curve_type", 2).put("returnNo", "None").build();
  335. PyResBody resBody = this.initiateRequest("GetPerformanceAttribution", params, extParams);
  336. List<Map<String, Object>> sequential = resBody.getSequential();
  337. Map<String, Object> holisticMap = resBody.getHolistic();
  338. Map<String, Object> betaList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  339. .put("date", holisticMap.get("end_date"))
  340. .put("beta1", holisticMap.get("beta1"))
  341. .put("beta2", holisticMap.get("beta2"))
  342. .put("beta3", holisticMap.get("beta3"))
  343. .put("beta4", holisticMap.get("beta4"))
  344. .put("beta5", holisticMap.get("beta5"))
  345. .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared")))
  346. .build();
  347. Map<String, Object> contList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  348. .put("date", holisticMap.get("end_date"))
  349. .put("beta1", holisticMap.get("cont1"))
  350. .put("beta2", holisticMap.get("cont2"))
  351. .put("beta3", holisticMap.get("cont3"))
  352. .put("beta4", holisticMap.get("cont4"))
  353. .put("beta5", holisticMap.get("cont5"))
  354. .put("epsi", holisticMap.get("tepsi"))
  355. .put("alpha", holisticMap.get("alpha"))
  356. .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared")))
  357. .build();
  358. AtomicReference<Double> intervalYieldRate = new AtomicReference<>((double) 0);
  359. List<String> rateKeys = ListUtil.toList("cont1", "cont2", "cont3", "cont4", "cont5", "tepsi", "alpha");
  360. holisticMap.forEach((k, v) -> {
  361. if (rateKeys.contains(k)) {
  362. intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v)));
  363. }
  364. });
  365. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", betaList)
  366. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper12, betaList))
  367. .put("intervalYieldRate", intervalYieldRate).build();
  368. Map<String, Object> chart4 = MapUtil.<String, Object>builder("dataset", contList)
  369. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper34, contList)).build();
  370. List<Map<String, Object>> betaList1 = sequential.stream().map(e ->
  371. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  372. .put("date", e.get("end_date"))
  373. .put("beta1", e.get("beta1"))
  374. .put("beta2", e.get("beta2"))
  375. .put("beta3", e.get("beta3"))
  376. .put("beta4", e.get("beta4"))
  377. .put("beta5", e.get("beta5"))
  378. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  379. .build()).collect(Collectors.toList());
  380. List<Map<String, Object>> contList1 = sequential.stream().map(e ->
  381. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  382. .put("date", e.get("end_date"))
  383. .put("beta1", e.get("cont1"))
  384. .put("beta2", e.get("cont2"))
  385. .put("beta3", e.get("cont3"))
  386. .put("beta4", e.get("cont4"))
  387. .put("beta5", e.get("cont5"))
  388. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  389. .put("epsi", e.get("epsi"))
  390. .put("alpha", e.get("alpha"))
  391. .build()).collect(Collectors.toList());
  392. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", betaList1)
  393. .put("chartProductNameMapping", chartMapper12).put("tableProductNameMapping", tableMapper1).build();
  394. Map<String, Object> chart3 = MapUtil.<String, Object>builder("dataset", contList1)
  395. .put("chartProductNameMapping", chartMapper34).put("tableProductNameMapping", tableMapper3).build();
  396. return MapUtil.<String, Object>builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build();
  397. } catch (Exception e) {
  398. logger.error("因子归因计算错误" + e.getMessage());
  399. return MapUtil.empty();
  400. }
  401. }
  402. @Override
  403. public Map<String, Object> bondAttribution(BondAttributionParams params) {
  404. this.checkParams(params);
  405. try {
  406. Map<String, String> chartMapper12 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  407. .put("duration", "久期").put("structure", "期限结构")
  408. .put("convex", "凸性管理").put("credit", "信用利差").put("hyield", "高收益利差").put("conv", "可转债").build();
  409. Map<String, String> chartMapper34 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  410. .putAll(chartMapper12).put("epsi", "残差").put("alpha", "超额收益").build();
  411. Map<String, String> tableMapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  412. .put("date", "因子系数(%)").putAll(chartMapper12).put("rSquared", "R2").build();
  413. Map<String, String> tableMapper3 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  414. .put("date", "贡献度(%)").putAll(chartMapper34).put("rSquared", "R2").build();
  415. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("winlen", params.getWinlen())
  416. .put("strategy", 1).put("curve_type", 2).build();
  417. PyResBody resBody = this.initiateRequest("GetBondAttribution", params, extParams);
  418. List<Map<String, Object>> sequential = resBody.getSequential();
  419. Map<String, Object> holisticMap = resBody.getHolistic();
  420. Map<String, Object> betaList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  421. .put("date", holisticMap.get("Date"))
  422. .put("duration", holisticMap.get("TDuration"))
  423. .put("structure", holisticMap.get("TStructure"))
  424. .put("convex", holisticMap.get("TConvex"))
  425. .put("credit", holisticMap.get("TCredit"))
  426. .put("hyield", holisticMap.get("THYield"))
  427. .put("conv", holisticMap.get("TConv"))
  428. .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared")))
  429. .build();
  430. Map<String, Object> contList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  431. .put("date", holisticMap.get("Date"))
  432. .put("duration", holisticMap.get("Duration"))
  433. .put("structure", holisticMap.get("Structure"))
  434. .put("convex", holisticMap.get("Convex"))
  435. .put("credit", holisticMap.get("Credit"))
  436. .put("hyield", holisticMap.get("HYield"))
  437. .put("conv", holisticMap.get("Conv"))
  438. .put("epsi", holisticMap.get("Tepsi"))
  439. .put("alpha", holisticMap.get("Talpha"))
  440. .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared")))
  441. .build();
  442. AtomicReference<Double> intervalYieldRate = new AtomicReference<>(0.);
  443. List<String> rateKeys = ListUtil.toList("TDuration", "TStructure", "TConvex", "TCredit", "THYield", "TConv", "Tepsi", "Talpha");
  444. holisticMap.forEach((k, v) -> {
  445. if (rateKeys.contains(k)) {
  446. intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v)));
  447. }
  448. });
  449. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", betaList)
  450. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper12, betaList))
  451. .put("intervalYieldRate", intervalYieldRate).build();
  452. Map<String, Object> chart4 = MapUtil.<String, Object>builder("dataset", contList)
  453. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper34, contList)).build();
  454. List<Map<String, Object>> betaList1 = sequential.stream().map(e ->
  455. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  456. .put("date", e.get("Date"))
  457. .put("duration", e.get("TDuration"))
  458. .put("structure", e.get("TStructure"))
  459. .put("convex", e.get("TConvex"))
  460. .put("credit", e.get("TCredit"))
  461. .put("hyield", e.get("THYield"))
  462. .put("conv", e.get("TConv"))
  463. .put("epsi", e.get("epsi"))
  464. .put("alpha", e.get("Alpha"))
  465. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  466. .build()).collect(Collectors.toList());
  467. List<Map<String, Object>> contList1 = sequential.stream().map(e ->
  468. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  469. .put("date", e.get("Date"))
  470. .put("duration", e.get("Duration"))
  471. .put("structure", e.get("Structure"))
  472. .put("convex", e.get("Convex"))
  473. .put("credit", e.get("Credit"))
  474. .put("hyield", e.get("HYield"))
  475. .put("conv", e.get("Conv"))
  476. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  477. .build()).collect(Collectors.toList());
  478. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", contList1)
  479. .put("chartProductNameMapping", chartMapper12).put("tableProductNameMapping", tableMapper1).build();
  480. Map<String, Object> chart3 = MapUtil.<String, Object>builder("dataset", betaList1)
  481. .put("chartProductNameMapping", chartMapper34).put("tableProductNameMapping", tableMapper3).build();
  482. return MapUtil.<String, Object>builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build();
  483. } catch (Exception e) {
  484. logger.error("债券业绩归因计算错误" + e.getMessage());
  485. return MapUtil.empty();
  486. }
  487. }
  488. @Override
  489. public Map<String, Object> relativeAttribution(RelativeAttributionParams params) {
  490. this.checkParams(params);
  491. try {
  492. Map<String, String> chartMapper2 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  493. .put("market", "市场").put("size", "市值").put("bookToPriceRatio", "账面市值比")
  494. .put("growvalue", "成长").put("hedge", "升贴水").build();
  495. Map<String, String> chartMapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).putAll(chartMapper2).put("rSquared", "R2").build();
  496. Map<String, String> chartMapper4 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).putAll(chartMapper2).put("epsi", "残差").put("alpha", "超额收益").build();
  497. Map<String, String> chartMapper3 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).putAll(chartMapper4).put("rSquared", "R2").build();
  498. Map<String, String> tableMapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("date", "因子系数(%)").putAll(chartMapper1).build();
  499. Map<String, String> tableMapper2 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("date", "").putAll(chartMapper1).build();
  500. Map<String, String> tableMapper3 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("date", "贡献度(%)").putAll(chartMapper3).build();
  501. Map<String, String> tableMapper4 = MapUtil.<String, String>builder(MapUtil.newHashMap(true)).put("date", "").putAll(chartMapper3).build();
  502. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("winlen", params.getWinlen()).put("rw", 0)
  503. .put("returnNo", "None").put("strategy", 5).put("curve_type", 2).build();
  504. PyResBody resBody = this.initiateRequest("GetRelAttribution", params, extParams);
  505. List<Map<String, Object>> sequential = resBody.getSequential();
  506. Map<String, Object> holisticMap = resBody.getHolistic();
  507. Map<String, Object> betaList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  508. .put("date", holisticMap.get("end_date"))
  509. .put("market", holisticMap.get("TMarket"))
  510. .put("size", holisticMap.get("TSize"))
  511. .put("growvalue", holisticMap.get("TGrowvalue"))
  512. .put("hedge", holisticMap.get("THedge"))
  513. .put("bookToPriceRatio", holisticMap.get("TBookToPriceRatio"))
  514. .put("epsi", holisticMap.get("Tepsi"))
  515. .put("alpha", holisticMap.get("Talpha"))
  516. .put("rSquared", this.rsquaredConstraint(holisticMap.get("R_squared")))
  517. .build();
  518. Map<String, Object> contList = MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  519. .put("date", holisticMap.get("end_date"))
  520. .put("market", holisticMap.get("Market"))
  521. .put("size", holisticMap.get("Size"))
  522. .put("growvalue", holisticMap.get("Growvalue"))
  523. .put("hedge", holisticMap.get("Hedge"))
  524. .put("bookToPriceRatio", holisticMap.get("BookToPriceRatio"))
  525. .build();
  526. AtomicReference<Double> intervalYieldRate = new AtomicReference<>(0.);
  527. List<String> rateKeys = ListUtil.toList("TMarket", "TSize", "TGrowvalue", "THedge", "TBookToPriceRatio", "Tepsi", "Talpha");
  528. holisticMap.forEach((k, v) -> {
  529. if (rateKeys.contains(k)) {
  530. intervalYieldRate.updateAndGet(v1 -> v1 + Double.parseDouble(StrUtil.toString(v)));
  531. }
  532. });
  533. tableMapper2.put("date", holisticMap.get("Dateini") + "~" + holisticMap.get("end_date"));
  534. tableMapper4.put("date", holisticMap.get("Dateini") + "~" + holisticMap.get("end_date"));
  535. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", betaList)
  536. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper2, betaList))
  537. .put("tableProductNameMapping", tableMapper2).put("intervalYieldRate", intervalYieldRate).build();
  538. Map<String, Object> chart4 = MapUtil.<String, Object>builder("dataset", contList)
  539. .put("chartProductNameMapping", this.sortMapperAsc(chartMapper4, contList)).put("tableProductNameMapping", tableMapper4).build();
  540. List<Map<String, Object>> betaList1 = sequential.stream().map(e ->
  541. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  542. .put("date", e.get("end_date"))
  543. .put("market", e.get("TMarket"))
  544. .put("size", e.get("TSize"))
  545. .put("growvalue", e.get("TGrowvalue"))
  546. .put("hedge", e.get("THedge"))
  547. .put("bookToPriceRatio", e.get("TBookToPriceRatio"))
  548. .put("epsi", e.get("epsi"))
  549. .put("alpha", e.get("Alpha"))
  550. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  551. .put("tmarket", e.get("TMarket"))
  552. .put("tsize", e.get("TSize"))
  553. .put("tgrowvalue", e.get("TGrowvalue"))
  554. .put("thedge", e.get("THedge"))
  555. .put("tbookToPriceRatio", e.get("TBookToPriceRatio"))
  556. .put("tepsi", e.get("epsi"))
  557. .put("talpha", e.get("Alpha"))
  558. .put("trSquared", this.rsquaredConstraint(e.get("R_squared")))
  559. .build()).collect(Collectors.toList());
  560. List<Map<String, Object>> contList1 = sequential.stream().map(e ->
  561. MapUtil.<String, Object>builder(MapUtil.newHashMap(true))
  562. .put("date", e.get("end_date"))
  563. .put("market", e.get("Market"))
  564. .put("size", e.get("Size"))
  565. .put("growvalue", e.get("Growvalue"))
  566. .put("hedge", e.get("Hedge"))
  567. .put("bookToPriceRatio", e.get("BookToPriceRatio"))
  568. .put("rSquared", this.rsquaredConstraint(e.get("R_squared")))
  569. .put("tmarket", e.get("Market"))
  570. .put("tsize", e.get("Size"))
  571. .put("tgrowvalue", e.get("Growvalue"))
  572. .put("thedge", e.get("Hedge"))
  573. .put("tbookToPriceRatio", e.get("BookToPriceRatio"))
  574. .put("trSquared", this.rsquaredConstraint(e.get("R_squared")))
  575. .build()).collect(Collectors.toList());
  576. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", contList1)
  577. .put("chartProductNameMapping", chartMapper1).put("tableProductNameMapping", tableMapper1).build();
  578. Map<String, Object> chart3 = MapUtil.<String, Object>builder("dataset", betaList1)
  579. .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build();
  580. return MapUtil.<String, Object>builder("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build();
  581. } catch (Exception e) {
  582. logger.error("相对价值业绩归因计算错误" + e.getMessage());
  583. return MapUtil.empty();
  584. }
  585. }
  586. @Override
  587. public FundStyleVO growthValue(GrowthValueParams params) {
  588. this.checkParams(params);
  589. try {
  590. RBSAIndexType indexType = RBSA_MAPPER.get(params.getAllocationIndex());
  591. return getFundStyleVO(params, indexType, params.getConstraint().getId());
  592. } catch (Exception e) {
  593. logger.error("成长价值风格计算错误" + e.getMessage());
  594. return null;
  595. }
  596. }
  597. @Override
  598. public FundStyleVO industryValue(IndustryValueParams params) {
  599. this.checkParams(params);
  600. try {
  601. if (params.getIndustryIndex() == IndustryType.ShenWan && params.getWinlen().compareTo("32") < 0) {
  602. params.setWinlen("36");
  603. }
  604. RBSAIndexType indexType = RBSA_MAPPER.get(params.getIndustryIndex());
  605. return getFundStyleVO(params, indexType, params.getConstraint().getId());
  606. } catch (Exception e) {
  607. logger.error("行业配置风格计算错误" + e.getMessage());
  608. return null;
  609. }
  610. }
  611. @Override
  612. public Map<String, Object> futureFactor(FutureFactorParams params) {
  613. this.checkParams(params);
  614. try {
  615. Map<String, String> mapper = MapUtil.newHashMap(true);
  616. Map<String, String> tableMapper = MapUtil.newHashMap(true);
  617. Map<String, String> tableMapper2 = MapUtil.newHashMap(true);
  618. Map<String, String> tableMapper4 = MapUtil.newHashMap(true);
  619. Map<String, String> tableMapper3 = MapUtil.newHashMap(true);
  620. Map<String, String> chartMapper4 = MapUtil.newHashMap(true);
  621. Map<String, String> chartMapper3 = MapUtil.newHashMap(true);
  622. chartMapper4.put("sp", "特质因子");
  623. chartMapper3.put("sp", "特质因子");
  624. mapper.put("date", "日期");
  625. for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) {
  626. mapper.put(value.getName(), value.getCName());
  627. chartMapper4.put(value.getName(), value.getCName());
  628. chartMapper3.put(value.getName(), value.getCName());
  629. }
  630. tableMapper.putAll(mapper);
  631. tableMapper3.putAll(chartMapper3);
  632. tableMapper.put("r2", "R2");
  633. tableMapper3.put("r2", "R2");
  634. tableMapper2.putAll(mapper);
  635. tableMapper4.put("date", "日期");
  636. tableMapper4.putAll(chartMapper4);
  637. tableMapper4.put("r2", "R2");
  638. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("winlen", params.getWinlen())
  639. .put("indexIds", BarrConstant.FUTURE_INDEXS).build();
  640. PyResBody resBody = this.initiateRequest("futures/style", params, extParams);
  641. List<Map<String, Object>> sequential = resBody.getSequential();
  642. Map<String, Object> holisticMap = resBody.getHolistic();
  643. List<Map<String, Object>> dataset1 = sequential.stream().map(e -> {
  644. Map<String, Object> temp = MapUtil.newHashMap();
  645. for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) {
  646. temp.put("date", e.get("date"));
  647. temp.put(value.getName(), e.get("beta" + value.getNum()));
  648. temp.put("r2", this.rsquaredConstraint(e.get("nav_r_squared")));
  649. }
  650. return temp;
  651. }).collect(Collectors.toList());
  652. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", dataset1)
  653. .put("chartProductNameMapping", mapper).put("tableProductNameMapping", tableMapper).build();
  654. Map<String, Object> dataset20 = MapUtil.newHashMap();
  655. Map<String, Object> dataset41 = MapUtil.newHashMap();
  656. Map<String, Object> dataset42 = MapUtil.newHashMap();
  657. for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) {
  658. dataset41.put(value.getName(), holisticMap.get("nav_coef" + value.getNum()));
  659. dataset42.put(value.getName(), holisticMap.get("vol_coef" + value.getNum()));
  660. dataset20.put(value.getName(), holisticMap.get("beta" + value.getNum()));
  661. }
  662. dataset41.put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared")));
  663. dataset41.put("sp", holisticMap.get("nav_sp"));
  664. dataset42.put("r2", this.rsquaredConstraint(holisticMap.get("vol_r_squared")));
  665. dataset42.put("sp", holisticMap.get("vol_sp"));
  666. dataset20.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date"));
  667. dataset41.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date"));
  668. dataset42.put("date", holisticMap.get("dateini") + "~" + holisticMap.get("end_date"));
  669. tableMapper2.put("date", "统计区间");
  670. tableMapper4.put("date", "统计区间");
  671. Map<String, Object> profit4 = MapUtil.<String, Object>builder("dataset", dataset41)
  672. .put("chartProductNameMapping", this.sortMapper(chartMapper4, dataset41, true))
  673. .put("tableProductNameMapping", tableMapper4).build();
  674. Map<String, Object> risk4 = MapUtil.<String, Object>builder("dataset", dataset42)
  675. .put("chartProductNameMapping", this.sortMapper(chartMapper4, dataset42, true))
  676. .put("tableProductNameMapping", tableMapper4).build();
  677. Map<String, Object> chart4 = MapUtil.<String, Object>builder("profit", profit4).put("risk", risk4).build();
  678. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", dataset20)
  679. .put("chartProductNameMapping", this.sortMapper(mapper, dataset20, true))
  680. .put("tableProductNameMapping", tableMapper2).put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared"))).build();
  681. List<Map<String, Object>> dataset31 = sequential.stream().map(e -> {
  682. Map<String, Object> temp = MapUtil.newHashMap();
  683. temp.put("date", e.get("date"));
  684. temp.put("sp", e.get("nav_sp"));
  685. temp.put("r2", this.rsquaredConstraint(e.get("nav_r_squared")));
  686. for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) {
  687. temp.put(value.getName(), e.get("nav_coef" + value.getNum()));
  688. }
  689. return temp;
  690. }).collect(Collectors.toList());
  691. List<Map<String, Object>> dataset32 = sequential.stream().map(e -> {
  692. Map<String, Object> temp = MapUtil.newHashMap();
  693. temp.put("date", e.get("date"));
  694. temp.put("sp", e.get("vol_sp"));
  695. temp.put("r2", this.rsquaredConstraint(e.get("vol_r_squared")));
  696. for (FutureStyleRespEnum value : FutureStyleRespEnum.values()) {
  697. temp.put(value.getName(), e.get("vol_coef" + value.getNum()));
  698. }
  699. return temp;
  700. }).collect(Collectors.toList());
  701. Map<String, Object> profit3 = MapUtil.<String, Object>builder("dataset", dataset31)
  702. .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build();
  703. Map<String, Object> risk3 = MapUtil.<String, Object>builder("dataset", dataset32)
  704. .put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build();
  705. Map<String, Object> chart3 = MapUtil.<String, Object>builder("profit", profit3).put("risk", risk3).build();
  706. return MapUtil.<String, Object>builder("chart1", chart1).put("chart2", chart2).put("chart4", chart4).put("chart3", chart3).build();
  707. } catch (Exception e) {
  708. logger.error("期货风格归因计算错误" + e.getMessage());
  709. return MapUtil.empty();
  710. }
  711. }
  712. @Override
  713. public CustomRbsaVO customRbsa(CustomRbsaParams params) {
  714. this.checkParams(params);
  715. try {
  716. List<String> ids = params.getIndexIds();
  717. String rfIndex = params.getExcess() == 0 ? "None" : Consts.RISK_OF_FREE;
  718. String indexIds = String.join("_", ids);
  719. String up = ids.stream().map(e -> "1").collect(Collectors.joining("_"));
  720. String down = ids.stream().map(e -> "0").collect(Collectors.joining("_"));
  721. Map<String, Object> extParams = MapUtil.<String, Object>builder()
  722. .put("indexIds", indexIds)
  723. .put("upbounds", up)
  724. .put("downbounds", down)
  725. .put("boundswitch", params.getConstraint().getId())
  726. .put("rfIndex", rfIndex)
  727. .put("rfValue", "None")
  728. .put("constraintvalue", params.getConstraintType() == 1 ? up : up.replaceAll("1", "0"))
  729. .put("constrainttype", params.getConstraintType())
  730. .put("alphacontrol", 0)
  731. .put("style", "F0")
  732. .put("winlen", params.getWinlen())
  733. .put("rw", 0)
  734. .put("dataType", 1)
  735. .put("returnNo", "None")
  736. .put("strategy", 1)
  737. .put("curve_type", 2)
  738. .put("freq", FREQ_MAPPER.get(params.getFrequency()))
  739. .build();
  740. PyReqParam holisticExt = PyReqParam.builder().api("GetCustomRbsa").control(0).taskId("holistic")
  741. .ext(MapUtil.<String, Object>builder("freq", FREQ_MAPPER.get(Frequency.Weekly)).build()).build();
  742. PyReqParam sequentialExt = PyReqParam.builder().api("GetCustomRbsa").control(1).taskId("sequential").build();
  743. List<PyReqParam> pyReqs = ListUtil.of(holisticExt, sequentialExt);
  744. PyResBody resBody = this.initiateRequest(params, extParams, pyReqs);
  745. Map<String, Object> holisticMap = resBody.getHolistic();
  746. List<Map<String, Object>> sequential = resBody.getSequential();
  747. Map<String, String> indexProMap = this.baseInfoService.querySecName(ids);
  748. Map<String, Object> risk = MapUtil.newHashMap(true);
  749. Map<String, Object> profit = MapUtil.newHashMap(true);
  750. indexProMap.forEach((k, v) -> {
  751. int i = ids.indexOf(k) + 1;
  752. risk.put("date", holisticMap.get("date"));
  753. profit.put("date", holisticMap.get("date"));
  754. risk.put(k, MapUtil.getStr(holisticMap, "beta" + i));
  755. profit.put(k, MapUtil.getStr(holisticMap, "cont" + i));
  756. });
  757. CustomRbsaVO.DataSet dataset = new CustomRbsaVO.DataSet(risk, profit);
  758. CustomRbsaVO.Chart2 chart2 = CustomRbsaVO.Chart2.builder().dataset(dataset).chartProductNameMapping(indexProMap)
  759. .r2(this.rsquaredConstraint(MapUtil.getStr(holisticMap, "r_squared"))).build();
  760. List<Map<String, Object>> dataset1 = sequential.stream().map(e -> {
  761. Map<String, Object> temp = MapUtil.newHashMap(true);
  762. temp.put("date", e.get("date"));
  763. temp.put("r2", this.rsquaredConstraint(e.get("r_squared")));
  764. indexProMap.forEach((k, v) -> {
  765. int i = ids.indexOf(k) + 1;
  766. temp.put(k, MapUtil.getStr(e, "beta" + i));
  767. });
  768. return temp;
  769. }).collect(Collectors.toList());
  770. CustomRbsaVO.Chart1 chart1 = CustomRbsaVO.Chart1.builder().dataset(dataset1).chartProductNameMapping(indexProMap).build();
  771. return CustomRbsaVO.builder().chart1(chart1).chart2(chart2).build();
  772. } catch (Exception e) {
  773. logger.error("自定义风格计算错误" + e.getMessage());
  774. return null;
  775. }
  776. }
  777. @Override
  778. public Map<String, Object> barraOverview(BarraStyleParams params) {
  779. this.checkParams(params);
  780. try {
  781. Map<String, String> mapper = MapUtil.newHashMap(true);
  782. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  783. mapper.put(value.getName(), value.getYName());
  784. }
  785. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("winlen", params.getWinlen()).put("benchmarkId", params.getBenchmarkId())
  786. .put("indexIds", BarrConstant.BARRA_FACTOR_INDEXS).put("poolCode", BarrConstant.POOL_CACHE_ALL).put("excess", params.getExcess()).build();
  787. PyReqParam holisticExt = PyReqParam.builder().api("GetBarraSensitivity").control(0).taskId("holistic").build();
  788. PyReqParam sequentialExt = PyReqParam.builder().api("GetBarraSensitivity").control(1).taskId("sequential").build();
  789. PyReqParam factorTrendExt = PyReqParam.builder().api("GetBarraSensitivity").control(2).taskId("factorTrend").build();
  790. List<PyReqParam> pyReqs = ListUtil.of(holisticExt, sequentialExt, factorTrendExt);
  791. PyResBody resBody = this.initiateRequest(params, extParams, pyReqs);
  792. Map<String, Object> holisticMap = resBody.getHolistic();
  793. List<Map<String, Object>> sequential = resBody.getSequential();
  794. List<Map<String, Object>> factorTrend = resBody.getExtBody().get("factorTrend");
  795. List<Map<String, Object>> dataset1 = ListUtil.list(true);
  796. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  797. Map<String, Object> temp = MapUtil.newHashMap();
  798. temp.put("name", value.getCName());
  799. temp.put("product", holisticMap.get("coef" + value.getNum()));
  800. temp.put("standardError", holisticMap.get("std_err" + value.getNum()));
  801. temp.put("t", holisticMap.get("t" + value.getNum()));
  802. temp.put("pt", holisticMap.get("pt" + value.getNum()));
  803. dataset1.add(temp);
  804. }
  805. dataset1.sort((o1, o2) -> MapUtil.getDouble(o2, "product").compareTo(MapUtil.getDouble(o1, "product")));
  806. Map<String, String> mapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  807. .put("name", "名称")
  808. .put("product", "产品敏感度")
  809. .put("standardError", "标准误差")
  810. .put("t", "t")
  811. .put("pt", "p>|t|")
  812. .build();
  813. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", dataset1).put("tableProductNameMapping", mapper1)
  814. .put("r2", this.rsquaredConstraint(holisticMap.get("r_squared"))).build();
  815. Map<String, Object> tableMapper23 = new LinkedHashMap<>();
  816. tableMapper23.put("date", "时段");
  817. tableMapper23.putAll(mapper);
  818. tableMapper23.put("r2", "R2");
  819. List<Map<String, Object>> dataset2 = factorTrend.stream().map(e -> {
  820. Map<String, Object> temp = MapUtil.newHashMap();
  821. temp.put("date", "custom".equals(e.get("dateini")) ? "当前区间" : e.get("dateini") + "年");
  822. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  823. temp.put(value.getName(), e.get("coef" + value.getNum()));
  824. }
  825. temp.put("r2", this.rsquaredConstraint(e.get(BarrConstant.R_SQUARED)));
  826. return temp;
  827. }).collect(Collectors.toList());
  828. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", dataset2).put("tableProductNameMapping", tableMapper23)
  829. .put("chartProductNameMapping", mapper).build();
  830. List<Map<String, Object>> dataset3 = sequential.stream().map(e -> {
  831. Map<String, Object> temp = MapUtil.newHashMap();
  832. temp.put("date", e.get("end_date"));
  833. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  834. temp.put(value.getName(), e.get("coef" + value.getNum()));
  835. }
  836. temp.put("r2", this.rsquaredConstraint(e.get("r_squared")));
  837. return temp;
  838. }).collect(Collectors.toList());
  839. Map<String, Object> chart3 = MapUtil.<String, Object>builder("dataset", dataset3).put("tableProductNameMapping", tableMapper23)
  840. .put("chartProductNameMapping", mapper).build();
  841. return MapUtil.<String, Object>builder().put("chart1", chart1).put("chart2", chart2).put("chart3", chart3).build();
  842. } catch (Exception e) {
  843. logger.error("barra概览计算错误" + e.getMessage());
  844. return MapUtil.empty();
  845. }
  846. }
  847. @Override
  848. public Map<String, Object> barraRiskProfit(BarraStyleParams params) {
  849. this.checkParams(params);
  850. try {
  851. Map<String, String> mapper = MapUtil.newHashMap(true);
  852. Map<String, String> mapperForTable = MapUtil.newHashMap(true);
  853. mapperForTable.put("r2", "R2值");
  854. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  855. mapper.put(value.getName(), value.getCName());
  856. mapperForTable.put(value.getName(), value.getCName());
  857. }
  858. Map<String, String> tableMapper1 = MapUtil.newHashMap(true);
  859. for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) {
  860. tableMapper1.put(value.getKey(), value.getProfit());
  861. }
  862. Map<String, String> chartMapper1 = new LinkedHashMap<>(tableMapper1);
  863. chartMapper1.remove("r2");
  864. Map<String, String> tableMapper3 = MapUtil.newHashMap(true);
  865. tableMapper3.put("date", "时段");
  866. for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) {
  867. tableMapper3.put(value.getKey(), value.getRisk());
  868. }
  869. Map<String, String> chartMapper3 = new LinkedHashMap<>(tableMapper3);
  870. chartMapper3.remove("r2");
  871. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("winlen", params.getWinlen()).put("benchmarkId", params.getBenchmarkId())
  872. .put("indexIds", BarrConstant.BARRA_FACTOR_INDEXS).put("poolCode", BarrConstant.POOL_CACHE_ALL).put("excess", params.getExcess()).build();
  873. PyResBody resBody = this.initiateRequest("GetBarraNavAttribution", params, extParams);
  874. List<Map<String, Object>> sequential = resBody.getSequential();
  875. Map<String, Object> holisticMap = resBody.getHolistic();
  876. // chart1
  877. List<Map<String, Object>> dataset1 = sequential.stream().map(e -> {
  878. Map<String, Object> temp = MapUtil.newHashMap();
  879. temp.put("date", e.get("end_date"));
  880. temp.put("r2", this.rsquaredConstraint(e.get("r_squared")));
  881. for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) {
  882. temp.put(value.getKey(), e.get("nav_" + value.getCode()));
  883. }
  884. return temp;
  885. }).collect(Collectors.toList());
  886. Map<String, Object> chart1 = MapUtil.<String, Object>builder("dataset", dataset1).put("chartProductNameMapping", chartMapper1).put("tableProductNameMapping", tableMapper1).build();
  887. // chart2
  888. List<Map<String, Object>> dataset2 = ListUtil.list(true);
  889. Map<String, Object> temp2 = MapUtil.newHashMap();
  890. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  891. temp2.put(value.getName(), holisticMap.get("nav_cont" + value.getNum()));
  892. }
  893. dataset2.add(temp2);
  894. Map<String, Object> chart2 = MapUtil.<String, Object>builder("dataset", dataset2).put("chartProductNameMapping", this.sortMapperAsc(mapper, dataset2.get(0)))
  895. .put("tableProductNameMapping", mapperForTable).put("r2", this.rsquaredConstraint(holisticMap.get("nav_r_squared"))).build();
  896. // chart3
  897. List<Map<String, Object>> dataset3 = sequential.stream().map(e -> {
  898. Map<String, Object> temp = MapUtil.newHashMap();
  899. temp.put("date", e.get("end_date"));
  900. temp.put("r2", this.rsquaredConstraint(e.get("r_squared")));
  901. for (BarraRiskProfitEnum value : BarraRiskProfitEnum.values()) {
  902. temp.put(value.getKey(), e.get("vol_" + value.getCode()));
  903. }
  904. return temp;
  905. }).collect(Collectors.toList());
  906. Map<String, Object> chart3 = MapUtil.<String, Object>builder("dataset", dataset3).put("chartProductNameMapping", chartMapper3).put("tableProductNameMapping", tableMapper3).build();
  907. // chart4
  908. List<Map<String, Object>> dataset4 = ListUtil.list(true);
  909. Map<String, Object> temp4 = MapUtil.newHashMap();
  910. for (BarraStyleRespEnum value : BarraStyleRespEnum.values()) {
  911. temp4.put(value.getName(), holisticMap.get("vol_cont" + value.getNum()));
  912. }
  913. dataset4.add(temp4);
  914. Map<String, Object> chart4 = MapUtil.<String, Object>builder("dataset", dataset4).put("chartProductNameMapping", this.sortMapperAsc(mapper, dataset4.get(0)))
  915. .put("tableProductNameMapping", mapperForTable).build();
  916. return MapUtil.<String, Object>builder().put("chart1", chart1).put("chart2", chart2).put("chart3", chart3).put("chart4", chart4).build();
  917. } catch (Exception e) {
  918. logger.error("barra风格计算错误" + e.getMessage());
  919. return MapUtil.empty();
  920. }
  921. }
  922. @Override
  923. public Map<String, Object> selectionTiming(SelectionTimingParams params) {
  924. try {
  925. if (!CAL_RANGE_MAPPER.containsKey(params.getWinlen())) throw new APIException("窗口参数非法");
  926. Map<String, String> mapper = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  927. .put("alpha", "选股能力").put("beta", "择时能力").build();
  928. Map<String, String> mapper1 = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  929. .put("range", "统计周期")
  930. .put("alpha", "Alpha(%)")
  931. .put("testAlpha", "T检验(Alpha)")
  932. .put("selectionAlpha", "选股能力(Alpha)")
  933. .put("beta2", "Beta2")
  934. .put("testBeta2", "T检验(Beta2)")
  935. .put("timingBeta2", "择时能力(Beta2)")
  936. .build();
  937. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("model", params.getModel()).put("benchmarkId", params.getBenchmarkId())
  938. .put("calRange", CAL_RANGE_MAPPER.get(params.getWinlen())).build();
  939. PyReqParam holisticExt = PyReqParam.builder().api("GetIndicatorStatsLine").method("get").taskId("holistic").build();
  940. PyReqParam sequentialExt = PyReqParam.builder().api("GetIndicatorStatsTable").method("get").taskId("sequential").control(1).build();
  941. List<PyReqParam> pyReqs = ListUtil.of(holisticExt, sequentialExt);
  942. PyResBody resBody = this.initiateRequest(params, extParams, pyReqs);
  943. List<Map<String, Object>> sequential = resBody.getSequential();
  944. List<Map<String, Object>> holistic = resBody.getExtBody().get("holistic");
  945. List<Map<String, Object>> dataset = holistic.stream().map(e -> MapUtil.builder("date", e.get("range_perid"))
  946. .put("alpha", e.get("alpha_value")).put("beta", e.get("beta2_value")).build()).collect(Collectors.toList());
  947. List<Map<Object, Object>> dataset1 = sequential.stream().filter(e -> !"成立以来".equals(e.get("range_perid"))).map(e ->
  948. MapUtil.builder(MapUtil.newHashMap(true))
  949. .put("range", e.get("range_perid"))
  950. .put("alpha", e.get("alpha"))
  951. .put("testAlpha", e.get("alpha_pvalue"))
  952. .put("selectionAlpha", e.get("stock_selection_ability"))
  953. .put("beta2", e.get("beta2"))
  954. .put("testBeta2", e.get("beta2_pvalue"))
  955. .put("timingBeta2", e.get("market_timing_ability"))
  956. .build()).collect(Collectors.toList());
  957. Map<String, Object> chart = MapUtil.<String, Object>builder().put("dataset", dataset).put("productNameMapping", mapper).build();
  958. Map<String, Object> table = MapUtil.<String, Object>builder().put("dataset", dataset1).put("productNameMapping", mapper1).build();
  959. return MapUtil.<String, Object>builder().put("chart", chart).put("table", table).build();
  960. } catch (Exception e) {
  961. logger.error("选股择时能力计算错误" + e.getMessage());
  962. return MapUtil.empty();
  963. }
  964. }
  965. @Override
  966. @SuppressWarnings("unchecked")
  967. public Map<String, Object> rzStyle(RzStyleParams params) {
  968. try {
  969. List<FundStyleStatsDO> fundStyleStatsList = fundStyleService.listFundStyleOverview(params.getSecId());
  970. List<Map<String, Object>> dataset = ListUtil.list(true);
  971. for (FundStyleStatsDO fundStyleStatsDO : fundStyleStatsList) {
  972. Map<String, Object> tempMap = MapUtil.newHashMap();
  973. tempMap.put("date", fundStyleStatsDO.getEndDate());
  974. tempMap.put("upside", fundStyleStatsDO.getUpsideCaptureRatio1y());
  975. tempMap.put("downside",fundStyleStatsDO.getDownsideCaptureRatio1y());
  976. tempMap.put("style", handleFundStyle(fundStyleStatsDO.getUpsideCaptureRatio1y(),fundStyleStatsDO.getDownsideCaptureRatio1y()));
  977. dataset.add(tempMap);
  978. }
  979. Map<String, String> mapper = MapUtil.<String, String>builder(MapUtil.newHashMap(true))
  980. .put("date", "时间").put("upside", "进攻能力").put("downside", "防御能力").put("style", "风格").build();
  981. Map<String, Object> chart1 = MapUtil.<String, Object>builder().put("dataset", dataset)
  982. .put("chartProductNameMapping", mapper).put("tableProductNameMapping", mapper).build();
  983. List<String> secIdList = ListUtil.list(true);
  984. List<String> fundBenchmarkList = ListUtil.toList(params.getSecId(), params.getBenchmarkId());
  985. List<String> unionIds = CollUtil.addAllIfNotContains(fundBenchmarkList, secIdList);
  986. return MapUtil.<String, Object>builder().put("chart1", chart1).build();
  987. } catch (Exception e) {
  988. logger.error("风格总览计算错误" + e.getMessage());
  989. return MapUtil.empty();
  990. }
  991. }
  992. private String handleFundStyle(BigDecimal upside, BigDecimal downside) {
  993. String style;
  994. BigDecimal standardLevel = BigDecimal.valueOf(0.5);
  995. if (standardLevel.compareTo(upside) <= 0 && standardLevel.compareTo(downside) >= 0) {
  996. style = "攻守兼备型";
  997. } else if (standardLevel.compareTo(upside) > 0 && standardLevel.compareTo(downside) > 0) {
  998. style = "防御型";
  999. } else if (standardLevel.compareTo(upside) < 0 && standardLevel.compareTo(downside) < 0) {
  1000. style = "进攻型";
  1001. } else {
  1002. style = "风格不明显";
  1003. }
  1004. return style;
  1005. }
  1006. /**
  1007. * 成长价值和行业配置接口重构,支持基金、机构、经理、组合等
  1008. *
  1009. * @param params 请求参数
  1010. * @param indexType 因子
  1011. * @param boundSwitch 多空或多头
  1012. * @param <P> 类型参数
  1013. * @return /
  1014. */
  1015. private <P extends BaseParams> FundStyleVO getFundStyleVO(P params, RBSAIndexType indexType, Integer boundSwitch) {
  1016. CurveType curveType = CurveType.getCurveType(params.getRaiseType(), StrategyHandleUtils.getStrategy(params.getStrategy()));
  1017. List<CurveType> strategyList = ListUtil.of(CurveType.PrivateSubstratgy, CurveType.PublicSubstrategy, CurveType.BothSubstratgy);
  1018. int curveTypeId = strategyList.contains(curveType) ? curveType.getId() : 2;
  1019. String indexIds = String.join("_", RBSAIndexTypeMap.getInstance().getIndexIds(indexType));
  1020. Map<String, Object> extParams = MapUtil.<String, Object>builder().put("boundSwitch", boundSwitch)
  1021. .put("indexIds", indexIds).put("strategy", 1).put("curveType", curveTypeId).build();
  1022. PyResBody resBody = this.initiateRequest("fund/style", params, extParams);
  1023. List<Map<String, Object>> sequential = resBody.getSequential();
  1024. Map<String, Object> holisticMap = resBody.getHolistic();
  1025. Map<String, String> indexProMap = RBSA_INDEX_PROD_MAPPER.get(indexType);
  1026. Map<String, Object> risk = MapUtil.newHashMap(true);
  1027. Map<String, Object> profit = MapUtil.newHashMap(true);
  1028. indexProMap.forEach((k, v) -> {
  1029. risk.put("date", holisticMap.get("date"));
  1030. risk.put(k, MapUtil.getStr(holisticMap, k));
  1031. });
  1032. for (int i = 0; i < indexProMap.size(); i++) {
  1033. profit.put("date", holisticMap.get("date"));
  1034. profit.put("beta" + (i + 1), MapUtil.getStr(holisticMap, "cont" + (i + 1)));
  1035. }
  1036. FundStyleVO.DataSet dataset = new FundStyleVO.DataSet(risk, profit);
  1037. FundStyleVO.Chart2 chart2 = FundStyleVO.Chart2.builder().dataset(dataset).chartProductNameMapping(indexProMap)
  1038. .r2(this.rsquaredConstraint(MapUtil.getStr(holisticMap, "r_squared"))).build();
  1039. List<Map<String, Object>> dataset1 = sequential.stream().map(e -> {
  1040. Map<String, Object> temp = MapUtil.newHashMap(true);
  1041. temp.put("date", e.get("date"));
  1042. temp.put("r2", this.rsquaredConstraint(e.get("r_squared")));
  1043. indexProMap.forEach((k, v) -> temp.put(k, MapUtil.getStr(e, k)));
  1044. return temp;
  1045. }).collect(Collectors.toList());
  1046. FundStyleVO.Chart1 chart1 = FundStyleVO.Chart1.builder().dataset(dataset1).chartProductNameMapping(indexProMap).build();
  1047. return FundStyleVO.builder().chart1(chart1).chart2(chart2).build();
  1048. }
  1049. /**
  1050. * 对r2做一个简单的约束,[-1, 1] 之间
  1051. *
  1052. * @param r2 /
  1053. * @return /
  1054. */
  1055. private String rsquaredConstraint(Object r2) {
  1056. if (r2 == null) {
  1057. return null;
  1058. }
  1059. double v = Double.parseDouble(StrUtil.toString(r2));
  1060. if (v < -1d) {
  1061. v = -1d;
  1062. } else if (v > 1d) {
  1063. v = 1d;
  1064. }
  1065. return String.valueOf(v);
  1066. }
  1067. }