task_fundPerformance.dos 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. module fundit::task_fundPerformance
  2. use fundit::sqlUtilities;
  3. use fundit::dataPuller;
  4. use fundit::dataSaver;
  5. use fundit::returnCalculator;
  6. use fundit::indicatorCalculator;
  7. use fundit::fundCalculator;
  8. use fundit::bfiMatcher;
  9. /*
  10. * 按照 XXX_performance 表结构准备数据记录
  11. *
  12. *
  13. */
  14. def generate_entity_performance(entity_info, indicators, isToMySQL, mutable entity_performance) {
  15. t = null;
  16. if(isToMySQL) {
  17. if(indicators['PBI-3M'].isVoid() || indicators['PBI-3M'].size() == 0) return;
  18. t = SELECT entity_id, end_date, price_date, nav AS cumulative_nav, ret AS ret_1m, ret AS ret_1m_a, trailing_ret AS ret_3m, trailing_ret_a AS ret_3m_a
  19. FROM indicators['PBI-3M'] AS ind
  20. INNER JOIN entity_info fi ON ind.entity_id = fi.entity_id
  21. WHERE ind.end_date >= fi.price_date.month(); // 过滤掉不必更新的旧记录
  22. UPDATE t
  23. SET ret_6m = trailing_ret, ret_6m_a = trailing_ret_a
  24. FROM ej(t, indicators['PBI-6M'], ['entity_id', 'end_date']);
  25. UPDATE t
  26. SET ret_1y = trailing_ret, ret_1y_a = trailing_ret_a
  27. FROM ej(t, indicators['PBI-1Y'], ['entity_id', 'end_date']);
  28. UPDATE t
  29. SET ret_2y = trailing_ret, ret_2y_a = trailing_ret_a
  30. FROM ej(t, indicators['PBI-2Y'], ['entity_id', 'end_date']);
  31. UPDATE t
  32. SET ret_3y = trailing_ret, ret_3y_a = trailing_ret_a
  33. FROM ej(t, indicators['PBI-3Y'], ['entity_id', 'end_date']);
  34. UPDATE t
  35. SET ret_4y = trailing_ret, ret_4y_a = trailing_ret_a
  36. FROM ej(t, indicators['PBI-4Y'], ['entity_id', 'end_date']);
  37. UPDATE t
  38. SET ret_5y = trailing_ret, ret_5y_a = trailing_ret_a
  39. FROM ej(t, indicators['PBI-5Y'], ['entity_id', 'end_date']);
  40. UPDATE t
  41. SET ret_10y = trailing_ret, ret_10y_a = trailing_ret_a
  42. FROM ej(t, indicators['PBI-10Y'], ['entity_id', 'end_date']);
  43. UPDATE t
  44. SET ret_ytd = trailing_ret, ret_ytd_a = trailing_ret_a
  45. FROM ej(t, indicators['PBI-YTD'], ['entity_id', 'end_date']);
  46. // 取消了 ret_incep_a_all (没意义) 和 ret_incep_a_gips (ret_incep_a 与之相等)
  47. UPDATE t
  48. SET ret_incep = trailing_ret, ret_incep_a = trailing_ret_a
  49. FROM ej(t, indicators['PBI-INCEP'], ['entity_id', 'end_date']);
  50. INSERT INTO entity_performance SELECT * FROM t;
  51. } else {
  52. }
  53. }
  54. /*
  55. * 按照 XXX_risk_stats 表结构准备数据记录
  56. *
  57. *
  58. */
  59. def generate_entity_risk_stats(entity_info, indicators, isToMySQL, mutable entity_risk_stats) {
  60. t = null;
  61. if(indicators['PBI-6M'].isVoid() || indicators['PBI-6M'].size() == 0) return;
  62. if(isToMySQL) {
  63. t = SELECT entity_id, end_date, std_dev_a AS stddev_6m, ds_dev_a AS downsidedev_6m, alpha_a AS alpha_6m, winrate AS winrate_6m, beta AS beta_6m,
  64. skewness AS skewness_6m, kurtosis AS kurtosis_6m, wrst_month AS worstmonth_6m, drawdown AS maxdrawdown_6m // mfdb中的真实字段名是 6m_maxdrawdown
  65. FROM indicators['PBI-6M'] AS ind
  66. INNER JOIN entity_info fi ON ind.entity_id = fi.entity_id
  67. WHERE ind.end_date >= fi.price_date.month(); // 过滤掉不必更新的旧记录
  68. UPDATE t
  69. SET stddev_1y = std_dev_a, downsidedev_1y = ds_dev_a, alpha_1y = alpha_a, winrate_1y = winrate, beta_1y = beta,
  70. skewness_1y = skewness, kurtosis_1y = kurtosis, worstmonth_1y = wrst_month, maxdrawdown_1y = drawdown
  71. FROM ej(t, indicators['PBI-1Y'], ['entity_id', 'end_date']);
  72. UPDATE t
  73. SET stddev_2y = std_dev_a, downsidedev_2y = ds_dev_a, alpha_2y = alpha_a, winrate_2y = winrate, beta_2y = beta,
  74. skewness_2y = skewness, kurtosis_2y = kurtosis, worstmonth_2y = wrst_month, maxdrawdown_2y = drawdown
  75. FROM ej(t, indicators['PBI-2Y'], ['entity_id', 'end_date']);
  76. UPDATE t
  77. SET stddev_3y = std_dev_a, downsidedev_3y = ds_dev_a, alpha_3y = alpha_a, winrate_3y = winrate, beta_3y = beta,
  78. skewness_3y = skewness, kurtosis_3y = kurtosis, worstmonth_3y = wrst_month, maxdrawdown_3y = drawdown
  79. FROM ej(t, indicators['PBI-3Y'], ['entity_id', 'end_date']);
  80. UPDATE t
  81. SET stddev_4y = std_dev_a, downsidedev_4y = ds_dev_a, alpha_4y = alpha_a, winrate_4y = winrate, beta_4y = beta,
  82. skewness_4y = skewness, kurtosis_4y = kurtosis, worstmonth_4y = wrst_month, maxdrawdown_4y = drawdown
  83. FROM ej(t, indicators['PBI-4Y'], ['entity_id', 'end_date']);
  84. UPDATE t
  85. SET stddev_5y = std_dev_a, downsidedev_5y = ds_dev_a, alpha_5y = alpha_a, winrate_5y = winrate, beta_5y = beta,
  86. skewness_5y = skewness, kurtosis_5y = kurtosis, worstmonth_5y = wrst_month, maxdrawdown_5y = drawdown
  87. FROM ej(t, indicators['PBI-5Y'], ['entity_id', 'end_date']);
  88. UPDATE t
  89. SET stddev_10y = std_dev_a, downsidedev_10y = ds_dev_a, alpha_10y = alpha_a, winrate_10y = winrate, beta_10y = beta,
  90. skewness_10y = skewness, kurtosis_10y = kurtosis, worstmonth_10y = wrst_month, maxdrawdown_10y = drawdown
  91. FROM ej(t, indicators['PBI-10Y'], ['entity_id', 'end_date']);
  92. UPDATE t
  93. SET stddev_ytd = std_dev_a, downsidedev_ytd = ds_dev_a, alpha_ytd = alpha_a, winrate_ytd = winrate, beta_ytd = beta,
  94. skewness_ytd = skewness, kurtosis_ytd = kurtosis, worstmonth_ytd = wrst_month, maxdrawdown_ytd = drawdown // mfdb中的真实字段名是 ytd_maxdrawdown
  95. FROM ej(t, indicators['PBI-YTD'], ['entity_id', 'end_date']);
  96. UPDATE t
  97. SET stddev_incep = std_dev_a, downsidedev_incep = ds_dev_a, alpha_incep = alpha_a, winrate_incep = winrate, beta_incep = beta,
  98. skewness_incep = skewness, kurtosis_incep = kurtosis, worstmonth_incep = wrst_month, maxdrawdown_incep = drawdown
  99. FROM ej(t, indicators['PBI-INCEP'], ['entity_id', 'end_date']);
  100. INSERT INTO entity_risk_stats SELECT * FROM t;
  101. } else {
  102. }
  103. }
  104. /*
  105. * 按照 XXX_riskadjret_stats 表结构准备数据记录
  106. *
  107. *
  108. */
  109. def generate_entity_riskadjret_stats(entity_info, indicators, isToMySQL, mutable entity_riskadjret_stats) {
  110. t = null;
  111. if(indicators['PBI-6M'].isVoid() || indicators['PBI-6M'].size() == 0) return;
  112. if(isToMySQL) {
  113. t = SELECT entity_id, end_date,
  114. sharpe_a AS sharperatio_6m, sortino_a AS sortinoratio_6m, treynor AS treynorratio_6m, jensen_a AS jensen_6m,
  115. calmar AS calmarratio_6m, omega AS omegaratio_6m, kappa AS kapparatio_6m
  116. FROM indicators['PBI-6M'] AS ind
  117. INNER JOIN entity_info fi ON ind.entity_id = fi.entity_id
  118. WHERE ind.end_date >= fi.price_date.month(); // 过滤掉不必更新的旧记录
  119. UPDATE t
  120. SET sharperatio_1y = sharpe_a, sortinoratio_1y = sortino_a, treynorratio_1y = treynor, jensen_1y = jensen_a,
  121. calmarratio_1y = calmar, omegaratio_1y = omega, kapparatio_1y = kappa
  122. FROM ej(t, indicators['PBI-1Y'], ['entity_id', 'end_date']);
  123. UPDATE t
  124. SET sharperatio_2y = sharpe_a, sortinoratio_2y = sortino_a, treynorratio_2y = treynor, jensen_2y = jensen_a,
  125. calmarratio_2y = calmar, omegaratio_2y = omega, kapparatio_2y = kappa
  126. FROM ej(t, indicators['PBI-2Y'], ['entity_id', 'end_date']);
  127. UPDATE t
  128. SET sharperatio_3y = sharpe_a, sortinoratio_3y = sortino_a, treynorratio_3y = treynor, jensen_3y = jensen_a,
  129. calmarratio_3y = calmar, omegaratio_3y = omega, kapparatio_3y = kappa
  130. FROM ej(t, indicators['PBI-3Y'], ['entity_id', 'end_date']);
  131. UPDATE t
  132. SET sharperatio_4y = sharpe_a, sortinoratio_4y = sortino_a, treynorratio_4y = treynor, jensen_4y = jensen_a,
  133. calmarratio_4y = calmar, omegaratio_4y = omega, kapparatio_4y = kappa
  134. FROM ej(t, indicators['PBI-4Y'], ['entity_id', 'end_date']);
  135. UPDATE t
  136. SET sharperatio_5y = sharpe_a, sortinoratio_5y = sortino_a, treynorratio_5y = treynor, jensen_5y = jensen_a,
  137. calmarratio_5y = calmar, omegaratio_5y = omega, kapparatio_5y = kappa
  138. FROM ej(t, indicators['PBI-5Y'], ['entity_id', 'end_date']);
  139. UPDATE t
  140. SET sharperatio_10y = sharpe_a, sortinoratio_10y = sortino_a, treynorratio_10y = treynor, jensen_10y = jensen_a,
  141. calmarratio_10y = calmar, omegaratio_10y = omega, kapparatio_10y = kappa
  142. FROM ej(t, indicators['PBI-10Y'], ['entity_id', 'end_date']);
  143. UPDATE t
  144. SET sharperatio_ytd = sharpe_a, sortinoratio_ytd = sortino_a, treynorratio_ytd = treynor, jensen_ytd = jensen_a,
  145. calmarratio_ytd = calmar, omegaratio_ytd = omega, kapparatio_ytd = kappa
  146. FROM ej(t, indicators['PBI-YTD'], ['entity_id', 'end_date']);
  147. UPDATE t
  148. SET sharperatio_incep = sharpe_a, sortinoratio_incep = sortino_a, treynorratio_incep = treynor, jensen_incep = jensen_a,
  149. calmarratio_incep = calmar, omegaratio_incep = omega, kapparatio_incep = kappa
  150. FROM ej(t, indicators['PBI-INCEP'], ['entity_id', 'end_date']);
  151. INSERT INTO entity_riskadjret_stats SELECT * FROM t;
  152. } else {
  153. }
  154. }
  155. /*
  156. * 按照 XXX_indicator 表结构准备数据记录
  157. *
  158. *
  159. */
  160. def generate_entity_indicator(entity_info, indicators, isToMySQL, mutable entity_indicator) {
  161. t = null;
  162. if(indicators['PBI-6M'].isVoid() || indicators['PBI-6M'].size() == 0) return;
  163. if(isToMySQL) {
  164. t = SELECT entity_id, end_date, info_a AS info_ratio_6m, m2_a AS m2_6m, track_error_a AS tracking_error_6m
  165. FROM indicators['PBI-6M'] AS ind
  166. INNER JOIN entity_info fi ON ind.entity_id = fi.entity_id
  167. WHERE ind.end_date >= fi.price_date.month(); // 过滤掉不必更新的旧记录
  168. UPDATE t
  169. SET info_ratio_1y = info_a, m2_1y = m2_a, tracking_error_1y = track_error_a
  170. FROM ej(t, indicators['PBI-1Y'], ['entity_id', 'end_date']);
  171. UPDATE t
  172. SET info_ratio_2y = info_a, m2_2y = m2_a, tracking_error_2y = track_error_a, var_2y = var, cvar_2y = cvar
  173. FROM ej(t, indicators['PBI-2Y'], ['entity_id', 'end_date']);
  174. UPDATE t
  175. SET info_ratio_3y = info_a, m2_3y = m2_a, tracking_error_3y = track_error_a, var_3y = var, cvar_3y = cvar
  176. FROM ej(t, indicators['PBI-3Y'], ['entity_id', 'end_date']);
  177. UPDATE t
  178. SET info_ratio_4y = info_a, m2_4y = m2_a, tracking_error_4y = track_error_a, var_4y = var, cvar_4y = cvar
  179. FROM ej(t, indicators['PBI-4Y'], ['entity_id', 'end_date']);
  180. UPDATE t
  181. SET info_ratio_5y = info_a, m2_5y = m2_a, tracking_error_5y = track_error_a, var_5y = var, cvar_5y = cvar
  182. FROM ej(t, indicators['PBI-5Y'], ['entity_id', 'end_date']);
  183. UPDATE t
  184. SET info_ratio_10y = info_a, m2_10y = m2_a, tracking_error_10y = track_error_a, var_10y = var, cvar_10y = cvar
  185. FROM ej(t, indicators['PBI-10Y'], ['entity_id', 'end_date']);
  186. UPDATE t
  187. SET info_ratio_ytd = info_a, m2_ytd = m2_a, tracking_error_ytd = track_error_a
  188. FROM ej(t, indicators['PBI-YTD'], ['entity_id', 'end_date']);
  189. UPDATE t
  190. SET info_ratio_incep = info_a, m2_incep = m2_a, tracking_error_incep = track_error_a, var_incep = var, cvar_incep = cvar
  191. FROM ej(t, indicators['PBI-INCEP'], ['entity_id', 'end_date']);
  192. INSERT INTO entity_indicator SELECT * FROM t;
  193. } else {
  194. }
  195. }
  196. /*
  197. * 按照 XXX_style_stats 表结构准备数据记录
  198. *
  199. *
  200. */
  201. def generate_entity_style_stats(entity_info, indicators, isToMySQL, mutable entity_style_stats) {
  202. t = null;
  203. if(indicators['PBI-6M'].isVoid() || indicators['PBI-6M'].size() == 0) return;
  204. if(isToMySQL) {
  205. t = SELECT entity_id, end_date, upside_capture_ret AS upsidecapture_ret_6m, downside_capture_ret AS downsidecapture_ret_6m,
  206. upside_capture_ratio AS upsidecapture_ratio_6m, downside_capture_ratio AS downsidecapture_ratio_6m
  207. FROM indicators['PBI-6M'] AS ind
  208. INNER JOIN entity_info fi ON ind.entity_id = fi.entity_id
  209. WHERE ind.end_date >= fi.price_date.month(); // 过滤掉不必更新的旧记录
  210. UPDATE t
  211. SET upsidecapture_ret_1y = upside_capture_ret, downsidecapture_ret_1y = downside_capture_ret,
  212. upsidecapture_ratio_1y = upside_capture_ratio, downsidecapture_ratio_1y = downside_capture_ratio
  213. FROM ej(t, indicators['PBI-1Y'], ['entity_id', 'end_date']);
  214. UPDATE t
  215. SET upsidecapture_ret_2y = upside_capture_ret, downsidecapture_ret_2y = downside_capture_ret,
  216. upsidecapture_ratio_2y = upside_capture_ratio, downsidecapture_ratio_2y = downside_capture_ratio
  217. FROM ej(t, indicators['PBI-2Y'], ['entity_id', 'end_date']);
  218. UPDATE t
  219. SET upsidecapture_ret_3y = upside_capture_ret, downsidecapture_ret_3y = downside_capture_ret,
  220. upsidecapture_ratio_3y = upside_capture_ratio, downsidecapture_ratio_3y = downside_capture_ratio
  221. FROM ej(t, indicators['PBI-3Y'], ['entity_id', 'end_date']);
  222. UPDATE t
  223. SET upsidecapture_ret_4y = upside_capture_ret, downsidecapture_ret_4y = downside_capture_ret,
  224. upsidecapture_ratio_4y = upside_capture_ratio, downsidecapture_ratio_4y = downside_capture_ratio
  225. FROM ej(t, indicators['PBI-4Y'], ['entity_id', 'end_date']);
  226. UPDATE t
  227. SET upsidecapture_ret_5y = upside_capture_ret, downsidecapture_ret_5y = downside_capture_ret,
  228. upsidecapture_ratio_5y = upside_capture_ratio, downsidecapture_ratio_5y = downside_capture_ratio
  229. FROM ej(t, indicators['PBI-5Y'], ['entity_id', 'end_date']);
  230. UPDATE t
  231. SET upsidecapture_ret_10y = upside_capture_ret, downsidecapture_ret_10y = downside_capture_ret,
  232. upsidecapture_ratio_10y = upside_capture_ratio, downsidecapture_ratio_10y = downside_capture_ratio
  233. FROM ej(t, indicators['PBI-10Y'], ['entity_id', 'end_date']);
  234. UPDATE t
  235. SET upsidecapture_ret_ytd = upside_capture_ret, downsidecapture_ret_ytd = downside_capture_ret,
  236. upsidecapture_ratio_ytd = upside_capture_ratio, downsidecapture_ratio_ytd = downside_capture_ratio
  237. FROM ej(t, indicators['PBI-YTD'], ['entity_id', 'end_date']);
  238. UPDATE t
  239. SET upsidecapture_ret_incep = upside_capture_ret, downsidecapture_ret_incep = downside_capture_ret,
  240. upsidecapture_ratio_incep = upside_capture_ratio, downsidecapture_ratio_incep = downside_capture_ratio
  241. FROM ej(t, indicators['PBI-INCEP'], ['entity_id', 'end_date']);
  242. INSERT INTO entity_style_stats SELECT * FROM t;
  243. } else {
  244. }
  245. }
  246. /*
  247. * 按照 XXX_performance_weekly 表结构准备数据记录
  248. *
  249. *
  250. */
  251. def generate_entity_performance_weekly(entity_info, ret_w, isToMySQL, mutable entity_performance_weekly) {
  252. t = null;
  253. if(ret_w.isVoid() || ret_w.size() == 0) return;
  254. if(isToMySQL) {
  255. t = SELECT entity_id, year_week, year_week.left(4)$INT AS end_year, year_week.right(2)$INT AS week_of_year, price_date,
  256. cumulative_nav, ret_1w
  257. FROM ret_w r
  258. INNER JOIN entity_info fi ON r.entity_id = fi.entity_id
  259. WHERE r.price_date >= fi.price_date; // 过滤掉不必更新的旧记录
  260. INSERT INTO entity_performance_weekly SELECT * FROM t;
  261. } else {
  262. }
  263. }
  264. /*
  265. * 按照 XXX_latest_performance 表结构准备数据记录
  266. *
  267. *
  268. */
  269. def generate_entity_latest_performance(entity_info, perf_latest, isToMySQL, mutable entity_latest_performance) {
  270. t = null;
  271. if(perf_latest.isVoid() || perf_latest.size() == 0) return;
  272. if(isToMySQL) {
  273. t = SELECT r.*
  274. FROM perf_latest r
  275. INNER JOIN entity_info fi ON r.entity_id = fi.entity_id
  276. WHERE r.price_date >= fi.price_date; // 过滤掉不必更新的旧记录
  277. INSERT INTO entity_latest_performance SELECT * FROM t;
  278. } else {
  279. }
  280. }
  281. /*
  282. * 定时任务:最新净值触发的业绩指标计算
  283. *
  284. * @param entityType <STRING>: 'MF', 'HF'...
  285. * @param date <DATETIME>: 净值更新时间
  286. *
  287. * NOTE: 与Java不同的是当月indicator计算每日触发,不必等到Month-end production
  288. */
  289. def calFundPerformance(entityType, date) {
  290. rt = '';
  291. very_old_date = 1990.01.01;
  292. if(find(['HF', 'MF'], entityType) < 0) return null;
  293. // 取有最新净值变动的基金列表 (1s)
  294. tb_cal_funds = get_entity_list_by_nav_updatetime(entityType, NULL, date, true);
  295. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  296. tb_fund_performance = create_entity_performance();
  297. tb_fund_indicator = create_entity_indicator();
  298. tb_fund_risk_stats = create_entity_risk_stats();
  299. tb_fund_riskadjret_stats = create_entity_riskadjret_stats();
  300. tb_fund_style_stats = create_entity_style_stats();
  301. tb_fund_performance_weekly = create_entity_performance_weekly();
  302. tb_fund_latest_performance = create_entity_latest_performance();
  303. // 分批跑
  304. i = 0;
  305. batch_size = 1000;
  306. do {
  307. funds = tb_cal_funds[i : min(tb_cal_funds.size(), i+batch_size)];
  308. //funds = SELECT * FROM tb_cal_funds WHERE entity_id in ('MF00003PXI', 'MF00003PXX')
  309. if(funds.isVoid() || funds.size() == 0) break;
  310. // 200ms
  311. fund_info = SELECT entity_id, price_date, inception_date, benchmark_id, ini_value
  312. FROM ej(funds, get_fund_info(funds.entity_id), 'entity_id', 'fund_id');
  313. // 计算月收益 (12s)
  314. rets = mix_monthly_returns(entityType, fund_info);
  315. if(!rets.isVoid() && rets.size() > 0) {
  316. // 计算月度指标 (56s)
  317. rets.rename!('cumulative_nav', 'nav');
  318. indicators = cal_monthly_indicators(entityType, 'PBI', rets);
  319. // 仿照MySQL的表结构准备好记录 (1s)
  320. generate_entity_performance(fund_info, indicators, true, tb_fund_performance);
  321. generate_entity_indicator(fund_info, indicators, true, tb_fund_indicator);
  322. generate_entity_risk_stats(fund_info, indicators, true, tb_fund_risk_stats);
  323. generate_entity_riskadjret_stats(fund_info, indicators, true, tb_fund_riskadjret_stats);
  324. generate_entity_style_stats(fund_info, indicators, true, tb_fund_style_stats);
  325. }
  326. // 计算周收益 (8s)
  327. rets_w = cal_weekly_returns(entityType, fund_info);
  328. if(! rets_w.isVoid() && rets_w.size() > 0) {
  329. generate_entity_performance_weekly(fund_info, rets_w, true, tb_fund_performance_weekly);
  330. }
  331. // 计算最新收益 (69s)
  332. perf_latest = cal_latest_performance(entityType, fund_info, true);
  333. if(! perf_latest.isVoid() && perf_latest.size() > 0) {
  334. generate_entity_latest_performance(fund_info, perf_latest, true, tb_fund_latest_performance);
  335. }
  336. i += batch_size;
  337. // } while (i < batch_size);
  338. } while (i <= tb_cal_funds.size());
  339. if(! tb_fund_performance.isVoid() && tb_fund_performance.size() > 0) {
  340. // save data to MySQL (13s)
  341. try {
  342. chg_columns_for_mysql(tb_fund_performance, 'fund_id');
  343. save_and_sync(tb_fund_performance, 'raw_db.fund_performance', 'raw_db.fund_performance');
  344. chg_columns_for_mysql(tb_fund_indicator, 'fund_id');
  345. save_and_sync(tb_fund_indicator, 'raw_db.fund_indicator', 'raw_db.fund_indicator');
  346. chg_columns_for_mysql(tb_fund_risk_stats, 'fund_id');
  347. // mfdb.fund_performance 表中 maxdrawdown_6m & maxdrawdown_ytd 是虚拟列,这里用数据列顺序强行写入真实列 6m_maxdrawdown & ytd_maxdrawdown (DolphinDB 不允许字段名以数字开头)
  348. save_and_sync(tb_fund_risk_stats, 'raw_db.fund_risk_stats', 'raw_db.fund_risk_stats');
  349. chg_columns_for_mysql(tb_fund_riskadjret_stats, 'fund_id');
  350. save_and_sync(tb_fund_riskadjret_stats, 'raw_db.fund_riskadjret_stats', 'raw_db.fund_riskadjret_stats');
  351. chg_columns_for_mysql(tb_fund_style_stats, 'fund_id');
  352. save_and_sync(tb_fund_style_stats, 'raw_db.fund_style_stats', 'raw_db.fund_style_stats');
  353. save_and_sync(tb_fund_performance_weekly, 'raw_db.fund_performance_weekly', 'raw_db.fund_performance_weekly');
  354. save_and_sync(tb_fund_latest_performance, 'raw_db.fund_latest_performance', 'raw_db.fund_latest_nav_performance');
  355. } catch(ex) {
  356. //TODO: Log errors
  357. rt = ex;
  358. }
  359. }
  360. return rt;
  361. }
  362. /*
  363. * 【临时】用于数据初始化:只计算收益
  364. *
  365. * @param entityType <STRING>: 'MF', 'HF'...
  366. * @param date <DATETIME>: 净值更新时间
  367. *
  368. */
  369. def ms_calFundReturns() {
  370. rt = '';
  371. very_old_date = 1990.01.01;
  372. // 取基金列表 (27s)
  373. tb_cal_funds = ms_get_fund_list_by_nav_createtime(NULL, very_old_date);
  374. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  375. tb_fund_performance = create_entity_performance();
  376. tb_fund_indicator = create_entity_indicator();
  377. tb_fund_risk_stats = create_entity_risk_stats();
  378. tb_fund_riskadjret_stats = create_entity_riskadjret_stats();
  379. tb_fund_style_stats = create_entity_style_stats();
  380. tb_fund_performance_weekly = create_entity_performance_weekly();
  381. tb_fund_latest_performance = create_entity_latest_performance();
  382. // 分批跑
  383. i = 0;
  384. batch_size = 1000;
  385. do {
  386. funds = tb_cal_funds[i : min(tb_cal_funds.size(), i+batch_size)];
  387. if(funds.isVoid() || funds.size() == 0) break;
  388. // 200ms
  389. fund_info = SELECT entity_id, price_date, inception_date, benchmark_id, ini_value
  390. FROM ej(funds, ms_get_fund_info(funds.entity_id), 'entity_id', 'fund_id');
  391. // 计算月收益 (19s)
  392. tb_nav = ms_get_fund_monthly_nav(fund_info.entity_id);
  393. rets = cal_monthly_returns_by_nav(fund_info, tb_nav);
  394. if(!rets.isVoid() && rets.size() > 0) {
  395. // 计算月度指标 (67s)
  396. rets.rename!('cumulative_nav', 'nav');
  397. indicators = cal_monthly_indicators('MF', 'PBI', rets);
  398. // 仿照MySQL的表结构准备好记录 (1s)
  399. generate_entity_performance(fund_info, indicators, true, tb_fund_performance);
  400. generate_entity_indicator(fund_info, indicators, true, tb_fund_indicator);
  401. generate_entity_risk_stats(fund_info, indicators, true, tb_fund_risk_stats);
  402. generate_entity_riskadjret_stats(fund_info, indicators, true, tb_fund_riskadjret_stats);
  403. generate_entity_style_stats(fund_info, indicators, true, tb_fund_style_stats);
  404. }
  405. // 计算周收益 (49s)
  406. rets_w = cal_weekly_returns('MF', fund_info);
  407. if(! rets_w.isVoid() && rets_w.size() > 0) {
  408. generate_entity_performance_weekly(fund_info, rets_w, true, tb_fund_performance_weekly);
  409. }
  410. // 计算最新收益 (23s)
  411. perf_latest = cal_latest_performance('MF', fund_info, true);
  412. if(! perf_latest.isVoid() && perf_latest.size() > 0) {
  413. generate_entity_latest_performance(fund_info, perf_latest, true, tb_fund_latest_performance);
  414. }
  415. i += batch_size;
  416. // } while (i < batch_size);
  417. } while (i <= tb_cal_funds.size());
  418. if(! tb_fund_performance.isVoid() && tb_fund_performance.size() > 0) {
  419. // save data to MySQL (26m)
  420. try {
  421. chg_columns_for_mysql(tb_fund_performance, 'fund_id');
  422. save_and_sync(tb_fund_performance, 'raw_db.fund_performance', 'raw_db.fund_performance');
  423. chg_columns_for_mysql(tb_fund_indicator, 'fund_id');
  424. save_and_sync(tb_fund_indicator, 'raw_db.fund_indicator', 'raw_db.fund_indicator');
  425. chg_columns_for_mysql(tb_fund_risk_stats, 'fund_id');
  426. // mfdb.fund_performance 表中 maxdrawdown_6m & maxdrawdown_ytd 是虚拟列,这里用数据列顺序强行写入真实列 6m_maxdrawdown & ytd_maxdrawdown (DolphinDB 不允许字段名以数字开头)
  427. save_and_sync(tb_fund_risk_stats, 'raw_db.fund_risk_stats', 'raw_db.fund_risk_stats');
  428. chg_columns_for_mysql(tb_fund_riskadjret_stats, 'fund_id');
  429. save_and_sync(tb_fund_riskadjret_stats, 'raw_db.fund_riskadjret_stats', 'raw_db.fund_riskadjret_stats');
  430. chg_columns_for_mysql(tb_fund_style_stats, 'fund_id');
  431. save_and_sync(tb_fund_style_stats, 'raw_db.fund_style_stats', 'raw_db.fund_style_stats');
  432. save_and_sync(tb_fund_performance_weekly, 'raw_db.fund_performance_weekly', 'raw_db.fund_performance_weekly');
  433. save_and_sync(tb_fund_latest_performance, 'raw_db.fund_latest_performance', 'raw_db.fund_latest_nav_performance');
  434. } catch(ex) {
  435. //TODO: Log errors
  436. rt = ex;
  437. }
  438. }
  439. return rt;
  440. }
  441. /*
  442. * 实验性质的API
  443. *
  444. *
  445. */
  446. def calFundIndexCorrelation(entityType, date) {
  447. if(find(['HF', 'MF'], entityType) < 0) return null;
  448. // 取有最新净值变动的基金列表 (1s)
  449. tb_cal_funds = get_entity_list_by_nav_updatetime(entityType, NULL, date, true);
  450. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  451. // tb_fund_index_coe = create_entity_index_coe();
  452. // (7m)
  453. coe = cal_entity_index_coe(entityType, tb_cal_funds[0:1000]);
  454. return coe;
  455. }