Joey 1 هفته پیش
والد
کامیت
aec1c39931
1فایلهای تغییر یافته به همراه101 افزوده شده و 103 حذف شده
  1. 101 103
      modules/indicatorCalculator.dos

+ 101 - 103
modules/indicatorCalculator.dos

@@ -401,7 +401,7 @@ def cal_indicators_with_benchmark(mutable ret, benchmarks, index_ret, risk_free)
 
 /*
  *   Monthly standard indicator calculation
- *   @param: ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
+ *   @param ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
  *   @param benchmarks <TABLE>: entity-benchmark mapping table
  *   @param benchmark_ret <TABLE>: historical benchmark return table, NEED COLUMNS fund_id, end_date, ret
  *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
@@ -459,7 +459,7 @@ def cal_indicators(mutable ret, benchmarks, benchmark_ret, risk_free) {
 
 /*
  *   Monthly BFI indicator calculation
- *   @param: ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
+ *   @param ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
  *   @param benchmarks <TABLE>: entity-benchmark mapping table
  *   @param benchmark_ret <TABLE>: historical benchmark return table, NEED COLUMNS fund_id, end_date, ret
  *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
@@ -479,17 +479,37 @@ def cal_bfi_indicators(mutable ret, benchmarks, benchmark_ret, risk_free) {
 }
 
 /*
- *   Calculate trailing 6m, ytd, 1y, 2y, 3y, 4y, 5y, 10y and since inception indicators
+ *   Monthly Morningstar indicator calculation
+ *   
+ *   @param ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
+ *   @param benchmarks <USELESS>:
+ *   @param benchmark_ret <USELESS>:
+ *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
+ * 
+ */
+def cal_ms_indicators(mutable ret, benchmarks, benchmark_ret, risk_free) {
+
+	r = cal_ms_return(ret, risk_free);
+
+	return r;
+}
+
+/*
+ *   Calculate trailing 6m, ytd, 1y, 2y, 3y, 4y, 5y, 10y and since inception datapoints
  *   
+ *   @param: func <FUNCTION>: the calculation function
  *   @param: entity_info <TABLE>: basic information of entity, NEED COLUMNS entity_id, inception_date
  *   @param benchmarks <TABLE>: entity-benchmark mapping table
  *   @param: ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
  *   @param: end_day <DATE>: 计算截止日期
  *   @param bmk_ret <TABLE>: historical benchmark return table, NEED COLUMNS fund_id, end_date, ret
  *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
+ *   @param periods <BOOL VECTOR>: 是否计算的区间向量,分别对应 incep, ytd, 6m, 1y, 2y, 3y, 4y, 5y, 10y
+ *   
+ *   Example: cal_trailing(
  * 
  */
-def cal_trailing_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bmk_ret, risk_free_rate) {
+def cal_trailing(func, entity_info, benchmarks, mutable tb_ret, end_day, bmk_ret, risk_free_rate, periods) {
 
     r_incep = null;
     r_ytd = null;
@@ -500,80 +520,74 @@ def cal_trailing_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bm
     r_4y = null;
     r_5y = null;
     r_10y = null;
-    r_ms_3y = null;
-    r_ms_5y = null;
-    r_ms_10y = null;
 
     // since inception
-    if(tb_ret.size() > 0) {
-        r_incep = cal_indicators(tb_ret, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret.size() > 0 && periods[0] == 1) {
+        r_incep = func(tb_ret, benchmarks, bmk_ret, risk_free_rate);
     }
 
     // ytd
     tb_ret_ytd = SELECT * FROM tb_ret WHERE end_date >= end_day.yearBegin().month();
-    if(tb_ret_ytd.size() > 0) {
-        r_ytd = cal_indicators(tb_ret_ytd, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret_ytd.size() > 0 && periods[1] == 1) {
+        r_ytd = func(tb_ret_ytd, benchmarks, bmk_ret, risk_free_rate);
     }
 
     // trailing 6m
     tb_ret_6m = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-6 AND (end_day.month() - ei.inception_date.month()) >= 6;
-    if(tb_ret_6m.size() > 0) {
-        r_6m = cal_indicators(tb_ret_6m, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret_6m.size() > 0 && periods[2] == 1) {
+        r_6m = func(tb_ret_6m, benchmarks, bmk_ret, risk_free_rate);
     }
     
     // trailing 1y
     tb_ret_1y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-12 AND (end_day.month() - ei.inception_date.month()) >= 12;
-    if(tb_ret_1y.size() > 0) {
-        r_1y = cal_indicators(tb_ret_1y, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret_1y.size() > 0 && periods[3] == 1) {
+        r_1y = func(tb_ret_1y, benchmarks, bmk_ret, risk_free_rate);
     }
     
     // trailing 2y
     tb_ret_2y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-24 AND (end_day.month() - ei.inception_date.month()) >= 24;
-    if(tb_ret_2y.size() > 0) {
-        r_2y = cal_indicators(tb_ret_2y, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret_2y.size() > 0 && periods[4] == 1) {
+        r_2y = func(tb_ret_2y, benchmarks, bmk_ret, risk_free_rate);
     }
     
     // trailing 3y
     tb_ret_3y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-36 AND (end_day.month() - ei.inception_date.month()) >= 36;
-    if(tb_ret_3y.size() > 0) {
-        r_3y = cal_indicators(tb_ret_3y, benchmarks, bmk_ret, risk_free_rate);
-        r_ms_3y = cal_ms_return(tb_ret_3y, risk_free_rate);
+    if(tb_ret_3y.size() > 0 && periods[5] == 1) {
+        r_3y = func(tb_ret_3y, benchmarks, bmk_ret, risk_free_rate);
     }
 
     // trailing 4y
     tb_ret_4y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-48 AND (end_day.month() - ei.inception_date.month()) >= 48;
-    if(tb_ret_4y.size() > 0) {
-        r_4y = cal_indicators(tb_ret_4y, benchmarks, bmk_ret, risk_free_rate);
+    if(tb_ret_4y.size() > 0 && periods[6] == 1) {
+        r_4y = func(tb_ret_4y, benchmarks, bmk_ret, risk_free_rate);
     }
     
     // trailing 5y
     tb_ret_5y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-60 AND (end_day.month() - ei.inception_date.month()) >= 60;
-    if(tb_ret_5y.size() > 0) {
-        r_5y = cal_indicators(tb_ret_5y, benchmarks, bmk_ret, risk_free_rate);
-        r_ms_5y = cal_ms_return(tb_ret_5y, risk_free_rate);
+    if(tb_ret_5y.size() > 0 && periods[7] == 1) {
+        r_5y = func(tb_ret_5y, benchmarks, bmk_ret, risk_free_rate);
     }
 
     // trailing 10y
     tb_ret_10y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
                 WHERE r.end_date > end_day.month()-120 AND (end_day.month() - ei.inception_date.month()) >= 120;
-    if(tb_ret_10y.size() > 0) {
-        r_10y = cal_indicators(tb_ret_10y, benchmarks, bmk_ret, risk_free_rate);
-        r_ms_10y = cal_ms_return(tb_ret_10y, risk_free_rate);
+    if(tb_ret_10y.size() > 0 && periods[8] == 1) {
+        r_10y = func(tb_ret_10y, benchmarks, bmk_ret, risk_free_rate);
     }
 
-    return r_incep, r_ytd, r_6m, r_1y, r_2y, r_3y, r_4y, r_5y, r_10y, r_ms_3y, r_ms_5y, r_ms_10y;
+    return r_incep, r_ytd, r_6m, r_1y, r_2y, r_3y, r_4y, r_5y, r_10y;
 }
 
 
 
 /*
- *   Calculate trailing 6m, ytd, 1y, 2y, 3y, 4y, 5y, 10y and since inception BFI indicators
+ *   Calculate trailing 6m, ytd, 1y, 2y, 3y, 4y, 5y, 10y and since inception standard indicators
  *   
  *   @param: entity_info <TABLE>: basic information of entity, NEED COLUMNS entity_id, inception_date
  *   @param benchmarks <TABLE>: entity-benchmark mapping table
@@ -581,83 +595,39 @@ def cal_trailing_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bm
  *   @param: end_day <DATE>: 计算截止日期
  *   @param bmk_ret <TABLE>: historical benchmark return table, NEED COLUMNS fund_id, end_date, ret
  *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
- *   
- *   TODO: integrated with cal_trailing_indicators by "function pointer"
  * 
  */
-def cal_trailing_bfi_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bmk_ret, risk_free_rate) {
-
-    r_incep = null;
-    r_ytd = null;
-    r_6m = null;
-    r_1y = null;
-    r_2y = null;
-    r_3y = null;
-    r_4y = null;
-    r_5y = null;
-    r_10y = null;
+def cal_trailing_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bmk_ret, risk_free_rate) {
 
-    // since inception
-    if(tb_ret.size() > 0) {
-        r_incep = cal_bfi_indicators(tb_ret, benchmarks, bmk_ret, risk_free_rate);
-    }
+    return cal_trailing(cal_indicators, entity_info, benchmarks, tb_ret, end_day, bmk_ret, risk_free_rate, [1,1,1,1,1,1,1,1,1]);
 
-    // ytd
-    tb_ret_ytd = SELECT * FROM tb_ret WHERE end_date >= end_day.yearBegin().month();
-    if(tb_ret_ytd.size() > 0) {
-        r_ytd = cal_bfi_indicators(tb_ret_ytd, benchmarks, bmk_ret, risk_free_rate);
-    }
+}
 
-    // trailing 6m
-    tb_ret_6m = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-6 AND (end_day.month() - ei.inception_date.month()) >= 6;
-    if(tb_ret_6m.size() > 0) {
-        r_6m = cal_bfi_indicators(tb_ret_6m, benchmarks, bmk_ret, risk_free_rate);
-    }
-    
-    // trailing 1y
-    tb_ret_1y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-12 AND (end_day.month() - ei.inception_date.month()) >= 12;
-    if(tb_ret_1y.size() > 0) {
-        r_1y = cal_bfi_indicators(tb_ret_1y, benchmarks, bmk_ret, risk_free_rate);
-    }
-    
-    // trailing 2y
-    tb_ret_2y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-24 AND (end_day.month() - ei.inception_date.month()) >= 24;
-    if(tb_ret_2y.size() > 0) {
-        r_2y = cal_bfi_indicators(tb_ret_2y, benchmarks, bmk_ret, risk_free_rate);
-    }
-    
-    // trailing 3y
-    tb_ret_3y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-36 AND (end_day.month() - ei.inception_date.month()) >= 36;
-    if(tb_ret_3y.size() > 0) {
-        r_3y = cal_bfi_indicators(tb_ret_3y, benchmarks, bmk_ret, risk_free_rate);
-    }
+/*
+ *   Calculate trailing 6m, ytd, 1y, 2y, 3y, 4y, 5y, 10y and since inception bfi indicators
+ *   
+ *   @param: entity_info <TABLE>: basic information of entity, NEED COLUMNS entity_id, inception_date
+ *   @param benchmarks <TABLE>: entity-benchmark mapping table
+ *   @param: ret <TABLE>: 收益表,NEED COLUMNS entity_id, price_dat, end_date, nav 
+ *   @param: end_day <DATE>: 计算截止日期
+ *   @param bmk_ret <TABLE>: historical benchmark return table, NEED COLUMNS fund_id, end_date, ret
+ *   @param risk_free <TABLE>: historical risk free rate table, NEED COLUMNS fund_id, end_date, ret
+ *   
+ * 
+ */
+def cal_trailing_bfi_indicators(entity_info, benchmarks, mutable tb_ret, end_day, bmk_ret, risk_free_rate) {
 
-    // trailing 4y
-    tb_ret_4y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-48 AND (end_day.month() - ei.inception_date.month()) >= 48;
-    if(tb_ret_4y.size() > 0) {
-        r_4y = cal_bfi_indicators(tb_ret_4y, benchmarks, bmk_ret, risk_free_rate);
-    }
-    
-    // trailing 5y
-    tb_ret_5y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-60 AND (end_day.month() - ei.inception_date.month()) >= 60;
-    if(tb_ret_5y.size() > 0) {
-        r_5y = cal_bfi_indicators(tb_ret_5y, benchmarks, bmk_ret, risk_free_rate);
-    }
+    return cal_trailing(cal_bfi_indicators, entity_info, benchmarks, tb_ret, end_day, bmk_ret, risk_free_rate, [1,1,1,1,1,1,1,1,1]);
 
-    // trailing 10y
-    tb_ret_10y = SELECT * FROM tb_ret r INNER JOIN entity_info ei ON r.entity_id = ei.entity_id
-                WHERE r.end_date > end_day.month()-120 AND (end_day.month() - ei.inception_date.month()) >= 120;
-    if(tb_ret_10y.size() > 0) {
-        r_10y = cal_bfi_indicators(tb_ret_10y, benchmarks, bmk_ret, risk_free_rate);
-    }
+}
 
-    return r_incep, r_ytd, r_6m, r_1y, r_2y, r_3y, r_4y, r_5y, r_10y;
+/*
+ *   Calculate trailing 3y, 5y, 10y Morningstar Return, Risk-Adjested Return and Risk
+ * 
+ */
+def cal_trailing_ms_indicators(entity_info, mutable tb_ret, end_day, risk_free_rate) {
+	
+    return cal_trailing(cal_ms_indicators,  entity_info, , tb_ret, end_day, , risk_free_rate, periods=[0,0,0,0,0,1,0,1,1]);
 }
 
 /*
@@ -669,6 +639,8 @@ def cal_trailing_bfi_indicators(entity_info, benchmarks, mutable tb_ret, end_day
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
  *   @param isFromSQL <BOOL>: TODO: 从MySQL还是本地DolphinDB取净值/收益数据
  *   
+ *   @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);
@@ -702,7 +674,16 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
 
     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);
 
-    return cal_trailing_indicators(fund_info, primary_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+    // 标准的指标
+    t0 = cal_trailing_indicators(fund_info, primary_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+
+    // Morningstar 指标
+    t1 = cal_trailing_ms_indicators(fund_info, tb_ret, end_day, risk_free_rate);
+
+    // 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 <- t1[5] <- t1[7] <- t1[8]);
 }
 
 /*
@@ -714,6 +695,8 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
  *   @param isFromNav <BOOL>: 用净值实时计算还是从表中取月收益
  *   @param isFromSQL <BOOL>: TODO: 从MySQL还是本地DolphinDB取净值/收益数据
  *   
+ *   @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
  * 
@@ -749,7 +732,12 @@ def cal_fund_bfi_indicators(entity_type, fund_ids, end_day, isFromNav) {
 
     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);
 
-    return cal_trailing_bfi_indicators(fund_info, bfi_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+    t0 = cal_trailing_bfi_indicators(fund_info, bfi_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+
+    // 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);
 }
 
 /*
@@ -798,7 +786,12 @@ def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
 
     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);
 
-    return cal_trailing_indicators(portfolio_info, primary_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+    t0 = cal_trailing_indicators(portfolio_info, primary_benchmark, tb_ret, end_day, 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);
+
 }
 
 
@@ -851,5 +844,10 @@ def cal_portfolio_bfi_indicators(portfolio_ids, end_day, cal_method, isFromNav)
 
     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);
 
-    return cal_trailing_bfi_indicators(portfolio_info, bfi_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
+    t0 = cal_trailing_bfi_indicators(portfolio_info, bfi_benchmark, tb_ret, end_day, 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);
+
 }