Browse Source

上传文件至 'modules'

Joey 6 months ago
parent
commit
f66dba769a
1 changed files with 93 additions and 103 deletions
  1. 93 103
      modules/indicatorCalculator.dos

+ 93 - 103
modules/indicatorCalculator.dos

@@ -64,40 +64,6 @@ defg maxDrawdown(navs) {
 
 
 
 
 /*
 /*
- *   取主基准和BFI的历史月收益率
- *   
- *   @param benchmarks <TABLE>: entity-benchmark 的对应关系表
- *   @param end_day <DATE>: 收益的截止日期
- * 
- *   @return <TABLE>: benchmark_id, end_date, ret
- *   
- */
-def get_benchmark_return(benchmarks, end_day) {
-
-    s_index_ids = '';
-    s_factor_ids = '';
-
-    if(benchmarks.isVoid() || benchmarks.size() == 0) { return null; }
-
-    // 前缀为 IN 的 benchmark id
-    t_index_id = SELECT DISTINCT benchmark_id FROM benchmarks WHERE benchmark_id LIKE 'IN%';
-    s_index_ids = iif(isVoid(t_index_id), "", "'" + t_index_id.benchmark_id.concat("','") + "'");
-
-   // 前缀为 FA 的 benchmark id
-   t_factor_id = SELECT DISTINCT benchmark_id FROM benchmarks WHERE benchmark_id LIKE 'FA%';
-   s_factor_ids = iif(isVoid(t_factor_id), "",  "'" + t_factor_id.benchmark_id.concat("','") + "'");
-
-
-    // 目前指数的月度业绩存在 fund_performance 表
-    t_bmk = SELECT fund_id AS benchmark_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_monthly_ret('IX', s_index_ids, 1990.01.01, end_day, true);
-
-    // 而因子的月度业绩存在 cm_factor_performance 表
-    INSERT INTO t_bmk SELECT factor_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_monthly_ret('FA', s_factor_ids, 1990.01.01, end_day, true);
-
-	return t_bmk;
-}
-
-/*
  *   Trailing Monthly Return, Standard Deviation, Skewness, Kurtosis, Max Drawdown, VaR, CVaR, Calmar Ratio
  *   Trailing Monthly Return, Standard Deviation, Skewness, Kurtosis, Max Drawdown, VaR, CVaR, Calmar Ratio
  *     
  *     
  *   @param entity_info <TABLE>: xxx_information表,NEED COLUMNS entity_id, inception_date
  *   @param entity_info <TABLE>: xxx_information表,NEED COLUMNS entity_id, inception_date
@@ -1026,9 +992,75 @@ def cal_trailing_bfi_indicators(entity_info, benchmarks, end_day, tb_ret, bmk_re
 
 
 
 
 /*
 /*
+ *   通用月度指标计算
+ * 
+ *   @param entity_type <STRING>:
+ *   @param indicator_type <STRING>: PBI, BFI
+ *   @param monthly_returns <TABLE>: NEED COLUMN: entity_id, end_date, price_date, nav, ret
+ * 
+ *   @return <DICT TABLE>: ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y', 'MS-3Y', 'MS-5Y', 'MS-10Y']
+ * 
+ */
+def cal_monthly_indicators(entity_type, indicator_type, monthly_returns) {
+
+    if(find(['MF', 'HF', 'PF'], entity_type) < 0) return null;
+
+    if(monthly_returns.isVoid() || monthly_returns.size() < 1) return null;
+
+    oldest_date = EXEC price_date.min() FROM monthly_returns;
+
+    v_entity_ids = (SELECT DISTINCT entity_id FROM monthly_returns).entity_id;
+    
+    entity_info = get_entity_info(entity_type, v_entity_ids);
+    
+    if(entity_info.isVoid() || entity_info.size() == 0) { return null };
+    
+    end_day = today();
+
+    // 取基金和基准的对照表
+    if(indicator_type == 'BFI') {
+
+        benchmark = SELECT fund_id AS entity_id, end_date.temporalParse('yyyy-MM') AS end_date, factor_id AS benchmark_id 
+                    FROM get_fund_bfi_factors(v_entity_ids, oldest_date.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM'));
+
+    } else {
+        // 主基准, 对应 xxx_info 中的 primary_benchmark_id
+        benchmark = SELECT entity_id, end_date, iif(benchmark_id.isNull(), 'IN00000008', benchmark_id) AS benchmark_id 
+                    FROM get_entity_primary_benchmark(entity_type, v_entity_ids, oldest_date.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM')) ;
+    	
+    }
+
+    // 取所有出现的基准月收益
+    bmk_ret = get_benchmark_return(benchmark, end_day);
+
+    if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
+
+    // TODO: risk free指数月收益存在fund_performance表,所以先将就用 fund_id 表示。之后统一改为更准确的名字
+    risk_free_rate = SELECT entity_id AS fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(oldest_date, end_day);
+
+    if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
+
+    // 指标计算
+    if(indicator_type == 'BFI') {
+
+        t0 = cal_trailing_bfi_indicators(entity_info, benchmark, end_day, monthly_returns, bmk_ret, risk_free_rate);
+
+        v_table_name = ['BFI-INCEP', 'BFI-YTD', 'BFI-6M', 'BFI-1Y', 'BFI-2Y', 'BFI-3Y', 'BFI-4Y', 'BFI-5Y', 'BFI-10Y'];
+
+    } else {
+
+        t0 = cal_trailing_indicators(entity_info, benchmark, end_day, monthly_returns, bmk_ret, risk_free_rate);
+
+        v_table_name = ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y'];
+    }
+
+    return dict(v_table_name, t0);
+	
+}
+/*
  *   Calculate historcial fund trailing indicators 
  *   Calculate historcial fund trailing indicators 
  * 
  * 
- *   @param entity_type <STRING>: MF, HF
+ *   @param fund_type <STRING>: MF, HF
  *   @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
  *   @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
  *   @param end_day <DATE>: 要计算的日期
  *   @param end_day <DATE>: 要计算的日期
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
@@ -1036,68 +1068,43 @@ def cal_trailing_bfi_indicators(entity_info, benchmarks, end_day, tb_ret, bmk_re
  *   
  *   
  *   @return <DICT TABLE>: ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y', 'MS-3Y', 'MS-5Y', 'MS-10Y']
  *   @return <DICT TABLE>: ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y', 'MS-3Y', 'MS-5Y', 'MS-10Y']
  *   
  *   
- *   TODO: primary_benchmark_id seems not be used as benchmark, when it is FA00000VNB
  * 
  * 
  *   Example: cal_fund_indicators('HF', "'HF000004KN','HF000103EU','HF00018WXG'", 2024.06.28, true);
  *   Example: cal_fund_indicators('HF', "'HF000004KN','HF000103EU','HF00018WXG'", 2024.06.28, true);
  * 
  * 
  */
  */
-def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
+def cal_fund_indicators(fund_type, fund_ids, end_day, isFromNav) {
 
 
     very_old_date = 1990.01.01;
     very_old_date = 1990.01.01;
 
 
-    start_month = 1990.01M;
-
-    fund_info = get_fund_info(fund_ids);
-    
-    if(fund_info.isVoid() || fund_info.size() == 0) { return null };
-    
-    fund_info.rename!('fund_id', 'entity_id');
-
     if(isFromNav == true) {
     if(isFromNav == true) {
+
         // 从净值开始计算收益
         // 从净值开始计算收益
-        tb_ret = SELECT * FROM cal_fund_monthly_returns(entity_type, fund_ids, true) WHERE price_date <= end_day;
+        tb_ret = SELECT * FROM cal_fund_monthly_returns(fund_type, fund_ids, true) WHERE price_date <= end_day;
         tb_ret.rename!(['fund_id', 'cumulative_nav'], ['entity_id', 'nav']);
         tb_ret.rename!(['fund_id', 'cumulative_nav'], ['entity_id', 'nav']);
+
     } else {
     } else {
+
         // 从fund_performance表里读月收益
         // 从fund_performance表里读月收益
-        tb_ret = get_monthly_ret('FD', fund_ids, very_old_date, end_day, true);
-        tb_ret.rename!(['fund_id'], ['entity_id']);
+        tb_ret = get_monthly_ret(fund_type, fund_ids, very_old_date, end_day, true);
+    
         v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
         v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
         tb_ret.replaceColumn!('end_date', v_end_date);
         tb_ret.replaceColumn!('end_date', v_end_date);
+
     }
     }
 
 
     if(tb_ret.isVoid() || tb_ret.size() == 0) { return null; }
     if(tb_ret.isVoid() || tb_ret.size() == 0) { return null; }
 
 
-    // 取基金和基准的对照表
-    primary_benchmark = SELECT fund_id AS entity_id, end_date, iif(benchmark_id.isNull(), 'IN00000008', benchmark_id) AS benchmark_id 
-                        FROM get_fund_primary_benchmark(fund_ids, start_month.temporalFormat('yyyy-MM'), end_day.month().temporalFormat('yyyy-MM')) ;
-
-    // 取所有出现的基准月收益
-    bmk_ret = get_benchmark_return(primary_benchmark, end_day);
-
-    if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
-
-    risk_free_rate = SELECT fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
-
-    if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
-
     // 标准的指标
     // 标准的指标
-    t0 = cal_trailing_indicators(fund_info, primary_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
+    d = cal_monthly_indicators(fund_type, 'PBI', tb_ret);
 
 
-    // Morningstar 指标
-    //t1 = cal_trailing_ms_indicators(fund_info, tb_ret, end_day, risk_free_rate);
+    return d;
 
 
-    // PBI stands for "Primary Benchmark Index", MS stands for "MorningStar"
-    v_table_name = ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y'/*, 'MS-3Y', 'MS-5Y', 'MS-10Y'*/];
-
-    return dict(v_table_name, t0);
-//    return dict(v_table_name, t0 <- t1[5] <- t1[7] <- t1[8]);
-    
 }
 }
 
 
 /*
 /*
  *   Calculate historcial fund trailing BFI indicators 
  *   Calculate historcial fund trailing BFI indicators 
  * 
  * 
- *   @param entity_type <STRING>: MF, HF
+ *   @param fund_type <STRING>: MF, HF
  *   @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
  *   @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
  *   @param end_day <DATE>: 要计算的日期
  *   @param end_day <DATE>: 要计算的日期
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
@@ -1105,56 +1112,37 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
  *   
  *   
  *   @return <DICT TABLE>: ['BFI-INCEP', 'BFI-YTD', 'BFI-6M', 'BFI-1Y', 'BFI-2Y', 'BFI-3Y', 'BFI-4Y', 'BFI-5Y', 'BFI-10Y']
  *   @return <DICT TABLE>: ['BFI-INCEP', 'BFI-YTD', 'BFI-6M', 'BFI-1Y', 'BFI-2Y', 'BFI-3Y', 'BFI-4Y', 'BFI-5Y', 'BFI-10Y']
  *   
  *   
- *   TODO: primary_benchmark_id seems not be used as benchmark, when it is FA00000VNB
- *   TODO: intergrate with cal_fund_indicators
  * 
  * 
  *   Example: cal_fund_bfi_indicators('MF', "'MF00003PW2', 'MF00003PW1', 'MF00003PXO'", 2024.08.31, true);
  *   Example: cal_fund_bfi_indicators('MF', "'MF00003PW2', 'MF00003PW1', 'MF00003PXO'", 2024.08.31, true);
  * 
  * 
  */
  */
-def cal_fund_bfi_indicators(entity_type, fund_ids, end_day, isFromNav) {
+def cal_fund_bfi_indicators(fund_type, fund_ids, end_day, isFromNav) {
 
 
     very_old_date = 1990.01.01;
     very_old_date = 1990.01.01;
 
 
-    start_month = 1990.01M;
-
-    fund_info = get_fund_info(fund_ids);
-    
-    if(fund_info.isVoid() || fund_info.size() == 0) { return null };
-    
-    fund_info.rename!('fund_id', 'entity_id');
-
     if(isFromNav == true) {
     if(isFromNav == true) {
+
         // 从净值开始计算收益
         // 从净值开始计算收益
-        tb_ret = SELECT * FROM cal_fund_monthly_returns(entity_type, fund_ids, true) WHERE price_date <= end_day;
+        tb_ret = SELECT * FROM cal_fund_monthly_returns(fund_type, fund_ids, true) WHERE price_date <= end_day;
         tb_ret.rename!(['fund_id', 'cumulative_nav'], ['entity_id', 'nav']);
         tb_ret.rename!(['fund_id', 'cumulative_nav'], ['entity_id', 'nav']);
+
     } else {
     } else {
+
         // 从fund_performance表里读月收益
         // 从fund_performance表里读月收益
-        tb_ret = get_monthly_ret('FD', fund_ids, very_old_date, end_day, true);
+        tb_ret = get_monthly_ret(fund_type, fund_ids, very_old_date, end_day, true);
         tb_ret.rename!(['fund_id'], ['entity_id']);
         tb_ret.rename!(['fund_id'], ['entity_id']);
+    
         v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
         v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
         tb_ret.replaceColumn!('end_date', v_end_date);
         tb_ret.replaceColumn!('end_date', v_end_date);
+
     }
     }
 
 
     if(tb_ret.isVoid() || tb_ret.size() == 0) { return null; }
     if(tb_ret.isVoid() || tb_ret.size() == 0) { return null; }
 
 
-    // 取基金和基准的对照表
-    bfi_benchmark = SELECT fund_id AS entity_id, end_date.temporalParse('yyyy-MM') AS end_date, factor_id AS benchmark_id 
-                           FROM get_fund_bfi_factors(fund_ids, start_month.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM'));
-
-    if(bfi_benchmark.isVoid() || bfi_benchmark.size() == 0) { return null; }
-
-    bmk_ret = get_benchmark_return(bfi_benchmark, end_day);
-
-    risk_free_rate = SELECT fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
-
-    if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
-
-    t0 = cal_trailing_bfi_indicators(fund_info, bfi_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
+    // BFI指标
+    d = cal_monthly_indicators(fund_type, 'BFI', tb_ret);
 
 
-    // BFI stands for "Best Fit Index"
-    v_table_name = ['BFI-INCEP', 'BFI-YTD', 'BFI-6M', 'BFI-1Y', 'BFI-2Y', 'BFI-3Y', 'BFI-4Y', 'BFI-5Y', 'BFI-10Y'];
-    
-    return dict(v_table_name, t0);
+    return d;
 }
 }
 
 
 /*
 /*
@@ -1215,7 +1203,8 @@ def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
 
 
     if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
     if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
 
 
-    risk_free_rate = SELECT fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
+    // TODO: risk free指数月收益存在fund_performance表,所以先将就用 fund_id 表示。之后统一改为更准确的名字
+    risk_free_rate = SELECT entity_id AS fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
 
 
     if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
     if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
 
 
@@ -1286,7 +1275,8 @@ def cal_portfolio_bfi_indicators(portfolio_ids, end_day, cal_method, isFromNav)
 
 
     if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
     if(bmk_ret.isVoid() || bmk_ret.size() == 0) { return null; }
 
 
-    risk_free_rate = SELECT fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
+    // TODO: risk free指数月收益存在fund_performance表,所以先将就用 fund_id 表示。之后统一改为更准确的名字
+    risk_free_rate = SELECT entity_id AS fund_id, temporalParse(end_date, 'yyyy-MM') AS end_date, ret FROM get_risk_free_rate(very_old_date, end_day);
 
 
     if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
     if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }