task_fundPerformance.dos 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. * [定时任务]:最新净值触发的业绩指标计算
  11. *
  12. * @param entityType <STRING>: 'MF', 'HF'...
  13. * @param date <DATETIME>: 净值更新时间
  14. *
  15. * NOTE: 与Java不同的是当月indicator计算每日触发,不必等到Month-end production
  16. */
  17. def calFundPerformanceTask(entityType, date) {
  18. rt = '';
  19. very_old_date = 1990.01.01;
  20. if(find(['HF', 'MF'], entityType) < 0) return null;
  21. // 取有最新净值变动的基金列表 (1s)
  22. tb_cal_funds = get_entity_list_by_nav_updatetime(entityType, NULL, date, true);
  23. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  24. tb_fund_performance = create_entity_performance();
  25. tb_fund_indicator = create_entity_indicator();
  26. tb_fund_risk_stats = create_entity_risk_stats();
  27. tb_fund_riskadjret_stats = create_entity_riskadjret_stats();
  28. tb_fund_style_stats = create_entity_style_stats();
  29. tb_fund_performance_weekly = create_entity_performance_weekly();
  30. tb_fund_latest_performance = create_entity_latest_performance();
  31. // 分批跑
  32. i = 0;
  33. batch_size = 1000;
  34. do {
  35. funds = tb_cal_funds[i : min(tb_cal_funds.size(), i+batch_size)];
  36. //funds = SELECT * FROM tb_cal_funds WHERE entity_id in ('MF00003PXI', 'MF00003PXX')
  37. if(funds.isVoid() || funds.size() == 0) break;
  38. // 200ms
  39. fund_info = SELECT entity_id, price_date, inception_date, benchmark_id, ini_value
  40. FROM ej(funds, get_fund_info(funds.entity_id), 'entity_id', 'fund_id');
  41. // 计算月收益 (12s)
  42. rets = mix_monthly_returns(entityType, fund_info);
  43. if(!rets.isVoid() && rets.size() > 0) {
  44. // 计算月度指标 (56s)
  45. rets.rename!('cumulative_nav', 'nav');
  46. indicators = cal_monthly_indicators(entityType, 'PBI', rets);
  47. // 仿照MySQL的表结构准备好记录 (1s)
  48. generate_entity_performance(fund_info, indicators, true, tb_fund_performance);
  49. generate_entity_indicator(fund_info, indicators, true, tb_fund_indicator);
  50. generate_entity_risk_stats(fund_info, indicators, true, tb_fund_risk_stats);
  51. generate_entity_riskadjret_stats(fund_info, indicators, true, tb_fund_riskadjret_stats);
  52. generate_entity_style_stats(fund_info, indicators, true, tb_fund_style_stats);
  53. }
  54. // 计算周收益 (8s)
  55. rets_w = cal_weekly_returns(entityType, fund_info);
  56. if(! rets_w.isVoid() && rets_w.size() > 0) {
  57. generate_entity_performance_weekly(fund_info, rets_w, true, tb_fund_performance_weekly);
  58. }
  59. // 计算最新收益 (69s)
  60. perf_latest = cal_latest_performance(entityType, fund_info, true);
  61. if(! perf_latest.isVoid() && perf_latest.size() > 0) {
  62. generate_entity_latest_performance(fund_info, perf_latest, true, tb_fund_latest_performance);
  63. }
  64. i += batch_size;
  65. // } while (i < batch_size);
  66. } while (i <= tb_cal_funds.size());
  67. if(! tb_fund_performance.isVoid() && tb_fund_performance.size() > 0) {
  68. // save data to MySQL (13s)
  69. try {
  70. chg_columns_for_mysql(tb_fund_performance, 'fund_id');
  71. save_and_sync(tb_fund_performance, 'raw_db.fund_performance', 'raw_db.fund_performance');
  72. chg_columns_for_mysql(tb_fund_indicator, 'fund_id');
  73. save_and_sync(tb_fund_indicator, 'raw_db.fund_indicator', 'raw_db.fund_indicator');
  74. chg_columns_for_mysql(tb_fund_risk_stats, 'fund_id');
  75. // mfdb.fund_performance 表中 maxdrawdown_6m & maxdrawdown_ytd 是虚拟列,这里用数据列顺序强行写入真实列 6m_maxdrawdown & ytd_maxdrawdown (DolphinDB 不允许字段名以数字开头)
  76. save_and_sync(tb_fund_risk_stats, 'raw_db.fund_risk_stats', 'raw_db.fund_risk_stats');
  77. chg_columns_for_mysql(tb_fund_riskadjret_stats, 'fund_id');
  78. save_and_sync(tb_fund_riskadjret_stats, 'raw_db.fund_riskadjret_stats', 'raw_db.fund_riskadjret_stats');
  79. chg_columns_for_mysql(tb_fund_style_stats, 'fund_id');
  80. save_and_sync(tb_fund_style_stats, 'raw_db.fund_style_stats', 'raw_db.fund_style_stats');
  81. save_and_sync(tb_fund_performance_weekly, 'raw_db.fund_performance_weekly', 'raw_db.fund_performance_weekly');
  82. save_and_sync(tb_fund_latest_performance, 'raw_db.fund_latest_performance', 'raw_db.fund_latest_nav_performance');
  83. } catch(ex) {
  84. //TODO: Log errors
  85. rt = ex;
  86. }
  87. }
  88. return rt;
  89. }
  90. /*
  91. * 【临时】用于数据初始化:只计算收益
  92. *
  93. * @param entityType <STRING>: 'MF', 'HF'...
  94. * @param date <DATETIME>: 净值更新时间
  95. *
  96. */
  97. def ms_calFundReturns() {
  98. rt = '';
  99. very_old_date = 1990.01.01;
  100. // 取基金列表 (27s)
  101. tb_cal_funds = ms_get_fund_list_by_nav_updatetime(NULL, very_old_date);
  102. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  103. tb_fund_performance = create_entity_performance();
  104. tb_fund_indicator = create_entity_indicator();
  105. tb_fund_risk_stats = create_entity_risk_stats();
  106. tb_fund_riskadjret_stats = create_entity_riskadjret_stats();
  107. tb_fund_style_stats = create_entity_style_stats();
  108. tb_fund_performance_weekly = create_entity_performance_weekly();
  109. tb_fund_latest_performance = create_entity_latest_performance();
  110. // 分批跑
  111. i = 0;
  112. batch_size = 1000;
  113. do {
  114. funds = tb_cal_funds[i : min(tb_cal_funds.size(), i+batch_size)];
  115. if(funds.isVoid() || funds.size() == 0) break;
  116. // 200ms
  117. fund_info = SELECT entity_id, price_date, inception_date, benchmark_id, ini_value
  118. FROM ej(funds, ms_get_fund_info(funds.entity_id), 'entity_id', 'fund_id');
  119. // 计算月收益 (19s)
  120. tb_nav = ms_get_fund_monthly_nav(fund_info.entity_id);
  121. rets = cal_monthly_returns_by_nav(fund_info, tb_nav);
  122. if(!rets.isVoid() && rets.size() > 0) {
  123. // 计算月度指标 (67s)
  124. rets.rename!('cumulative_nav', 'nav');
  125. indicators = cal_monthly_indicators('MF', 'PBI', rets);
  126. // 仿照MySQL的表结构准备好记录 (1s)
  127. generate_entity_performance(fund_info, indicators, true, tb_fund_performance);
  128. generate_entity_indicator(fund_info, indicators, true, tb_fund_indicator);
  129. generate_entity_risk_stats(fund_info, indicators, true, tb_fund_risk_stats);
  130. generate_entity_riskadjret_stats(fund_info, indicators, true, tb_fund_riskadjret_stats);
  131. generate_entity_style_stats(fund_info, indicators, true, tb_fund_style_stats);
  132. }
  133. // 计算周收益 (49s)
  134. rets_w = cal_weekly_returns('MF', fund_info);
  135. if(! rets_w.isVoid() && rets_w.size() > 0) {
  136. generate_entity_performance_weekly(fund_info, rets_w, true, tb_fund_performance_weekly);
  137. }
  138. // 计算最新收益 (23s)
  139. perf_latest = cal_latest_performance('MF', fund_info, true);
  140. if(! perf_latest.isVoid() && perf_latest.size() > 0) {
  141. generate_entity_latest_performance(fund_info, perf_latest, true, tb_fund_latest_performance);
  142. }
  143. i += batch_size;
  144. // } while (i < batch_size);
  145. } while (i <= tb_cal_funds.size());
  146. if(! tb_fund_performance.isVoid() && tb_fund_performance.size() > 0) {
  147. // save data to MySQL (26m)
  148. try {
  149. chg_columns_for_mysql(tb_fund_performance, 'fund_id');
  150. save_and_sync(tb_fund_performance, 'raw_db.fund_performance', 'raw_db.fund_performance');
  151. chg_columns_for_mysql(tb_fund_indicator, 'fund_id');
  152. save_and_sync(tb_fund_indicator, 'raw_db.fund_indicator', 'raw_db.fund_indicator');
  153. chg_columns_for_mysql(tb_fund_risk_stats, 'fund_id');
  154. // mfdb.fund_performance 表中 maxdrawdown_6m & maxdrawdown_ytd 是虚拟列,这里用数据列顺序强行写入真实列 6m_maxdrawdown & ytd_maxdrawdown (DolphinDB 不允许字段名以数字开头)
  155. save_and_sync(tb_fund_risk_stats, 'raw_db.fund_risk_stats', 'raw_db.fund_risk_stats');
  156. chg_columns_for_mysql(tb_fund_riskadjret_stats, 'fund_id');
  157. save_and_sync(tb_fund_riskadjret_stats, 'raw_db.fund_riskadjret_stats', 'raw_db.fund_riskadjret_stats');
  158. chg_columns_for_mysql(tb_fund_style_stats, 'fund_id');
  159. save_and_sync(tb_fund_style_stats, 'raw_db.fund_style_stats', 'raw_db.fund_style_stats');
  160. save_and_sync(tb_fund_performance_weekly, 'raw_db.fund_performance_weekly', 'raw_db.fund_performance_weekly');
  161. save_and_sync(tb_fund_latest_performance, 'raw_db.fund_latest_performance', 'raw_db.fund_latest_nav_performance');
  162. } catch(ex) {
  163. //TODO: Log errors
  164. rt = ex;
  165. }
  166. }
  167. return rt;
  168. }
  169. /*
  170. * 实验性质的API
  171. *
  172. *
  173. */
  174. def calFundIndexCorrelation(entityType, date) {
  175. if(find(['HF', 'MF'], entityType) < 0) return null;
  176. // 取有最新净值变动的基金列表 (1s)
  177. tb_cal_funds = get_entity_list_by_nav_updatetime(entityType, NULL, date, true);
  178. if(tb_cal_funds.isVoid() || tb_cal_funds.size() == 0 ) return;
  179. // tb_fund_index_coe = create_entity_index_coe();
  180. // (7m)
  181. coe = cal_entity_index_coe(entityType, tb_cal_funds[0:1000]);
  182. return coe;
  183. }