task_monthlyPerformance.dos 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. module fundit::task_monthlyPerformance
  2. use fundit::sqlUtilities;
  3. use fundit::operationDataPuller;
  4. use fundit::performanceDataPuller;
  5. use fundit::indicatorCalculator;
  6. use fundit::dataSaver;
  7. use fundit::bfiMatcher;
  8. use fundit::rankingCalculator;
  9. use fundit::navCalculator;
  10. /*
  11. * [定时任务] 计算基金一、二级分类排名并存入数据库
  12. *
  13. * @param entity_type <STRING>: 'MF', 'HF' (MF=HF)
  14. * @param end_date <MONTH>:
  15. * @param isFromMySQL <BOOL>: false 时读取dolphin本地的收益及指标表,用于初始化数据
  16. *
  17. * NOTE: 与 MySQL 不同,这里的 rank 最小值是0,不是1
  18. *
  19. * Example: CalEntityRankingTask('PL', 2024.12M, true);
  20. * CalEntityRankingTask('CO', 2024.12M, true);
  21. */
  22. def CalEntityRankingTask(entityType, endDate, isFromMySQL=true) {
  23. //entityType='MF'
  24. //endDate = 2025.01M
  25. //isFromMySQL = true
  26. if(!(entityType in ['MF', 'HF', 'PL', 'CO'])) return NULL;
  27. entity_info = get_entity_info(entityType, NULL);
  28. v_ranking_tables = cal_indicator_ranking('strategy', entityType, entity_info, endDate, isFromMySQL);
  29. save_ranking_tables(entityType, 'strategy', v_ranking_tables);
  30. }
  31. /*
  32. * [定时任务] 计算基金BFI排名并存入数据库
  33. *
  34. * @param entityType <STRING>: 'MF', 'HF' (MF=HF), 'PL'
  35. * @param endDate <MONTH>:
  36. * @param isFromMySQL <BOOL>: false 时读取dolphin本地的收益及指标表,用于初始化数据
  37. *
  38. *
  39. * Example: CalEntityBfiRankingTask('MF', 2024.12M, true);
  40. * CalEntityBfiRankingTask('PL', 2024.12M, true);
  41. */
  42. def CalEntityBfiRankingTask(entityType, endDate, isFromMySQL=true) {
  43. if(!(entityType in ['MF', 'HF', 'PL'])) return NULL;
  44. entity_info = get_entity_info(entityType, NULL);
  45. // 16 sec
  46. v_ranking_tables = cal_indicator_ranking('bfi', entityType, entity_info, endDate, isFromMySQL);
  47. // 39 sec
  48. save_ranking_tables(entityType, 'bfi', v_ranking_tables);
  49. // 用于 Tamp 基金推荐的主因子排名
  50. v_ranking_tables = cal_indicator_ranking_for_propose(endDate, isFromMySQL);
  51. t1 = v_ranking_tables[0];
  52. t1.rename!(['entity_id', 'category_id'], ['fund_id', 'factor_id']);
  53. save_and_sync(t1, 'raw_db.pf_fund_bfi_bm_indicator_ranking_for_propose', , 'fund_id', 'end_date');
  54. t2 = v_ranking_tables[1];
  55. t2.rename!('category_id', 'factor_id');
  56. save_and_sync(t2, 'raw_db.pf_fund_bfi_bm_indicator_ranking_for_propose_num', , '', 'end_date');
  57. }
  58. /*
  59. * Private Method: 计算相对排名并存入数据库
  60. *
  61. *
  62. */
  63. def cal_and_save_relative_ranking(entity_type, benchmark_ranking, entity_ranking, ranking_by, isFromMySQL=true) {
  64. // benchmark_ranking= tb_fund_ranking
  65. t_entity_ranking = entity_ranking;
  66. cal_relative_ranking(benchmark_ranking, t_entity_ranking, isFromMySQL);
  67. t_entity_ranking.rename!('category_id', iif(ranking_by=='bfi', 'factor_id', ranking_by));
  68. save_relative_ranking_table(entity_type, t_entity_ranking, ranking_by);
  69. }
  70. /*
  71. *
  72. * [定时任务] 以公募基金为评级参考,计算组合、私有基金收益及指标排名
  73. *
  74. * @param entityType <STRING>: PF
  75. *
  76. * TODO: customer fund
  77. * TODO: 计算单个组合时总耗时1.5min, 大部分时间用来获取Mysql数据
  78. *
  79. * Example: CalRelativeRankingTask('PF', NULL, 2024.12M, true);
  80. * CalRelativeRankingTask('PF', 143109, 2024.09M, true);
  81. */
  82. def CalRelativeRankingTask(entity_type, entity_ids, end_date, isFromMySQL=true) {
  83. // entity_type = 'PF'
  84. // end_date = 2024.09M
  85. // isFromMySQL = true
  86. // ranking_by = 'bfi'
  87. // entity_ids = 143109
  88. entity_info = get_entity_info(entity_type, entity_ids);
  89. if(entity_type == 'PF')
  90. entity_info = SELECT * FROM entity_info WHERE portfolio_type IN (1, 2) // 1: 用户组合、2:客户真实组合,忽略客户推荐组合、总览综合等虚拟组合
  91. v_ranking_by = ['strategy', 'substrategy', 'bfi'];
  92. // 暂时以公募混合基金为排名参考
  93. for(ranking_by in v_ranking_by) {
  94. if(ranking_by == 'strategy') {
  95. v_category = EXEC DISTINCT strategy FROM entity_info WHERE strategy IS NOT NULL;
  96. tb_fund_ranking = get_fund_indicator_ranking(NULL, end_date, v_category, isFromMySQL);
  97. UPDATE tb_fund_ranking SET category_id = strategy$STRING;
  98. } else if(ranking_by == 'substrategy') {
  99. v_category = EXEC DISTINCT substrategy FROM entity_info WHERE substrategy IS NOT NULL;
  100. tb_fund_ranking = get_fund_indicator_substrategy_ranking(NULL, end_date, v_category, isFromMySQL);
  101. UPDATE tb_fund_ranking SET category_id = substrategy$STRING;
  102. } else if(ranking_by == 'bfi') {
  103. if(entity_ids != NULL || entity_ids != '')
  104. v_category = EXEC DISTINCT factor_id FROM get_entity_bfi_factors(entity_type, entity_ids, end_date, end_date);
  105. else
  106. v_category = NULL;
  107. tb_fund_ranking = get_fund_bfi_bm_indicator_ranking(NULL, end_date, v_category, isFromMySQL);
  108. UPDATE tb_fund_ranking SET category_id = factor_id;
  109. }
  110. if(tb_fund_ranking.isVoid() || tb_fund_ranking.size() == 0) return;
  111. entity_ranking = transform_data_for_ranking(entity_type, entity_info, end_date, ranking_by, isFromMySQL);
  112. cal_and_save_relative_ranking(entity_type, tb_fund_ranking, entity_ranking, ranking_by, isFromMySQL);
  113. }
  114. }
  115. /*
  116. * 计算并存储基金经理和公司月度净值
  117. *
  118. * @return <TABLE>: [COLUMNS] entity_id, curve_type, strategy, effective_date, price_date, ret, nav
  119. *
  120. */
  121. def cal_and_save_mc_monthly_nav(entity_type, entity_date, is_save_local) {
  122. rt = '';
  123. if( !(entity_type in ['PL', 'CO']) ) return rt;
  124. if(entity_date.isVoid() || entity_date.size() == 0) return rt;
  125. // 准备类似MySQL结构的数据表
  126. tb_entity_nav = create_mc_fitted_curve();
  127. // 暂时与 MySQL 保持一致,只计算公募,私募,公私募综合三条时间序列。未来可细化至公、私募+主策略
  128. d_curve_type = dict(INT, INT);
  129. d_curve_type[1] = 1; // 私募
  130. d_curve_type[4] = 2; // 公募
  131. d_curve_type[7] = -99; // 公私募综合
  132. // 分批跑
  133. i = 0;
  134. batch_size = 1000;
  135. all_entity_id = entity_date.entity_id.distinct();
  136. do { // 14 sec
  137. tb_entity = SELECT entity_id, effective_date FROM entity_date
  138. WHERE entity_id IN all_entity_id[i : min(all_entity_id.size(), i+batch_size)];
  139. if(tb_entity.isVoid() || tb_entity.size() == 0) break;
  140. s_json = tb_entity.toStdJson();
  141. t_ret = get_mc_average_return(entity_type, 'm', s_json, 0, 1, true);
  142. for(cur in d_curve_type.keys()) {
  143. tmp = SELECT entity_id, cur AS curve_type, 0 AS strategy, effective_date, price_date, ret, incl_cal_cnt
  144. FROM t_ret WHERE raise_type = d_curve_type[cur] AND strategy = -99; // 目前只需要全策略
  145. // 计算月收益
  146. tb_nav = cal_mc_nav_by_return(entity_type, tmp, 'm');
  147. INSERT INTO tb_entity_nav
  148. SELECT entity_id, curve_type, strategy, effective_date AS end_date, nav, incl_cal_cnt
  149. FROM ej(tb_nav, tmp, ['entity_id', 'curve_type', 'strategy', 'effective_date']);
  150. }
  151. i += batch_size;
  152. } while (i <= all_entity_id.size());
  153. if(! tb_entity_nav.isVoid() && tb_entity_nav.size() > 0) {
  154. // save data to MySQL (12 sec)
  155. try {
  156. entity_id_col = iif(entity_type == 'PL', 'fund_manager_id', 'company_id');
  157. tb_entity_nav.rename!('entity_id', entity_id_col);
  158. save_and_sync(tb_entity_nav, iif(entity_type == 'PL', 'raw_db.fund_manager_fitted_curve', 'raw_db.company_fitted_curve'), , entity_id_col, 'end_date');
  159. // 数据初始化时将指标存入本地
  160. if(is_save_local == true) {
  161. save_table(tb_entity_nav, iif(entity_type == 'PL', 'mfdb.fund_manager_fitted_curve', 'mfdb.company_fitted_curve'), false);
  162. }
  163. } catch(ex) {
  164. //TODO: Log errors
  165. rt += ex;
  166. }
  167. }
  168. return rt;
  169. }
  170. /*
  171. * 计算并存储基金经理/公司的月度收益及指标
  172. *
  173. * @param entity_date <TABLE>: entity_id, curve_type, strategy, price_date
  174. * @param monthly_returns <TABLE>: entity_id, curve_type, strategy, end_date, price_date, nav, ret
  175. * @param indicator_type <STRING>: PBI, BFI
  176. *
  177. */
  178. def cal_and_save_mc_indicator(entity_type, entity_date, monthly_returns, indicator_type, is_save_local) {
  179. rt = '';
  180. if(!(entity_type IN ['PL', 'CO'] && indicator_type IN ['PBI', 'BFI'])) return rt;
  181. if(entity_date.isVoid() || entity_date.size() == 0) return rt;
  182. d_indicators = cal_mc_monthly_indicators(entity_type, indicator_type, monthly_returns);
  183. if(d_indicators.isVoid() || d_indicators["7"].isVoid()) break;
  184. // cal_mc_monthly_indicators 返回个两重字典,分别对应 curve_type 和不同区间的数据表,将同样区间的数据表(但不同curve_type)合并
  185. // curve_type: 1:私募,4:公募,7:公私募综合
  186. trailing_num = d_indicators["7"].keys().size();
  187. for(k in d_indicators["7"].keys()) {
  188. if(!d_indicators["1"].isVoid())
  189. d_indicators["7"][k].append!(d_indicators["1"][k]);
  190. if(!d_indicators["4"].isVoid())
  191. d_indicators["7"][k].append!(d_indicators["4"][k]);
  192. }
  193. indicators = d_indicators["7"];
  194. d_indicators = null;
  195. //
  196. // 按照 MySQL 建好各表
  197. if(indicator_type == 'PBI') {
  198. entity_info = SELECT entity_id, curve_type, strategy, price_date.temporalParse('yyyy-MM') AS price_date FROM entity_date;
  199. tb_mc_performance = create_mc_performance();
  200. tb_mc_indicator = create_mc_indicator();
  201. tb_mc_risk_stats = create_mc_risk_stats();
  202. tb_mc_riskadjret_stats = create_mc_riskadjret_stats();
  203. tb_mc_style_stats = create_mc_style_stats();
  204. // 写入数据
  205. generate_entity_performance(entity_info, indicators, true, tb_mc_performance, ['curve_type', 'strategy']);
  206. generate_entity_indicator(entity_info, indicators, true, tb_mc_indicator, ['curve_type', 'strategy']);
  207. generate_entity_risk_stats(entity_info, indicators, true, tb_mc_risk_stats, ['curve_type', 'strategy']);
  208. generate_entity_riskadjret_stats(entity_info, indicators, true, tb_mc_riskadjret_stats, ['curve_type', 'strategy']);
  209. generate_entity_style_stats(entity_info, indicators, true, tb_mc_style_stats, ['curve_type', 'strategy']);
  210. if(! tb_mc_performance.isVoid() && tb_mc_performance.size() > 0) {
  211. // save data to MySQL (13s)
  212. try {
  213. entity_id_col = iif(entity_type == 'PL', 'manager_id', 'company_id');
  214. chg_columns_for_mysql(tb_mc_performance, entity_id_col);
  215. save_and_sync(tb_mc_performance, iif(entity_type == 'PL', 'raw_db.manager_performance', 'raw_db.company_performance'), , entity_id_col, 'end_date');
  216. chg_columns_for_mysql(tb_mc_indicator, iif(entity_type == 'PL', 'manager_id', 'company_id'));
  217. save_and_sync(tb_mc_indicator, iif(entity_type == 'PL', 'raw_db.manager_indicator', 'raw_db.company_indicator'), , entity_id_col, 'end_date');
  218. chg_columns_for_mysql(tb_mc_risk_stats, iif(entity_type == 'PL', 'manager_id', 'company_id'));
  219. save_and_sync(tb_mc_risk_stats, iif(entity_type == 'PL', 'raw_db.manager_risk_stats', 'raw_db.company_risk_stats'), , entity_id_col, 'end_date');
  220. chg_columns_for_mysql(tb_mc_riskadjret_stats, iif(entity_type == 'PL', 'manager_id', 'company_id'));
  221. save_and_sync(tb_mc_riskadjret_stats, iif(entity_type == 'PL', 'raw_db.manager_riskadjret_stats', 'raw_db.company_riskadjret_stats'), , entity_id_col, 'end_date');
  222. chg_columns_for_mysql(tb_mc_style_stats, iif(entity_type == 'PL', 'manager_id', 'company_id'));
  223. save_and_sync(tb_mc_style_stats, iif(entity_type == 'PL', 'raw_db.manager_style_stats', 'raw_db.company_style_stats'), , entity_id_col, 'end_date');
  224. // 数据初始化时将指标存入本地
  225. if(is_save_local == true) {
  226. save_table(tb_mc_performance, iif(entity_type == 'PL', 'mfdb.manager_performance', 'mfdb.company_performance'), false);
  227. save_table(tb_mc_indicator, iif(entity_type == 'PL', 'mfdb.manager_indicator', 'mfdb.company_indicator'), false);
  228. save_table(tb_mc_risk_stats, iif(entity_type == 'PL', 'mfdb.manager_risk_stats', 'mfdb.company_risk_stats'), false);
  229. save_table(tb_mc_riskadjret_stats, iif(entity_type == 'PL', 'mfdb.manager_riskadjret_stats', 'mfdb.company_riskadjret_stats'), false);
  230. save_table(tb_mc_style_stats, iif(entity_type == 'PL', 'mfdb.manager_style_stats', 'mfdb.company_style_stats'), false);
  231. }
  232. } catch(ex) {
  233. //TODO: Log errors
  234. rt += ex;
  235. }
  236. }
  237. } else {
  238. entity_info = SELECT entity_id, curve_type, strategy, end_date.temporalParse('yyyy-MM') AS end_date, factor_id AS benchmark_id FROM entity_date;
  239. tb_mc_bfi_indicator = create_mc_bfi_indicator();
  240. //tb_mc_bfi_indicator.rename!('factor_id', 'benchmark_id');
  241. generate_entity_bfi_indicator(entity_info, indicators, true, tb_mc_bfi_indicator, ['curve_type', 'strategy']);
  242. if(! tb_mc_bfi_indicator.isVoid() && tb_mc_bfi_indicator.size() > 0) {
  243. // save data to MySQL
  244. try {
  245. entity_id_col = iif(entity_type == 'PL', 'manager_id', 'company_id');
  246. chg_columns_for_mysql(tb_mc_bfi_indicator, entity_id_col);
  247. save_and_sync(tb_mc_bfi_indicator, iif(entity_type == 'PL', 'raw_db.manager_ty_bfi_bm_indicator', 'raw_db.company_ty_bfi_bm_indicator'), , entity_id_col, 'end_date');
  248. // 数据初始化时将指标存入本地
  249. if(is_save_local == true)
  250. save_table(tb_mc_bfi_indicator, iif(entity_type == 'PL', 'mfdb.manager_ty_bfi_bm_indicator', 'mfdb.company_ty_bfi_bm_indicator'), false);
  251. } catch(ex) {
  252. //TODO: Log errors
  253. rt = ex;
  254. }
  255. }
  256. }
  257. return rt;
  258. }
  259. /*
  260. * [定时任务]: 基金经理/公司月净值计算
  261. *
  262. * Example: CalMCMonthlyNavTask('CO', 2024.12.01);
  263. */
  264. def CalMCMonthlyNavTask(entity_type, updatetime) {
  265. //updatetime = 2024.12.01;
  266. //entity_type = 'CO';
  267. if(!(entity_type IN ['PL', 'CO'])) return;
  268. is_save_local = iif(updatetime <= get_ini_data_const()['updatetime'], true, false);
  269. // 31 sec 简化起见,不区分curve_type, strategy; TODO: 性能能否优化?
  270. if(entity_type == 'PL') {
  271. entity_date = get_manager_list_by_fund_updatetime(updatetime);
  272. entity_date.rename!('manager_id', 'entity_id');
  273. }
  274. else {
  275. entity_date = get_company_list_by_fund_updatetime(updatetime);
  276. entity_date.rename!('company_id', 'entity_id');
  277. }
  278. // 15 sec
  279. cal_and_save_mc_monthly_nav(entity_type, entity_date, is_save_local);
  280. entity_date = null;
  281. }
  282. /*
  283. * [定时任务]: 基金经理/公司月收益及指标(含标准及BFI)计算
  284. *
  285. * @param entity_type <STRING>: PL, CO
  286. *
  287. * Example: CalMCIndicatorTask('CO', 2024.12.01);
  288. * CalMCIndicatorTask('PL', 2024.12.01);
  289. */
  290. def CalMCIndicatorTask(entity_type, updatetime) {
  291. // entity_type = 'CO';
  292. // updatetime = 2024.12.01
  293. rt = '';
  294. is_save_local = iif(updatetime <= get_ini_data_const()['updatetime'], true, false);
  295. // 3 sec
  296. entity_date = get_entity_list_by_nav_updatetime(entity_type, NULL, updatetime, true);
  297. i = 0;
  298. batch_size = 1000;
  299. v_entity_id = entity_date.entity_id.distinct();
  300. max_cnt = v_entity_id.size();
  301. ver_old_month = 1900.01M;
  302. do {
  303. // 取完整月净值
  304. tb_entity_date = SELECT entity_id, curve_type, strategy, ver_old_month AS effective_date
  305. FROM entity_date WHERE entity_id in v_entity_id[i : min(i + batch_size, max_cnt)];
  306. if(tb_entity_date.isVoid() || tb_entity_date.size() == 0) break;
  307. s_json = tb_entity_date.toStdJson();
  308. tb_nav = get_mc_nav_for_return_calculation(entity_type, s_json, 0);
  309. v_end_date = tb_nav.effective_date.temporalParse('yyyy-MM');
  310. tb_nav.replaceColumn!('effective_date', v_end_date);
  311. tb_nav.join!(v_end_date.temporalFormat('yyyy-MM-dd').temporalParse('yyyy-MM-dd').businessMonthEnd() AS price_date);
  312. tb_nav.sortBy!(['entity_id', 'curve_type', 'strategy', 'effective_date']);
  313. // 计算月度收益
  314. tb_monthly_ret = SELECT entity_id, curve_type, strategy, effective_date AS end_date, price_date, cumulative_nav AS nav, cumulative_nav.ratios()-1 AS ret
  315. FROM tb_nav
  316. CONTEXT BY entity_id, curve_type, strategy;
  317. // 40+ min
  318. cal_and_save_mc_indicator(entity_type, entity_date, tb_monthly_ret, 'PBI', is_save_local);
  319. i += batch_size;
  320. } while (i < max_cnt);
  321. }
  322. /*
  323. * [定时任务]: 基金经理月BFI指标计算
  324. *
  325. *
  326. * Example: CalManagerBfiIndicatorTask(2024.11.04);
  327. */
  328. def CalManagerBfiIndicatorTask(updatetime) {
  329. // updatetime = 2024.11.01
  330. rt = '';
  331. entity_type = 'PL';
  332. is_save_local = iif(updatetime <= get_ini_data_const()['updatetime'], true, false);
  333. // BFI indicator 计算由 bfi matching 表更新驱动
  334. entity_date = get_mc_bfi_factors(entity_type, NULL, 1990.01M, today().month(), updatetime);
  335. entity_date.join!(entity_date.end_date AS price_date);
  336. i = 0;
  337. batch_size = 1000;
  338. v_entity_id = entity_date.entity_id.distinct();
  339. max_cnt = v_entity_id.size();
  340. do {
  341. // 取完整月收益 1+ min
  342. tb_monthly_ret = get_monthly_ret(entity_type, v_entity_id[i : min(i + batch_size, max_cnt)], 1900.01.01, today(), true);
  343. v_end_date = tb_monthly_ret.end_date.temporalParse('yyyy-MM');
  344. tb_monthly_ret.replaceColumn!('end_date', v_end_date);
  345. UPDATE tb_monthly_ret SET price_date = end_date.temporalFormat('yyyy-MM-dd').temporalParse('yyyy-MM-dd').businessMonthEnd() WHERE price_date IS NULL;
  346. // 40+ min
  347. cal_and_save_mc_indicator(entity_type, entity_date, tb_monthly_ret, 'BFI', is_save_local);
  348. i += batch_size;
  349. } while (i < max_cnt);
  350. }
  351. /*
  352. *
  353. * [定时任务]: 基金经理的BFI MATCHING
  354. *
  355. * it takes 16 min
  356. */
  357. def MatchManagerBFITask(updatetime) {
  358. rt = '';
  359. is_save_local = iif(updatetime <= get_ini_data_const()['updatetime'], true, false);
  360. entity_type = 'PL';
  361. // 31 sec
  362. entity_date = get_mc_performance_by_updatetime(entity_type, updatetime);
  363. if(entity_date.isVoid() || entity_date.size() == 0) return rt;
  364. i = 0;
  365. batch_size = 1000;
  366. max_cnt = entity_date.size();
  367. do {
  368. t_entity_date = entity_date[i : min(max_cnt, i + batch_size)];
  369. // 22 min per 1000 records, way too slow
  370. t_bfi = match_mc_bfi(entity_type, t_entity_date);
  371. t_max_r2 = SELECT entity_id , curve_type, strategy, factor_id.first() AS factor_id, end_date,
  372. string(NULL) AS performance_flag, coe.first() AS coe, r2.first() AS r2, concat(factor_name, ",") AS rz_portrait
  373. FROM ej(t_bfi, get_bfi_index_list(), 'factor_id')
  374. GROUP BY entity_id, curve_type, strategy, end_date;
  375. try {
  376. // 高度怀疑 pf_manager_factor_bfi 表只是中间表,没有用,这里就不存了
  377. // 有效 factors 存到 xxx_factor_bfi_by_category_group 表
  378. chg_columns_for_mysql(t_bfi, 'manager_id');
  379. save_and_sync(t_bfi, 'raw_db.pf_manager_factor_bfi_by_category_group', , 'manager_id', 'end_date');
  380. // 有效因子中 R2 最大的因子存 xxx_max_r2
  381. chg_columns_for_mysql(t_max_r2, 'manager_id');
  382. save_and_sync(t_max_r2, 'raw_db.pf_manager_factor_bfi_max_r2', , 'manager_id', 'end_date');
  383. } catch (ex) {
  384. //TODO: Log errors
  385. rt += ex;
  386. }
  387. i += batch_size
  388. } while (i < max_cnt);
  389. return rt;
  390. }