bfiMatcher.dos 3.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. module fundit::bfiMatcher
  2. use fundit::sqlUtilities
  3. use fundit::dataPuller
  4. /*
  5. * 取BFI所需要的指数/因子ID
  6. *
  7. * NOTE: Java使用的逻辑如下(除了FA),暂时没有差别
  8. * SELECT a.fund_Id FROM mfdb.fund_performance AS a
  9. LEFT JOIN pfdb.cm_class_asset_index AS b ON a.fund_id = b.index_id
  10. WHERE a.end_date = 'YYYY-MM' AND a.fund_id LIKE 'IN%' AND b.isvalid = 1 ORDER BY a.fund_id ASC
  11. */
  12. def get_bfi_index_list() {
  13. return ['FA00000VML','FA00000VMM','FA00000VMN','FA00000VMO','FA00000WKG','FA00000WKH','IN00000008','IN0000000D','IN0000000M','IN0000000S',
  14. 'IN0000000T','IN0000000U','IN0000000V','IN0000000W','IN0000000X','IN0000000Y','IN0000000Z','IN00000010','IN00000011','IN00000012',
  15. 'IN00000013','IN00000014','IN00000015','IN00000016','IN00000017','IN00000077','IN00000078','IN00000079','IN0000007A','IN0000007B',
  16. 'IN0000007C','IN0000007D','IN0000007E','IN0000007F','IN0000007G','IN0000007M','IN0000007N','IN0000007O','IN00000080','IN00000088',
  17. 'IN0000008O','IN0000009M','IN0000028E','IN000002CM'];
  18. }
  19. /*
  20. * 计算收益月度相关性
  21. *
  22. * @param ret1 <TABLE>: NEED COLUMN entity_id, price_date, ret
  23. * @param ret2 <TABLE>: NEED COLUMN entity_id, price_date, ret
  24. * @param win <DURATION>: 1y, 3y, 5y
  25. *
  26. * NOTE: price_date 应统一为各周中的同一天(比如周收益都用 price_date.weekEnd(4) 转化为周五, 月收益都用 price_date.monthEnd() 转为月末日
  27. */
  28. def cal_monthly_correlation(ret1, ret2, win) {
  29. t = SELECT r1.price_date, tmcorr(r1.price_date, r1.ret, r2.ret, win) AS corr
  30. FROM ret1 r1
  31. LEFT JOIN ret2 r2 ON r1.price_date = r2.price_date
  32. ORDER BY r1.price_date;
  33. return SELECT price_date.month()[0] AS end_date, corr.last() AS corr FROM t WHERE corr IS NOT NULL GROUP BY price_date.month();
  34. }
  35. /*
  36. * 计算目标和BFI所用指数因子的相关系数
  37. *
  38. * NOTE: 与Java把月末日期作为截止日期不同的是,这里用每月最后一个周五作为截止日,所以数值会与MySQL中存储的略为不同
  39. *
  40. */
  41. def cal_entity_index_coe(entity_type, entity_info) {
  42. if(entity_info.isVoid() || entity_info.size() == 0) return null;
  43. // 简单起见,取数据集中最新日期作为截止日期
  44. end_day = entity_info.price_date.max();
  45. ret_entity = get_entity_weekly_rets(entity_type, entity_info);
  46. if(ret_entity.isVoid() || ret_entity.size() == 0) return null;
  47. // 取BFI用得到的指数/因子列表
  48. v_indexes = get_bfi_index_list();
  49. // 手搓一个带日期的数据表
  50. index_info = table(v_indexes AS entity_id, take(end_day, v_indexes.size()) AS price_date);
  51. ret_index = get_entity_weekly_rets('MI', index_info);
  52. if(ret_index.isVoid() || ret_index.size() == 0) return null;
  53. // 两次循环遍历所有entity和指数
  54. entity_coe = table(1000:0, ['entity_id', 'index_id', 'end_date', 'coe_1y', 'coe_3y', 'coe_5y'],
  55. [SYMBOL, SYMBOL, MONTH, DOUBLE, DOUBLE, DOUBLE]);
  56. for(entity in entity_info.entity_id) {
  57. for(index in v_indexes) {
  58. ret1 = SELECT fund_id, price_date.weekEnd(4) AS price_date, ret_1w AS ret FROM ret_entity WHERE fund_id = entity AND price_date.weekEnd(4) <= end_day;
  59. ret2 = SELECT index_id, price_date.weekEnd(4) AS price_date, ret_1w AS ret FROM ret_index WHERE index_id = index AND price_date.weekEnd(4) <= end_day;
  60. corr_1y = cal_monthly_correlation(ret1, ret2, 1y);
  61. corr_3y = cal_monthly_correlation(ret1, ret2, 3y);
  62. corr_5y = cal_monthly_correlation(ret1, ret2, 5y);
  63. INSERT INTO entity_coe
  64. SELECT entity, index, corr_1y.end_date, corr_1y.corr AS coe_1y, corr_3y.corr AS coe_3y, corr_5y.corr AS coe_5y
  65. FROM corr_1y
  66. LEFT JOIN corr_3y ON corr_1y.end_date = corr_3y.end_date
  67. LEFT JOIN corr_5y ON corr_1y.end_date = corr_5y.end_date;
  68. }
  69. }
  70. return entity_coe;
  71. }