IndicatorCalcUtil.java 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. package com.smppw.utils;
  2. import com.smppw.common.cache.CaffeineLocalCache;
  3. import com.smppw.common.pojo.dto.CompoundRet;
  4. import com.smppw.common.pojo.dto.DateValue;
  5. import com.smppw.common.pojo.dto.calc.IndicatorCalcPropertyDto;
  6. import com.smppw.common.pojo.dto.calc.IndicatorCalcTimeRangeDto;
  7. import com.smppw.common.pojo.enums.Frequency;
  8. import com.smppw.common.pojo.enums.Indicator;
  9. import com.smppw.common.pojo.enums.TimeRange;
  10. import com.smppw.common.pojo.enums.TrendType;
  11. import com.smppw.constants.DateConst;
  12. import com.smppw.constants.IndicatorConst;
  13. import com.smppw.core.reta.IndicatorFactory;
  14. import com.smppw.core.reta.Rate;
  15. import com.smppw.core.reta.calc.PerformanceConsistency;
  16. import com.smppw.core.trend.Trend;
  17. import com.smppw.core.trend.TrendFactory;
  18. import org.apache.commons.lang3.StringUtils;
  19. import org.joda.time.DateTime;
  20. import org.joda.time.format.DateTimeFormat;
  21. import java.math.BigDecimal;
  22. import java.util.*;
  23. /**
  24. * @author lzj
  25. */
  26. public class IndicatorCalcUtil {
  27. public static List<Double> getFundRetList(List<CompoundRet> list) {
  28. List<Double> doubleList = new ArrayList<>();
  29. for (CompoundRet value : list) {
  30. if (value.getRetOfFund() != null) {
  31. doubleList.add(value.getRetOfFund());
  32. }
  33. }
  34. return doubleList;
  35. }
  36. public static Map<String, String> calcNavIndicatorValue(List<DateValue> navList, List<Indicator> navIndicatorList) {
  37. IndicatorFactory factory = IndicatorFactory.getInstance();
  38. Map<String, String> navIndicatorValueMap = new HashMap<>();
  39. for (Indicator indicator : navIndicatorList) {
  40. if (null == navList || navList.size() == 0) {
  41. navIndicatorValueMap.put(indicator.name(), null);
  42. continue;
  43. }
  44. Rate rate = factory.get(indicator);
  45. Double navIndicatorValue = null;
  46. try {
  47. navIndicatorValue = rate.calc(navList);
  48. } catch (Exception e) {
  49. // log.error("计算异常Exception",e.getMessage(),e);
  50. navIndicatorValue = null;
  51. }
  52. if(navIndicatorValue != null && navIndicatorValue.isNaN()){
  53. navIndicatorValue = null;
  54. } else if( navIndicatorValue != null ) {
  55. BigDecimal bigDecimalValue = new BigDecimal(navIndicatorValue.toString());
  56. BigDecimal maxBigDecimalValue = new BigDecimal(IndicatorConst.MAX_INDICATOR_VALUE_STRING);
  57. BigDecimal minBigDecimalValue = new BigDecimal(IndicatorConst.MIN_INDICATOR_VALUE_STRING);
  58. if (bigDecimalValue.compareTo(maxBigDecimalValue)>0) {
  59. navIndicatorValueMap.put(indicator.name(), maxBigDecimalValue.toPlainString());
  60. continue;
  61. } else if (bigDecimalValue.compareTo(minBigDecimalValue)<0) {
  62. navIndicatorValueMap.put(indicator.name(), minBigDecimalValue.toPlainString());
  63. continue;
  64. }
  65. }
  66. if (Indicator.INTEGER_VALUE_ARRAY.contains(indicator)) {
  67. navIndicatorValueMap.put(indicator.name(), CommonUtil.double2IntegerString(navIndicatorValue));
  68. } else {
  69. navIndicatorValueMap.put(indicator.name(), CommonUtil.double2StringPoint6WithoutHalfUp(navIndicatorValue));
  70. }
  71. }
  72. convertMaxDrawdownRecureDate(navIndicatorValueMap, navIndicatorList);
  73. return navIndicatorValueMap;
  74. }
  75. private static void convertMaxDrawdownRecureDate(Map<String, String> dataMap, List<Indicator> indicators) {
  76. if (indicators.contains(Indicator.MaxDrawdownRecureDate)) {
  77. String value = dataMap.get(Indicator.MaxDrawdownRecureDate.name());
  78. if (value != null) {
  79. String dateStr = String.valueOf(Double.valueOf(value).intValue());
  80. dataMap.put(Indicator.MaxDrawdownRecureDate.name(), DateTime
  81. .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
  82. }
  83. }
  84. if (indicators.contains(Indicator.MaxDrawdownPeakDate)) {
  85. String value = dataMap.get(Indicator.MaxDrawdownPeakDate.name());
  86. if (value != null) {
  87. String dateStr = String.valueOf(Double.valueOf(value).intValue());
  88. dataMap.put(Indicator.MaxDrawdownPeakDate.name(), DateTime
  89. .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
  90. }
  91. }
  92. if (indicators.contains(Indicator.MaxDrawdownValleyDate)) {
  93. String value = dataMap.get(Indicator.MaxDrawdownValleyDate.name());
  94. if (value != null) {
  95. String dateStr = String.valueOf(Double.valueOf(value).intValue());
  96. dataMap.put(Indicator.MaxDrawdownValleyDate.name(), DateTime
  97. .parse(dateStr, DateTimeFormat.forPattern(DateConst.YYYYMMDD)).toString(DateConst.YYYY_MM_DD));
  98. }
  99. }
  100. }
  101. public static Map<String, String> calcRetIndicatorValue(List<CompoundRet> retList, TimeRange timeRange,
  102. Frequency frequency, boolean ifAnnualize, List<Indicator> retIndicatorList, boolean ifConvertPerformanceConsistencyWord, int leastRetNum) {
  103. Map<String,String> retIndicatorValueMap = new HashMap<>();
  104. IndicatorFactory factory = IndicatorFactory.getInstance();
  105. for (Indicator indicator : retIndicatorList) {
  106. if (indicator == null) {
  107. continue;
  108. }
  109. Double value = null;
  110. if (null == retList) {
  111. retIndicatorValueMap.put(indicator.name(), null);
  112. continue;
  113. }
  114. // update by wangzaijun on 2023-04-06 超额胜率支持
  115. if (indicator.name().startsWith("ExcessReturn") || indicator == Indicator.ExcessAriIntervalReturn || indicator == Indicator.ExcessAnnualAriIntervalReturn || indicator == Indicator.WinRate
  116. || (retList != null && retList.size() >= leastRetNum) || timeRange == TimeRange.FromSetup) {
  117. Rate rate = factory.get(indicator);
  118. try {
  119. value = rate.calc(retList, frequency, ifAnnualize);
  120. } catch (Exception e) {
  121. // log.info("计算异常Exception",e.getMessage(),e);
  122. value = null;
  123. }
  124. if (value != null && (value.isNaN() || value.isInfinite() )) {
  125. value = null;
  126. } else if (value != null) {
  127. BigDecimal bigDecimalValue = new BigDecimal(value.toString());
  128. BigDecimal maxBigDecimalValue = new BigDecimal(IndicatorConst.MAX_INDICATOR_VALUE_STRING);
  129. BigDecimal minBigDecimalValue = new BigDecimal(IndicatorConst.MIN_INDICATOR_VALUE_STRING);
  130. if (bigDecimalValue.compareTo(maxBigDecimalValue) > 0) {
  131. retIndicatorValueMap.put(indicator.name(), maxBigDecimalValue.toPlainString());
  132. continue;
  133. } else if (bigDecimalValue.compareTo(minBigDecimalValue) < 0) {
  134. retIndicatorValueMap.put(indicator.name(), minBigDecimalValue.toPlainString());
  135. continue;
  136. }
  137. }
  138. retIndicatorValueMap.put(indicator.name(), CommonUtil.double2StringPoint6WithoutHalfUp(value));
  139. } else {
  140. retIndicatorValueMap.put(indicator.name(), null);
  141. }
  142. }
  143. convertPerformanceConsistency(retIndicatorList, retIndicatorValueMap, ifConvertPerformanceConsistencyWord);
  144. return retIndicatorValueMap;
  145. }
  146. private static void convertPerformanceConsistency(List<Indicator> retIndicatorList, Map<String, String> retIndicatorValueMap, boolean ifConvertPerformanceConsistencyWord) {
  147. if (retIndicatorList.contains(Indicator.PerformanceConsistency) && ifConvertPerformanceConsistencyWord) {
  148. String value = retIndicatorValueMap.get(Indicator.PerformanceConsistency.name());
  149. if (value != null) {
  150. retIndicatorValueMap.put(Indicator.PerformanceConsistency.name(),
  151. PerformanceConsistency.convert2Word(Double.valueOf(value)));
  152. }
  153. }
  154. }
  155. /**
  156. * 获取标的的有效净值序列
  157. * 截取规则 :
  158. * 开始日期 : 1, timeRange == TimeRange.FromSetup - 开始日期直接用入参的开始日期, 其他timeRange根据下方规则截取
  159. * 2. 如果入参的开始日期有净值, 则开始日期直接用入参的开始日期. 否则先往前找四个交易日, 找不到就往后截
  160. * @param secId 标的ID
  161. * @param indicatorCalcTimeRangeDto 时间区间
  162. * @param allNavMap 净值map
  163. */
  164. public static List<DateValue> getSecIdValidNav(String secId, IndicatorCalcTimeRangeDto indicatorCalcTimeRangeDto, Map<String, List<DateValue>> allNavMap, boolean isTrend, Frequency frequency) {
  165. //标的的净值序列
  166. List<DateValue> secNavList = allNavMap.get(secId);
  167. //标的的净值map key-日期 value-净值
  168. Map<String,Double> secNavMap = new HashMap<>();
  169. //全部的日期序列
  170. List<String> dateList = new ArrayList<>();
  171. for (DateValue dv : secNavList) {
  172. secNavMap.put(dv.getDate(),dv.getValue());
  173. dateList.add(dv.getDate());
  174. }
  175. boolean isValidIndicatorCalcTimeRangeDto = (null != indicatorCalcTimeRangeDto && !StringUtils.isEmpty(indicatorCalcTimeRangeDto.getStartDate()) &&
  176. !StringUtils.isEmpty(indicatorCalcTimeRangeDto.getEndDate()));
  177. if (isValidIndicatorCalcTimeRangeDto) {
  178. TimeRange timeRange = indicatorCalcTimeRangeDto.getTimeRange();
  179. String startDate = indicatorCalcTimeRangeDto.getStartDate();
  180. String endDate = indicatorCalcTimeRangeDto.getEndDate();
  181. //推开始日期
  182. String resultStartDate = null;
  183. if (timeRange == TimeRange.FromSetup || timeRange == TimeRange.Custom) {
  184. resultStartDate = startDate;
  185. } else {
  186. //判断startDate是否有净值
  187. Double startNav = secNavMap.get(startDate);
  188. if (startNav != null) {
  189. resultStartDate = startDate;
  190. } else {
  191. if (frequency == Frequency.Monthly) {
  192. List<String> monthPreDays = indicatorCalcTimeRangeDto.getMonthPreDays();
  193. List<String> monthLaterDays = indicatorCalcTimeRangeDto.getMonthLaterDays();
  194. String preDays = null;
  195. String laterDays = null;
  196. for (String monthPreDay : monthPreDays) {
  197. Double monthPreDayNav = secNavMap.get(monthPreDay);
  198. if (monthPreDayNav != null) {
  199. preDays = monthPreDay;
  200. break;
  201. }
  202. }
  203. for (String monthLaterDay : monthLaterDays) {
  204. Double monthLaterDayNav = secNavMap.get(monthLaterDay);
  205. if (monthLaterDayNav != null) {
  206. laterDays = monthLaterDay;
  207. break;
  208. }
  209. }
  210. if (null != preDays || null != laterDays) {
  211. if (null == preDays) {
  212. resultStartDate = laterDays;
  213. } else if (null == laterDays) {
  214. resultStartDate = preDays;
  215. } else {
  216. String monthLastDate = monthPreDays.get(0);
  217. //获取距离(剔除交易日) 谁近取谁, 同样近取前面的
  218. int laterMonthDateDistance = 1;
  219. for (String monthLaterDay : monthLaterDays) {
  220. if (laterDays.equals(monthLaterDay)) {
  221. break;
  222. } else {
  223. boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(monthLaterDay);
  224. if (isTradingDay) {
  225. laterMonthDateDistance ++;
  226. }
  227. }
  228. }
  229. int thisMonthDateDistance = 0;
  230. for (String monthPreDay : monthPreDays) {
  231. if (preDays.equals(monthPreDay)) {
  232. break;
  233. } else {
  234. boolean isTradingDay = CaffeineLocalCache.getIsTradingDay(monthPreDay);
  235. if (isTradingDay) {
  236. thisMonthDateDistance ++;
  237. }
  238. }
  239. }
  240. if (thisMonthDateDistance <= laterMonthDateDistance) {
  241. resultStartDate = preDays;
  242. } else {
  243. resultStartDate = laterDays;
  244. }
  245. }
  246. }
  247. } else {
  248. // 获取前四个交易日的集合 从大到小排序
  249. List<String> tradingDayList = indicatorCalcTimeRangeDto.getPreDays();
  250. for (String tradingDay : tradingDayList) {
  251. startNav = secNavMap.get(tradingDay);
  252. if (startNav != null) {
  253. resultStartDate = tradingDay;
  254. break;
  255. }
  256. }
  257. }
  258. if (resultStartDate == null) {
  259. //startDate没有净值, 而且前四天的交易日都没有净值
  260. String firstDate = null;
  261. if (secNavList != null && secNavList.size() > 0) {
  262. firstDate = secNavList.get(0).getDate();
  263. }
  264. if (isTrend || (timeRange == TimeRange.FromThisYear && StringUtils.isNotEmpty(firstDate) && firstDate.compareTo(startDate) >= 0)) {
  265. resultStartDate = startDate;
  266. } else {
  267. return new ArrayList<>();
  268. }
  269. }
  270. }
  271. }
  272. indicatorCalcTimeRangeDto.setStartDate(resultStartDate);
  273. List<DateValue> validSecNavList = new ArrayList<>();
  274. //截取净值序列 [resultStartDate,endDate]
  275. //二分法找净值
  276. Integer endIndex = getMostLeftLessNav(dateList, endDate);
  277. Integer startIndex = -1;
  278. if (timeRange != TimeRange.Custom) {
  279. startIndex = getMostRightThanNav(dateList, resultStartDate);
  280. } else {
  281. startIndex = getMostLeftLessNav(dateList, resultStartDate);
  282. }
  283. if (startIndex == -1 || endIndex == -1 || startIndex >= endIndex) {
  284. return new ArrayList<>();
  285. }
  286. List<DateValue> dateValues = secNavList.subList(startIndex, endIndex + 1);
  287. if (dateValues.size() == 0) {
  288. return dateValues;
  289. }
  290. if ( dateValues.get(0).getIsvalid() == null || dateValues.get(0).getIsvalid() == 0 ) {
  291. dateValues.get(0).setIsvalid(1);
  292. }
  293. if (dateValues.get(dateValues.size() - 1).getIsvalid() == null || dateValues.get(dateValues.size() - 1).getIsvalid() == 0) {
  294. dateValues.get(dateValues.size() - 1).setIsvalid(1);
  295. }
  296. for (DateValue dateValue : dateValues) {
  297. if (dateValue.getIsvalid() != null && dateValue.getIsvalid() == 1) {
  298. DateValue validSecNav = new DateValue();
  299. validSecNav.setIsvalid(dateValue.getIsvalid());
  300. validSecNav.setValue(dateValue.getValue());
  301. validSecNav.setDate(dateValue.getDate());
  302. validSecNavList.add(validSecNav);
  303. }
  304. }
  305. return validSecNavList;
  306. } else {
  307. return new ArrayList<>();
  308. }
  309. }
  310. /**
  311. * 循环净值序列, 拿出日期序列 排序, 从小到大
  312. * @param navList 净值序列
  313. * @return 日期序列
  314. */
  315. public static List<String> getValidSecNavDateList(List<DateValue> navList) {
  316. List<String> validSecNavDateList = new ArrayList<>();
  317. for (DateValue dateValue : navList) {
  318. validSecNavDateList.add(dateValue.getDate());
  319. }
  320. //排序, 从小到大
  321. Collections.sort(validSecNavDateList);
  322. return validSecNavDateList;
  323. }
  324. /**
  325. * 更近入参的时间序列筛选净值序列
  326. * @param navList 净值序列
  327. * @param dateList 时间序列
  328. * @return 有效净值序列
  329. */
  330. public static List<DateValue> filterOtherNav(List<DateValue> navList, List<String> dateList, boolean isTrendIndex) {
  331. if (null != navList && navList.size() > 0) {
  332. Map<String, DateValue> dateNavMap = new HashMap<>();
  333. for (DateValue nav : navList) {
  334. dateNavMap.put(nav.getDate(), nav);
  335. }
  336. List<DateValue> validNavList = new ArrayList<>();
  337. for (int i = 0 ; i < dateList.size() ; i++) {
  338. DateValue dateValue = new DateValue();
  339. dateValue.setDate(dateList.get(i));
  340. Double value = null;
  341. if (dateNavMap.containsKey(dateList.get(i))) {
  342. value = dateNavMap.get(dateList.get(i)).getValue();
  343. } else if (!isTrendIndex || i == 0) {
  344. //二分法获取小于等于的最接近这个日期的净值
  345. DateValue lessDateValue = getMostLeftNoLessNav(navList, dateList.get(i));
  346. value = lessDateValue.getValue();
  347. }
  348. dateValue.setValue(value);
  349. dateValue.setIsvalid(1);
  350. validNavList.add(dateValue);
  351. }
  352. return validNavList;
  353. }
  354. return new ArrayList<>();
  355. }
  356. /**
  357. *
  358. * @param navList 从小到大的净值序列
  359. * @param date 日期
  360. * @return 小于等于 date 的 日期最大的净值
  361. */
  362. private static DateValue getMostLeftNoLessNav(List<DateValue> navList, String date) {
  363. if (navList == null || navList.size() == 0) {
  364. return new DateValue();
  365. }
  366. int L = 0;
  367. int R = navList.size() - 1;
  368. int ans = -1;
  369. while (L <= R) {
  370. int mid = (L + R) / 2;
  371. if (navList.get(mid).getDate() !=null && navList.get(mid).getDate().compareTo(date) <= 0) {
  372. ans = mid;
  373. L = mid + 1;
  374. } else {
  375. R = mid - 1;
  376. }
  377. }
  378. return ans == -1 ? new DateValue(date, null) : navList.get(ans);
  379. }
  380. /**
  381. *
  382. * @param dateList 从小到大的净值序列
  383. * @param date 日期
  384. * @return 小于等于 date 的 日期最大的净值
  385. */
  386. public static Integer getMostLeftLessNav(List<String> dateList, String date) {
  387. if (dateList == null || dateList.size() == 0) {
  388. return -1;
  389. }
  390. int L = 0;
  391. int R = dateList.size() - 1;
  392. int ans = -1;
  393. while (L <= R) {
  394. int mid = (L + R) / 2;
  395. if (dateList.get(mid) !=null && dateList.get(mid).compareTo(date) <= 0) {
  396. ans = mid;
  397. L = mid + 1;
  398. } else {
  399. R = mid - 1;
  400. }
  401. }
  402. return ans;
  403. }
  404. /**
  405. *
  406. * @param dateList 从小到大的净值序列
  407. * @param date 日期
  408. * @return 大于等于 date 的 日期最小的净值
  409. */
  410. public static Integer getMostRightThanNav(List<String> dateList, String date) {
  411. if(dateList == null || Objects.requireNonNull(dateList).size() == 0){
  412. return -1;
  413. }else if(dateList.get(dateList.size()-1).compareTo(date) < 0){
  414. return dateList.size() - 1;
  415. }
  416. int low = 0;
  417. int high = dateList.size() - 1;
  418. while(low < high){
  419. //防止溢出
  420. int mid = low + (high-low)/2;
  421. if(dateList.get(mid).compareTo(date) < 0){
  422. low = mid + 1;
  423. }else{
  424. high = mid;
  425. }
  426. }
  427. return low;
  428. }
  429. /**
  430. * 获取收益
  431. * @param navList
  432. * @param benchmarkRetList
  433. * @param riskFreeDateRetMap
  434. * @param strategyDateRetMap
  435. * @return
  436. */
  437. public static List<CompoundRet> getRet(List<DateValue> navList, List<CompoundRet> benchmarkRetList, Map<String, CompoundRet> riskFreeDateRetMap, Map<String, CompoundRet> strategyDateRetMap) {
  438. return getRet(navList, benchmarkRetList, riskFreeDateRetMap, strategyDateRetMap, false);
  439. }
  440. /**
  441. * 获取收益
  442. * @param navList
  443. * @param benchmarkRetList
  444. * @param riskFreeDateRetMap
  445. * @param strategyDateRetMap
  446. * @return
  447. */
  448. public static List<CompoundRet> getRet(List<DateValue> navList, List<CompoundRet> benchmarkRetList, Map<String, CompoundRet> riskFreeDateRetMap, Map<String, CompoundRet> strategyDateRetMap, Boolean isTrend) {
  449. List<CompoundRet> retList = new ArrayList<>();
  450. if (navList == null || navList.size() == 0) {
  451. return retList;
  452. }
  453. //排序 从小到大
  454. Collections.sort(navList, new Comparator<DateValue>() {
  455. @Override
  456. public int compare(DateValue o1, DateValue o2) {
  457. return o1.getDate().compareTo(o2.getDate());
  458. }
  459. });
  460. Map<String, CompoundRet> benchmarkRetMap = new HashMap<>();
  461. if (benchmarkRetList != null) {
  462. for (CompoundRet benchmarkRet : benchmarkRetList) {
  463. benchmarkRetMap.put(benchmarkRet.getEndDate(), benchmarkRet);
  464. }
  465. }
  466. Double preNav = 0.0;
  467. for (int i = 0 ; i < navList.size() ; i++) {
  468. CompoundRet compoundRet = new CompoundRet();
  469. Double ret = null;
  470. if (i == 0 && isTrend && navList.get(0).getValue() != null) {
  471. ret = 0.0;
  472. }
  473. String date = navList.get(i).getDate();
  474. compoundRet.setEndDate(date);
  475. if ( i != 0 ) {
  476. Double nav = navList.get(i).getValue();
  477. if (preNav != null && nav!= null) {
  478. BigDecimal preNavBigDecimal = new BigDecimal(preNav.toString());
  479. BigDecimal navBigDecimal = new BigDecimal(nav.toString());
  480. BigDecimal bigDecimalRet = BigDecimalUtils.subtract(BigDecimalUtils.divide(navBigDecimal, preNavBigDecimal), new BigDecimal("1"));
  481. if (null != bigDecimalRet) {
  482. ret = bigDecimalRet.doubleValue();
  483. }
  484. if (null != riskFreeDateRetMap) {
  485. compoundRet.setRetOfRf(riskFreeDateRetMap.get(date) != null ? riskFreeDateRetMap.get(date).getRetOfFund() : null);
  486. }
  487. if (null != strategyDateRetMap) {
  488. compoundRet.setRetOfStg(strategyDateRetMap.get(date) != null ? strategyDateRetMap.get(date).getRetOfFund() : null);
  489. }
  490. if (benchmarkRetList != null) {
  491. compoundRet.setRetOfBmk(benchmarkRetMap.get(date) != null ? benchmarkRetMap.get(date).getRetOfFund() : null);
  492. }
  493. }
  494. }
  495. compoundRet.setRetOfFund(ret);
  496. retList.add(compoundRet);
  497. if (isTrend) {
  498. if (preNav == null || preNav.compareTo(0.0) == 0) {
  499. preNav = navList.get(i).getValue();
  500. }
  501. } else {
  502. preNav = navList.get(i).getValue();
  503. }
  504. }
  505. return retList;
  506. }
  507. public static List<CompoundRet> calcExtraRetGeo(List<CompoundRet> secRetList, List<CompoundRet> benchmarkRetList) {
  508. List<CompoundRet> extraRetAriList = new ArrayList<>();
  509. Map<String, CompoundRet> benchmarkRetMap = new HashMap<>();
  510. for (CompoundRet compoundRet : benchmarkRetList) {
  511. benchmarkRetMap.put(compoundRet.getEndDate(), compoundRet);
  512. }
  513. for (CompoundRet compoundRet : secRetList) {
  514. CompoundRet extraRetAri = new CompoundRet();
  515. Double secRet = compoundRet.getRetOfFund();
  516. CompoundRet benchmarkRetDto = benchmarkRetMap.get(compoundRet.getEndDate());
  517. if (null == benchmarkRetDto || null ==secRet || benchmarkRetDto.getRetOfFund() == null ) {
  518. extraRetAri.setEndDate(compoundRet.getEndDate());
  519. extraRetAri.setRetOfFund(null);
  520. } else if (benchmarkRetDto.getRetOfFund().compareTo(0.0) == 0) {
  521. extraRetAri.setEndDate(compoundRet.getEndDate());
  522. extraRetAri.setRetOfFund(0.0);
  523. } else {
  524. Double molecule = secRet + 1;
  525. Double denominator = benchmarkRetDto.getRetOfFund() + 1;
  526. Double benchmarkRet = BigDecimalUtils.subtract(BigDecimalUtils.divide(new BigDecimal(molecule), new BigDecimal(denominator)), new BigDecimal("1")).doubleValue();
  527. extraRetAri.setEndDate(compoundRet.getEndDate());
  528. extraRetAri.setRetOfFund(benchmarkRet);
  529. }
  530. extraRetAriList.add(extraRetAri);
  531. }
  532. return extraRetAriList;
  533. }
  534. public static void getTrendData(IndicatorCalcPropertyDto indicatorCalcPropertyDto) {
  535. List<TrendType> trendTypeList = indicatorCalcPropertyDto.getIndicatorCalcReq().getTrendTypeList();
  536. List<CompoundRet> benchmarkRetList = null;
  537. if (indicatorCalcPropertyDto.getIndicatorCalcReq().getFixedIncome() != null) {
  538. benchmarkRetList = new ArrayList<>();
  539. List<CompoundRet> retList = indicatorCalcPropertyDto.getSecData().getRetList();
  540. for (CompoundRet ret : retList) {
  541. CompoundRet bRet = new CompoundRet();
  542. bRet.setEndDate(ret.getEndDate());
  543. bRet.setRetOfFund(BigDecimalUtils.divide(indicatorCalcPropertyDto.getIndicatorCalcReq().getFixedIncome(), new BigDecimal("100")).doubleValue());
  544. benchmarkRetList.add(bRet);
  545. }
  546. } else {
  547. benchmarkRetList = indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkRetList();
  548. }
  549. for (TrendType trendType : trendTypeList) {
  550. TrendFactory trendFactory = TrendFactory.getInstance();
  551. Trend trend = trendFactory.get(trendType);
  552. //标的的走势数据 - start
  553. if (TrendType.Nav == trendType) {
  554. List<DateValue> navList = trend.getDateValueTrend(null, indicatorCalcPropertyDto.getSecData().getNavList(), null);
  555. indicatorCalcPropertyDto.getSecData().setNavList(navList);
  556. List<Double> trendList = datevalueToDouble(navList);
  557. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  558. } else if (TrendType.Ret == trendType) {
  559. List<CompoundRet> retList = trend.getCompoundRetTrend(indicatorCalcPropertyDto.getSecData().getNavList(), null, null);
  560. indicatorCalcPropertyDto.getSecData().setRetList(retList);
  561. List<Double> trendList = compoundRetToDouble(retList);
  562. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  563. } else if (TrendType.ExtraNav == trendType) {
  564. List<DateValue> extraNavList = trend.getDateValueTrend(null, indicatorCalcPropertyDto.getSecData().getNavList(), indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkNavList());
  565. indicatorCalcPropertyDto.getSecData().setExtraNavList(extraNavList);
  566. List<Double> trendList = datevalueToDouble(extraNavList);
  567. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  568. } else if (TrendType.ExtraRetAri == trendType ) {
  569. List<CompoundRet> extraRetList = trend.getCompoundRetTrend(null, indicatorCalcPropertyDto.getSecData().getRetList(), benchmarkRetList);
  570. indicatorCalcPropertyDto.getSecData().setExtraRetAriList(extraRetList);
  571. List<Double> trendList = compoundRetToDouble(extraRetList);
  572. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  573. } else if (TrendType.ExtraRetGeo == trendType ) {
  574. List<CompoundRet> extraRetList = trend.getCompoundRetTrend(null, indicatorCalcPropertyDto.getSecData().getRetList(), benchmarkRetList);
  575. indicatorCalcPropertyDto.getSecData().setExtraRetGeoList(extraRetList);
  576. List<Double> trendList = compoundRetToDouble(extraRetList);
  577. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  578. } else if (TrendType.DrawdownTrend == trendType) {
  579. List<DateValue> drawDownValueList = trend.getDateValueTrend(indicatorCalcPropertyDto.getDateList(), indicatorCalcPropertyDto.getSecData().getNavList(), null);
  580. indicatorCalcPropertyDto.getSecData().setDrawdownList(drawDownValueList);
  581. List<Double> trendList = datevalueToDouble(drawDownValueList);
  582. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  583. } else if (TrendType.ExtraDrawdownTrend == trendType) {
  584. List<DateValue> extraDrawDownValueList = trend.getDateValueTrend(indicatorCalcPropertyDto.getDateList(),
  585. indicatorCalcPropertyDto.getSecData().getNavList(), indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkNavList());
  586. indicatorCalcPropertyDto.getSecData().setDrawdownList(extraDrawDownValueList);
  587. List<Double> trendList = datevalueToDouble(extraDrawDownValueList);
  588. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  589. } else if (TrendType.NetValueChange == trendType) {
  590. List<CompoundRet> netValueChangeList = trend.getCompoundRetTrend(indicatorCalcPropertyDto.getSecData().getNavList(), null, null);
  591. List<Double> trendList = compoundRetToDouble(netValueChangeList);
  592. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  593. } else if (TrendType.OrigNav == trendType) {
  594. List<DateValue> navList = trend.getDateValueTrend(null, indicatorCalcPropertyDto.getSecData().getOriNavList(), null);
  595. indicatorCalcPropertyDto.getSecData().setNavList(navList);
  596. List<Double> trendList = datevalueToDouble(navList);
  597. indicatorCalcPropertyDto.getSecData().getTrendValueMap().put(trendType, trendList);
  598. }
  599. //标的的走势数据 - end
  600. //基准 和 指数 的走势数据 - start
  601. List<String> indexIdList = indicatorCalcPropertyDto.getIndicatorCalcReq().getIndexIdList();
  602. if (TrendType.Nav == trendType || TrendType.ExtraNav == trendType) {
  603. Trend navTrend = trendFactory.get(TrendType.Nav);
  604. List<DateValue> benchmarkNavList = navTrend.getDateValueTrend(null, indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkNavList(), null);
  605. indicatorCalcPropertyDto.getBenchmarkData().setBenchmarkNavList(benchmarkNavList);
  606. List<Double> benchmarkTrendList = datevalueToDouble(benchmarkNavList);
  607. indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkTrendValueMap().put(TrendType.Nav, benchmarkTrendList);
  608. Map<String, List<DateValue>> indexNavMap = new HashMap<>();
  609. for (String index : indexIdList) {
  610. List<DateValue> indexNavList = navTrend.getDateValueTrend(null, indicatorCalcPropertyDto.getIndexData().getIndexNavMap().get(index), null);
  611. indexNavMap.put(index, indexNavList);
  612. List<Double> indexTrendList = datevalueToDouble(indexNavList);
  613. Map<String, Map<TrendType, List<Double>>> indexTrendValueMapMap = indicatorCalcPropertyDto.getIndexData().getIndexTrendValueMap();
  614. if (indexTrendValueMapMap.containsKey(index)) {
  615. indexTrendValueMapMap.get(index).put(TrendType.Nav,indexTrendList);
  616. } else {
  617. Map<TrendType, List<Double>> indexTrendValueMap = new HashMap<>();
  618. indexTrendValueMap.put(TrendType.Nav, indexTrendList);
  619. indexTrendValueMapMap.put(index, indexTrendValueMap);
  620. }
  621. }
  622. indicatorCalcPropertyDto.getIndexData().setIndexNavMap(indexNavMap);
  623. } else if (TrendType.Ret == trendType || TrendType.ExtraRetAri == trendType || TrendType.ExtraRetGeo == trendType) {
  624. Trend retTrend = trendFactory.get(TrendType.Ret);
  625. List<CompoundRet> retList = retTrend.getCompoundRetTrend(indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkNavList(), null, null);
  626. indicatorCalcPropertyDto.getBenchmarkData().setBenchmarkRetList(retList);
  627. List<Double> benchmarkTrendList = compoundRetToDouble(retList);
  628. indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkTrendValueMap().put(TrendType.Ret, benchmarkTrendList);
  629. Map<String, List<CompoundRet>> indexRetListMap = new HashMap<>();
  630. for (String index : indexIdList) {
  631. List<CompoundRet> indexRetList = retTrend.getCompoundRetTrend(indicatorCalcPropertyDto.getIndexData().getIndexNavMap().get(index), null, null);
  632. indexRetListMap.put(index, indexRetList);
  633. List<Double> indexTrendList = compoundRetToDouble(indexRetList);
  634. Map<String, Map<TrendType, List<Double>>> indexTrendValueMapMap = indicatorCalcPropertyDto.getIndexData().getIndexTrendValueMap();
  635. if (indexTrendValueMapMap.containsKey(index)) {
  636. indexTrendValueMapMap.get(index).put(TrendType.Ret,indexTrendList);
  637. } else {
  638. Map<TrendType, List<Double>> indexTrendValueMap = new HashMap<>();
  639. indexTrendValueMap.put(TrendType.Ret, indexTrendList);
  640. indexTrendValueMapMap.put(index, indexTrendValueMap);
  641. }
  642. }
  643. indicatorCalcPropertyDto.getIndexData().setIndexRetListMap(indexRetListMap);
  644. } else if (TrendType.DrawdownTrend == trendType || TrendType.ExtraDrawdownTrend == trendType) {
  645. Trend drawdownTrendTrend = trendFactory.get(TrendType.DrawdownTrend);
  646. List<DateValue> benchmarkDrawDownValueList = drawdownTrendTrend.getDateValueTrend(indicatorCalcPropertyDto.getDateList(), indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkNavList(), null);
  647. indicatorCalcPropertyDto.getBenchmarkData().setBenchmarkDrawdown(benchmarkDrawDownValueList);
  648. List<Double> benchmarkTrendList = datevalueToDouble(benchmarkDrawDownValueList);
  649. indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkTrendValueMap().put(TrendType.DrawdownTrend, benchmarkTrendList);
  650. Map<String, List<DateValue>> indexDrawdownMap = new HashMap<>();
  651. for (String index : indexIdList) {
  652. List<DateValue> indexDrawDownValueList = drawdownTrendTrend.getDateValueTrend(indicatorCalcPropertyDto.getDateList(), indicatorCalcPropertyDto.getIndexData().getIndexNavMap().get(index), null);
  653. indexDrawdownMap.put(index, indexDrawDownValueList);
  654. List<Double> indexTrendList = datevalueToDouble(indexDrawDownValueList);
  655. Map<String, Map<TrendType, List<Double>>> indexTrendValueMapMap = indicatorCalcPropertyDto.getIndexData().getIndexTrendValueMap();
  656. if (indexTrendValueMapMap.containsKey(index)) {
  657. indexTrendValueMapMap.get(index).put(TrendType.DrawdownTrend,indexTrendList);
  658. } else {
  659. Map<TrendType, List<Double>> indexTrendValueMap = new HashMap<>();
  660. indexTrendValueMap.put(TrendType.DrawdownTrend, indexTrendList);
  661. indexTrendValueMapMap.put(index, indexTrendValueMap);
  662. }
  663. }
  664. indicatorCalcPropertyDto.getIndexData().setIndexDrawdownMap(indexDrawdownMap);
  665. } else if (TrendType.OrigNav == trendType) {
  666. Trend navTrend = trendFactory.get(TrendType.Nav);
  667. List<DateValue> benchmarkNavList = navTrend.getDateValueTrend(null, indicatorCalcPropertyDto.getBenchmarkData().getOriBenchmarkNavList(), null);
  668. indicatorCalcPropertyDto.getBenchmarkData().setOriBenchmarkNavList(benchmarkNavList);
  669. List<Double> benchmarkTrendList = datevalueToDouble(benchmarkNavList);
  670. indicatorCalcPropertyDto.getBenchmarkData().getBenchmarkTrendValueMap().put(TrendType.OrigNav, benchmarkTrendList);
  671. Map<String, List<DateValue>> indexNavMap = new HashMap<>();
  672. for (String index : indexIdList) {
  673. List<DateValue> indexNavList = navTrend.getDateValueTrend(null, indicatorCalcPropertyDto.getIndexData().getOriIndexNavMap().get(index), null);
  674. indexNavMap.put(index, indexNavList);
  675. List<Double> indexTrendList = datevalueToDouble(indexNavList);
  676. Map<String, Map<TrendType, List<Double>>> indexTrendValueMapMap = indicatorCalcPropertyDto.getIndexData().getIndexTrendValueMap();
  677. if (indexTrendValueMapMap.containsKey(index)) {
  678. indexTrendValueMapMap.get(index).put(TrendType.OrigNav,indexTrendList);
  679. } else {
  680. Map<TrendType, List<Double>> indexTrendValueMap = new HashMap<>();
  681. indexTrendValueMap.put(TrendType.OrigNav, indexTrendList);
  682. indexTrendValueMapMap.put(index, indexTrendValueMap);
  683. }
  684. }
  685. indicatorCalcPropertyDto.getIndexData().setOriIndexNavMap(indexNavMap);
  686. }
  687. //基准 和 指数 的走势数据 - end
  688. }
  689. }
  690. public static List<DateValue> navNormalize(List<DateValue> dateValueList) {
  691. Double firstValue = null;
  692. List<DateValue> navNormalizeList = new ArrayList<>();
  693. for (DateValue dateValue : dateValueList) {
  694. DateValue navNormalize = new DateValue();
  695. navNormalize.setDate(dateValue.getDate());
  696. navNormalize.setIsvalid(dateValue.getIsvalid());
  697. if (dateValue.getValue() == null || dateValue.getValue().compareTo(0.0) == 0) {
  698. navNormalize.setValue(0.0);
  699. } else {
  700. if (firstValue == null) {
  701. firstValue = dateValue.getValue();
  702. }
  703. navNormalize.setValue(dateValue.getValue() / firstValue);
  704. }
  705. navNormalizeList.add(navNormalize);
  706. }
  707. return navNormalizeList;
  708. }
  709. private static List<Double> datevalueToDouble(List<DateValue> dateValueList) {
  710. List<Double> doubles = new ArrayList<>();
  711. for (DateValue dateValue : dateValueList) {
  712. doubles.add(dateValue.getValue());
  713. }
  714. return doubles;
  715. }
  716. private static List<Double> compoundRetToDouble(List<CompoundRet> list) {
  717. List<Double> doubles = new ArrayList<>();
  718. for (CompoundRet compoundRet : list) {
  719. doubles.add(compoundRet.getRetOfFund());
  720. }
  721. return doubles;
  722. }
  723. }