module fundit::bfiMatcher
use fundit::sqlUtilities
use fundit::dataPuller
/*
* 取BFI所需要的指数/因子ID
*
* NOTE: Java使用的逻辑如下(除了FA),暂时没有差别
* SELECT a.fund_Id FROM mfdb.fund_performance AS a
LEFT JOIN pfdb.cm_class_asset_index AS b ON a.fund_id = b.index_id
WHERE a.end_date = 'YYYY-MM' AND a.fund_id LIKE 'IN%' AND b.isvalid = 1 ORDER BY a.fund_id ASC
*/
def get_bfi_index_list() {
return ['FA00000VML','FA00000VMM','FA00000VMN','FA00000VMO','FA00000WKG','FA00000WKH','IN00000008','IN0000000D','IN0000000M','IN0000000S',
'IN0000000T','IN0000000U','IN0000000V','IN0000000W','IN0000000X','IN0000000Y','IN0000000Z','IN00000010','IN00000011','IN00000012',
'IN00000013','IN00000014','IN00000015','IN00000016','IN00000017','IN00000077','IN00000078','IN00000079','IN0000007A','IN0000007B',
'IN0000007C','IN0000007D','IN0000007E','IN0000007F','IN0000007G','IN0000007M','IN0000007N','IN0000007O','IN00000080','IN00000088',
'IN0000008O','IN0000009M','IN0000028E','IN000002CM'];
}
/*
* 计算收益月度相关性
*
* @param ret1
: NEED COLUMN entity_id, price_date, ret
* @param ret2 : NEED COLUMN entity_id, price_date, ret
* @param win : 1y, 3y, 5y
*
* NOTE: price_date 应统一为各周中的同一天(比如周收益都用 price_date.weekEnd(4) 转化为周五, 月收益都用 price_date.monthEnd() 转为月末日
*/
def cal_monthly_correlation(ret1, ret2, win) {
t = SELECT r1.price_date, tmcorr(r1.price_date, r1.ret, r2.ret, win) AS corr
FROM ret1 r1
LEFT JOIN ret2 r2 ON r1.price_date = r2.price_date
ORDER BY r1.price_date;
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();
}
/*
* 计算目标和BFI所用指数因子的相关系数
*
* NOTE: 与Java把月末日期作为截止日期不同的是,这里用每月最后一个周五作为截止日,所以数值会与MySQL中存储的略为不同
*
*/
def cal_entity_index_coe(entity_type, entity_info) {
if(entity_info.isVoid() || entity_info.size() == 0) return null;
// 简单起见,取数据集中最新日期作为截止日期
end_day = entity_info.price_date.max();
ret_entity = get_entity_weekly_rets(entity_type, entity_info);
if(ret_entity.isVoid() || ret_entity.size() == 0) return null;
// 取BFI用得到的指数/因子列表
v_indexes = get_bfi_index_list();
// 手搓一个带日期的数据表
index_info = table(v_indexes AS entity_id, take(end_day, v_indexes.size()) AS price_date);
ret_index = get_entity_weekly_rets('MI', index_info);
if(ret_index.isVoid() || ret_index.size() == 0) return null;
// 两次循环遍历所有entity和指数
entity_coe = table(1000:0, ['entity_id', 'index_id', 'end_date', 'coe_1y', 'coe_3y', 'coe_5y'],
[SYMBOL, SYMBOL, MONTH, DOUBLE, DOUBLE, DOUBLE]);
for(entity in entity_info.entity_id) {
for(index in v_indexes) {
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;
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;
corr_1y = cal_monthly_correlation(ret1, ret2, 1y);
corr_3y = cal_monthly_correlation(ret1, ret2, 3y);
corr_5y = cal_monthly_correlation(ret1, ret2, 5y);
INSERT INTO entity_coe
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
FROM corr_1y
LEFT JOIN corr_3y ON corr_1y.end_date = corr_3y.end_date
LEFT JOIN corr_5y ON corr_1y.end_date = corr_5y.end_date;
}
}
return entity_coe;
}