|
@@ -53,7 +53,7 @@ defg aggCVaR(returns, method, confidenceLevel) {
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * 最大回撤
|
|
|
|
|
|
+ * 回撤
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
@@ -107,10 +107,11 @@ def get_benchmark_return(benchmarks, end_day) {
|
|
* NOTE: standard deviation of Java version is noncompliant-GIPS annulized number
|
|
* NOTE: standard deviation of Java version is noncompliant-GIPS annulized number
|
|
*
|
|
*
|
|
* Create: 20240904 Joey
|
|
* Create: 20240904 Joey
|
|
- * TODO: max drawdowns are the same with SWAGGER, but are off with SQL
|
|
|
|
|
|
+ * TODO: SQL is wrong for max drawdowns
|
|
* TODO: var, cvar, calmar are off; std dev, skewness, kurtosis are slightly off
|
|
* TODO: var, cvar, calmar are off; std dev, skewness, kurtosis are slightly off
|
|
- * TODO: since inception date
|
|
|
|
- *
|
|
|
|
|
|
+ * TODO: SQL is missing for portfolio since inception date return
|
|
|
|
+ * TODO: Java calculates max drawdown even there is no nav
|
|
|
|
+ * TODO: Java ytd worst month could be wrong (i.e. portfolio 166002, 2024-03)
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
@@ -139,8 +140,8 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
|
|
|
|
// 不会用上面的办法算最大回撤, VaR, CVaR
|
|
// 不会用上面的办法算最大回撤, VaR, CVaR
|
|
t_var = SELECT entity_id, end_date, ret,
|
|
t_var = SELECT entity_id, end_date, ret,
|
|
- cummax(1 - nav \ nav.cummax()) AS drawdown,
|
|
|
|
- cumpercentile(ret, 5, 'linear') AS var
|
|
|
|
|
|
+ cummax(1 - nav \ cummax(nav)) AS drawdown,
|
|
|
|
+ - cumpercentile(ret, 5, 'linear') AS var
|
|
FROM ret WHERE ret > -1
|
|
FROM ret WHERE ret > -1
|
|
CONTEXT BY entity_id;
|
|
CONTEXT BY entity_id;
|
|
|
|
|
|
@@ -162,7 +163,7 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
iif(cumcount(entity_id) > 5, tmoving(skew{, false}, end_date, ret, 12), null) AS skewness,
|
|
iif(cumcount(entity_id) > 5, tmoving(skew{, false}, end_date, ret, 12), null) AS skewness,
|
|
iif(cumcount(entity_id) > 5, tmoving(kurtosis{, false}, end_date, ret, 12)-3, null) AS kurtosis,
|
|
iif(cumcount(entity_id) > 5, tmoving(kurtosis{, false}, end_date, ret, 12)-3, null) AS kurtosis,
|
|
cummin(ret) AS wrst_month,
|
|
cummin(ret) AS wrst_month,
|
|
- maxDrawdown(nav) AS drawdown
|
|
|
|
|
|
+ cummax(1 - nav \ cummax(nav)) AS drawdown
|
|
FROM ret WHERE ret > -1
|
|
FROM ret WHERE ret > -1
|
|
CONTEXT BY entity_id, end_date.year()
|
|
CONTEXT BY entity_id, end_date.year()
|
|
ORDER BY entity_id, end_date;
|
|
ORDER BY entity_id, end_date;
|
|
@@ -308,7 +309,7 @@ def cal_omega_sortino_kappa(ret, risk_free, trailing_month) {
|
|
* Winning Ratio, Tracking Error, Information Ratio
|
|
* Winning Ratio, Tracking Error, Information Ratio
|
|
*
|
|
*
|
|
* NOTE: mcount is very unique in mFun, because it doesn't support minPeriods(BUG?), while others default minPeriods = window.
|
|
* NOTE: mcount is very unique in mFun, because it doesn't support minPeriods(BUG?), while others default minPeriods = window.
|
|
- * As a result, we have to live with lots of records having winrate but no tracking error and info ratio
|
|
|
|
|
|
+ * As a result, we have to delete records having winrate but no tracking error and info ratio for the sake of consisence
|
|
*
|
|
*
|
|
* TODO: Win Rate incept is off, because Java incorrectly takes all end_date as denominator even when benchmark has no price
|
|
* TODO: Win Rate incept is off, because Java incorrectly takes all end_date as denominator even when benchmark has no price
|
|
* Information Ratio is way off!
|
|
* Information Ratio is way off!
|
|
@@ -320,7 +321,8 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
|
|
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
- t.entity_id.cumcount() AS cnt, (t.ret - bmk.ret) AS exc_ret, bm.benchmark_id
|
|
|
|
|
|
+ t.entity_id.cumcount() AS cnt,
|
|
|
|
+ t.ret - bmk.ret AS exc_ret, bm.benchmark_id
|
|
FROM ret t
|
|
FROM ret t
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
@@ -329,10 +331,10 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
CONTEXT BY t.entity_id, bm.benchmark_id;
|
|
CONTEXT BY t.entity_id, bm.benchmark_id;
|
|
|
|
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
- cumcount(iif(exc_ret >= 0, 1, null)) \ cnt AS winrate,
|
|
|
|
- exc_ret.cumstd() AS track_error,
|
|
|
|
- iif(exc_ret.cumstd() == 0, null, exc_ret.cumavg() \ exc_ret.cumstd()) AS info
|
|
|
|
- FROM t0
|
|
|
|
|
|
+ iif(cnt > 5, cumcount(iif(exc_ret >= 0, 1, null)) \ cnt, null) AS winrate,
|
|
|
|
+ iif(cnt > 5, exc_ret.cumstd(), null) AS track_error,
|
|
|
|
+ iif(cnt > 5, iif(exc_ret.cumstd() == 0, null, exc_ret.cumavg() \ exc_ret.cumstd()), 5) AS info
|
|
|
|
+ FROM t0
|
|
CONTEXT BY entity_id, benchmark_id
|
|
CONTEXT BY entity_id, benchmark_id
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
|
|
|
|
@@ -340,7 +342,7 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
|
|
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
- t.entity_id.cumcount() AS cnt, (t.ret - bmk.ret) AS exc_ret, bm.benchmark_id
|
|
|
|
|
|
+ t.entity_id.cumcount() AS cnt, t.ret - bmk.ret AS exc_ret, bm.benchmark_id
|
|
FROM ret t
|
|
FROM ret t
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
@@ -349,10 +351,10 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
CONTEXT BY t.entity_id, bm.benchmark_id, t.end_date.year();
|
|
CONTEXT BY t.entity_id, bm.benchmark_id, t.end_date.year();
|
|
|
|
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
- cumcount(iif(exc_ret >= 0, 1, null)) \ cnt AS winrate,
|
|
|
|
- exc_ret.cumstd() AS track_error,
|
|
|
|
- iif(exc_ret.cumstd() == 0, null, exc_ret.cumavg() \ exc_ret.cumstd()) AS info
|
|
|
|
- FROM t0
|
|
|
|
|
|
+ iif(cnt > 5, cumcount(iif(exc_ret >= 0, 1, null)) \ cnt, null) AS winrate,
|
|
|
|
+ iif(cnt > 5, exc_ret.cumstd(), null) AS track_error,
|
|
|
|
+ iif(cnt > 5, iif(exc_ret.cumstd() == 0, null, exc_ret.cumavg() \ exc_ret.cumstd()), null) AS info
|
|
|
|
+ FROM t0
|
|
CONTEXT BY entity_id, benchmark_id, end_date.year()
|
|
CONTEXT BY entity_id, benchmark_id, end_date.year()
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
} else {
|
|
} else {
|
|
@@ -361,7 +363,8 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
|
|
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t0 = SELECT t.entity_id, t.end_date, t.price_date,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
t.ret, bmk.ret AS ret_bmk,
|
|
- t.entity_id.mcount(win) AS cnt, (t.ret - bmk.ret) AS exc_ret, bm.benchmark_id
|
|
|
|
|
|
+ t.entity_id.mcount(win) AS cnt,
|
|
|
|
+ t.ret - bmk.ret AS exc_ret, bm.benchmark_id
|
|
FROM ret t
|
|
FROM ret t
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN benchmarks bm ON t.entity_id = bm.entity_id AND t.end_date = bm.end_date
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
INNER JOIN bmk_ret bmk ON t.end_date = bmk.end_date AND bm.benchmark_id = bmk.benchmark_id
|
|
@@ -370,15 +373,15 @@ def cal_benchmark_tracking(ret, benchmarks, bmk_ret, trailing_month) {
|
|
CONTEXT BY t.entity_id, bm.benchmark_id;
|
|
CONTEXT BY t.entity_id, bm.benchmark_id;
|
|
|
|
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
t = SELECT entity_id, end_date, benchmark_id,
|
|
- mcount(iif(exc_ret >= 0, 1, null), win) \ cnt AS winrate,
|
|
|
|
- mstd(exc_ret, win) AS track_error,
|
|
|
|
- iif(mstd(exc_ret, win) == 0, null, mavg(exc_ret, win) \ mstd(exc_ret, win)) AS info
|
|
|
|
- FROM t0
|
|
|
|
|
|
+ iif(cnt > 5, mcount(iif(exc_ret >= 0, 1, null), win) \ cnt, null) AS winrate,
|
|
|
|
+ iif(cnt > 5, mstd(exc_ret, win), null) AS track_error,
|
|
|
|
+ iif(cnt > 5, iif(mstd(exc_ret, win) == 0, null, mavg(exc_ret, win) \ mstd(exc_ret, win)), null) AS info
|
|
|
|
+ FROM t0
|
|
CONTEXT BY entity_id, benchmark_id
|
|
CONTEXT BY entity_id, benchmark_id
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
ORDER BY entity_id, end_date, benchmark_id;
|
|
}
|
|
}
|
|
|
|
|
|
- return t;
|
|
|
|
|
|
+ return t; //SELECT * FROM t WHERE track_error IS NOT NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -396,7 +399,9 @@ def cal_alpha_beta(ret, benchmarks, bmk_ret, risk_free, trailing_month) {
|
|
|
|
|
|
if(trailing_month == 'incep') {
|
|
if(trailing_month == 'incep') {
|
|
|
|
|
|
- beta = SELECT entity_id, end_date, benchmark_id, ret.cumbeta(ret_bmk) AS beta FROM t CONTEXT BY entity_id, benchmark_id;
|
|
|
|
|
|
+ beta = SELECT entity_id, end_date, benchmark_id,
|
|
|
|
+ iif(cumcount(end_date) > 5, ret.cumbeta(ret_bmk), null) AS beta
|
|
|
|
+ FROM t CONTEXT BY entity_id, benchmark_id;
|
|
|
|
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
(t.ret - rfr.ret).cumavg() - beta.beta * (t.ret_bmk - rfr.ret).cumavg() AS alpha
|
|
(t.ret - rfr.ret).cumavg() - beta.beta * (t.ret_bmk - rfr.ret).cumavg() AS alpha
|
|
@@ -408,7 +413,9 @@ def cal_alpha_beta(ret, benchmarks, bmk_ret, risk_free, trailing_month) {
|
|
|
|
|
|
} else if(trailing_month == 'ytd') {
|
|
} else if(trailing_month == 'ytd') {
|
|
|
|
|
|
- beta = SELECT entity_id, end_date, benchmark_id, ret.cumbeta(ret_bmk) AS beta FROM t CONTEXT BY entity_id, benchmark_id, end_date.year();
|
|
|
|
|
|
+ beta = SELECT entity_id, end_date, benchmark_id,
|
|
|
|
+ iif(cumcount(end_date) > 5, ret.cumbeta(ret_bmk), null) AS beta
|
|
|
|
+ FROM t CONTEXT BY entity_id, benchmark_id, end_date.year();
|
|
|
|
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
(t.ret - rfr.ret).cumavg() - beta.beta * (t.ret_bmk - rfr.ret).cumavg() AS alpha
|
|
(t.ret - rfr.ret).cumavg() - beta.beta * (t.ret_bmk - rfr.ret).cumavg() AS alpha
|
|
@@ -422,7 +429,9 @@ def cal_alpha_beta(ret, benchmarks, bmk_ret, risk_free, trailing_month) {
|
|
|
|
|
|
win = trailing_month$INT;
|
|
win = trailing_month$INT;
|
|
|
|
|
|
- beta = SELECT entity_id, end_date, benchmark_id, ret.mbeta(ret_bmk, win) AS beta FROM t CONTEXT BY entity_id, benchmark_id;
|
|
|
|
|
|
+ beta = SELECT entity_id, end_date, benchmark_id,
|
|
|
|
+ iif(mcount(end_date, win) > 5, ret.mbeta(ret_bmk, win), null) AS beta
|
|
|
|
+ FROM t CONTEXT BY entity_id, benchmark_id;
|
|
|
|
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
alpha = SELECT t.entity_id, t.end_date, t.benchmark_id, beta.beta AS beta,
|
|
(t.ret - rfr.ret).mavg(win) - beta.beta * (t.ret_bmk - rfr.ret).mavg(win) AS alpha
|
|
(t.ret - rfr.ret).mavg(win) - beta.beta * (t.ret_bmk - rfr.ret).mavg(win) AS alpha
|
|
@@ -806,6 +815,9 @@ def get_effective_benchmarks(benchmarks, end_day, trailing_month, isEffectiveOnl
|
|
*/
|
|
*/
|
|
def cal_indicators_with_benchmark(entity_info, benchmark_mapping, end_day, tb_ret, index_ret, risk_free, month) {
|
|
def cal_indicators_with_benchmark(entity_info, benchmark_mapping, end_day, tb_ret, index_ret, risk_free, month) {
|
|
|
|
|
|
|
|
+ if(entity_info.isVoid() || entity_info.size() == 0 || benchmark_mapping.isVoid() || benchmark_mapping.size() == 0 ) return null;
|
|
|
|
+ if(tb_ret.isVoid() || tb_ret.size() == 0 || index_ret.isVoid() || index_ret.size() == 0 || risk_free.isVoid() || risk_free.size() == 0 ) return null;
|
|
|
|
+
|
|
// sorting for correct first() and last() value
|
|
// sorting for correct first() and last() value
|
|
ret = SELECT * FROM tb_ret WHERE ret > -1 AND end_date <= end_day.month() ORDER BY entity_id, price_date;
|
|
ret = SELECT * FROM tb_ret WHERE ret > -1 AND end_date <= end_day.month() ORDER BY entity_id, price_date;
|
|
|
|
|
|
@@ -877,6 +889,9 @@ def cal_indicators_with_benchmark(entity_info, benchmark_mapping, end_day, tb_re
|
|
*/
|
|
*/
|
|
def cal_indicators(entity_info, benchmarks, end_day, tb_ret, benchmark_ret, risk_free, month) {
|
|
def cal_indicators(entity_info, benchmarks, end_day, tb_ret, benchmark_ret, risk_free, month) {
|
|
|
|
|
|
|
|
+ if(entity_info.isVoid() || entity_info.size() == 0 || benchmarks.isVoid() || benchmarks.size() == 0 ) return null;
|
|
|
|
+ if(tb_ret.isVoid() || tb_ret.size() == 0 || benchmark_ret.isVoid() || benchmark_ret.size() == 0 || risk_free.isVoid() || risk_free.size() == 0 ) return null;
|
|
|
|
+
|
|
// sorting for correct first() and last() value
|
|
// sorting for correct first() and last() value
|
|
ret = SELECT * FROM tb_ret WHERE end_date <= end_day.month() ORDER BY entity_id, price_date;
|
|
ret = SELECT * FROM tb_ret WHERE end_date <= end_day.month() ORDER BY entity_id, price_date;
|
|
|
|
|
|
@@ -938,7 +953,7 @@ def cal_indicators(entity_info, benchmarks, end_day, tb_ret, benchmark_ret, risk
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
-def cal_trailing2(func, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
+def cal_trailing(func, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
r_incep = null;
|
|
r_incep = null;
|
|
r_ytd = null;
|
|
r_ytd = null;
|
|
@@ -992,9 +1007,9 @@ def cal_trailing2(func, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_
|
|
* @param risk_free <TABLE>: historical risk free rate 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_indicators2(entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
+def cal_trailing_indicators(entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
- return cal_trailing2(cal_indicators, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ return cal_trailing(cal_indicators, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1010,14 +1025,14 @@ def cal_trailing_indicators2(entity_info, benchmarks, end_day, tb_ret, bmk_ret,
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
*/
|
|
-def cal_trailing_bfi_indicators2(entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
+def cal_trailing_bfi_indicators(entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate) {
|
|
|
|
|
|
- return cal_trailing2(cal_indicators_with_benchmark, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ return cal_trailing(cal_indicators_with_benchmark, entity_info, benchmarks, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Calculate fund indicators for one date
|
|
|
|
|
|
+ * Calculate historcial fund trailing indicators
|
|
*
|
|
*
|
|
* @param entity_type <STRING>: MF, HF
|
|
* @param entity_type <STRING>: MF, HF
|
|
* @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
|
|
* @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
|
|
@@ -1052,8 +1067,12 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
// 从fund_performance表里读月收益
|
|
// 从fund_performance表里读月收益
|
|
tb_ret = get_monthly_ret('FD', fund_ids, very_old_date, end_day, true);
|
|
tb_ret = get_monthly_ret('FD', 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');
|
|
|
|
+ tb_ret.replaceColumn!('end_date', v_end_date);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ 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
|
|
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')) ;
|
|
FROM get_fund_primary_benchmark(fund_ids, start_month.temporalFormat('yyyy-MM'), end_day.month().temporalFormat('yyyy-MM')) ;
|
|
@@ -1061,10 +1080,14 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
// 取所有出现的基准月收益
|
|
// 取所有出现的基准月收益
|
|
bmk_ret = get_benchmark_return(primary_benchmark, end_day);
|
|
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);
|
|
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_indicators2(fund_info, primary_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ t0 = cal_trailing_indicators(fund_info, primary_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
// Morningstar 指标
|
|
// Morningstar 指标
|
|
//t1 = cal_trailing_ms_indicators(fund_info, tb_ret, end_day, risk_free_rate);
|
|
//t1 = cal_trailing_ms_indicators(fund_info, tb_ret, end_day, risk_free_rate);
|
|
@@ -1078,7 +1101,7 @@ def cal_fund_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Calculate fund BFI indicators for one date
|
|
|
|
|
|
+ * Calculate historcial fund trailing BFI indicators
|
|
*
|
|
*
|
|
* @param entity_type <STRING>: MF, HF
|
|
* @param entity_type <STRING>: MF, HF
|
|
* @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
|
|
* @param fund_ids <STRING>: 逗号和单引号分隔的fund_id
|
|
@@ -1114,8 +1137,12 @@ def cal_fund_bfi_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
// 从fund_performance表里读月收益
|
|
// 从fund_performance表里读月收益
|
|
tb_ret = get_monthly_ret('FD', fund_ids, very_old_date, end_day, true);
|
|
tb_ret = get_monthly_ret('FD', 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');
|
|
|
|
+ tb_ret.replaceColumn!('end_date', v_end_date);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ 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
|
|
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'));
|
|
FROM get_fund_bfi_factors(fund_ids, start_month.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM'));
|
|
@@ -1126,7 +1153,9 @@ 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);
|
|
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);
|
|
|
|
|
|
- t0 = cal_trailing_bfi_indicators2(fund_info, bfi_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ 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 stands for "Best Fit Index"
|
|
// 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'];
|
|
v_table_name = ['BFI-INCEP', 'BFI-YTD', 'BFI-6M', 'BFI-1Y', 'BFI-2Y', 'BFI-3Y', 'BFI-4Y', 'BFI-5Y', 'BFI-10Y'];
|
|
@@ -1135,7 +1164,7 @@ def cal_fund_bfi_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Calculate portfolio indicators for one date
|
|
|
|
|
|
+ * Calculate historcial portfolio trailing indicators
|
|
*
|
|
*
|
|
* @param portfolio_ids <STRING>: comma-delimited portfolio ids
|
|
* @param portfolio_ids <STRING>: comma-delimited portfolio ids
|
|
* @param end_day <DATE>: the date
|
|
* @param end_day <DATE>: the date
|
|
@@ -1148,6 +1177,7 @@ def cal_fund_bfi_indicators(entity_type, fund_ids, end_day, isFromNav) {
|
|
def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
|
|
def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
|
|
|
|
|
|
very_old_date = 1990.01.01;
|
|
very_old_date = 1990.01.01;
|
|
|
|
+ start_month = very_old_date.month();
|
|
|
|
|
|
portfolio_info = get_portfolio_info(portfolio_ids);
|
|
portfolio_info = get_portfolio_info(portfolio_ids);
|
|
|
|
|
|
@@ -1158,7 +1188,9 @@ def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
|
|
if(isFromNav == true) {
|
|
if(isFromNav == true) {
|
|
// 从净值开始计算收益
|
|
// 从净值开始计算收益
|
|
tb_raw_ret = SELECT * FROM cal_portfolio_nav(portfolio_ids, very_old_date, cal_method) WHERE price_date <= end_day;
|
|
tb_raw_ret = SELECT * FROM cal_portfolio_nav(portfolio_ids, very_old_date, cal_method) WHERE price_date <= end_day;
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ if(tb_raw_ret.isVoid() || tb_raw_ret.size() == 0) return null;
|
|
|
|
+
|
|
// funky thing is you can't use "AS" for the grouping columns?
|
|
// funky thing is you can't use "AS" for the grouping columns?
|
|
tb_ret = SELECT portfolio_id, price_date.month(), price_date.last() AS price_date, (1+ret).prod()-1 AS ret, nav.last() AS nav
|
|
tb_ret = SELECT portfolio_id, price_date.month(), price_date.last() AS price_date, (1+ret).prod()-1 AS ret, nav.last() AS nav
|
|
FROM tb_raw_ret
|
|
FROM tb_raw_ret
|
|
@@ -1170,17 +1202,30 @@ def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
|
|
// 从pf_portfolio_performance表里读月收益
|
|
// 从pf_portfolio_performance表里读月收益
|
|
tb_ret = get_monthly_ret('PF', portfolio_ids, very_old_date, end_day, true);
|
|
tb_ret = get_monthly_ret('PF', portfolio_ids, very_old_date, end_day, true);
|
|
tb_ret.rename!(['portfolio_id'], ['entity_id']);
|
|
tb_ret.rename!(['portfolio_id'], ['entity_id']);
|
|
|
|
+ v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
|
|
|
|
+ tb_ret.replaceColumn!('end_date', v_end_date);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(tb_ret.isVoid() || tb_ret.size() == 0) return null;
|
|
|
|
+
|
|
// 沪深300做基准,同SQL保持一致
|
|
// 沪深300做基准,同SQL保持一致
|
|
- primary_benchmark = SELECT entity_id, 'IN00000008' AS benchmark_id FROM portfolio_info;
|
|
|
|
|
|
+ t_dates = table(start_month..end_day.month() AS end_date);
|
|
|
|
+ primary_benchmark = SELECT ei.entity_id, dt.end_date, 'IN00000008' AS benchmark_id
|
|
|
|
+ FROM portfolio_info ei JOIN t_dates dt
|
|
|
|
+ WHERE dt.end_date >= ei.inception_date.month();
|
|
|
|
+
|
|
|
|
+ if(primary_benchmark.isVoid() || primary_benchmark.size() == 0) { return null; }
|
|
|
|
|
|
// 取所有出现的基准月收益
|
|
// 取所有出现的基准月收益
|
|
bmk_ret = get_benchmark_return(primary_benchmark, end_day);
|
|
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);
|
|
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);
|
|
|
|
|
|
- t0 = cal_trailing_indicators2(portfolio_info, primary_benchmark, end_day, tb_ret, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
|
|
|
|
+
|
|
|
|
+ t0 = cal_trailing_indicators(portfolio_info, primary_benchmark, end_day, tb_ret, 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'];
|
|
v_table_name = ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y'];
|
|
|
|
|
|
@@ -1190,7 +1235,7 @@ def cal_portfolio_indicators(portfolio_ids, end_day, cal_method, isFromNav) {
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Calculate portfolio bfi indicators for one date
|
|
|
|
|
|
+ * Calculate historcial portfolio trailing BFI indicators
|
|
*
|
|
*
|
|
* @param portfolio_ids <STRING>: comma-delimited portfolio ids
|
|
* @param portfolio_ids <STRING>: comma-delimited portfolio ids
|
|
* @param end_day <DATE>: the date
|
|
* @param end_day <DATE>: the date
|
|
@@ -1217,6 +1262,8 @@ def cal_portfolio_bfi_indicators(portfolio_ids, end_day, cal_method, isFromNav)
|
|
if(isFromNav == true) {
|
|
if(isFromNav == true) {
|
|
// 从净值开始计算收益
|
|
// 从净值开始计算收益
|
|
tb_raw_ret = SELECT * FROM cal_portfolio_nav(portfolio_ids, very_old_date, cal_method) WHERE price_date <= end_day;
|
|
tb_raw_ret = SELECT * FROM cal_portfolio_nav(portfolio_ids, very_old_date, cal_method) WHERE price_date <= end_day;
|
|
|
|
+
|
|
|
|
+ if(tb_raw_ret.isVoid() || tb_raw_ret.size() == 0) return null;
|
|
|
|
|
|
// funky thing is you can't use "AS" for the grouping columns?
|
|
// funky thing is you can't use "AS" for the grouping columns?
|
|
tb_ret = SELECT portfolio_id, price_date.month(), price_date.last() AS price_date, (1+ret).prod()-1 AS ret, nav.last() AS nav
|
|
tb_ret = SELECT portfolio_id, price_date.month(), price_date.last() AS price_date, (1+ret).prod()-1 AS ret, nav.last() AS nav
|
|
@@ -1229,19 +1276,27 @@ def cal_portfolio_bfi_indicators(portfolio_ids, end_day, cal_method, isFromNav)
|
|
// 从pf_portfolio_performance表里读月收益
|
|
// 从pf_portfolio_performance表里读月收益
|
|
tb_ret = get_monthly_ret('PF', portfolio_ids, very_old_date, end_day, true);
|
|
tb_ret = get_monthly_ret('PF', portfolio_ids, very_old_date, end_day, true);
|
|
tb_ret.rename!(['portfolio_id'], ['entity_id']);
|
|
tb_ret.rename!(['portfolio_id'], ['entity_id']);
|
|
|
|
+ v_end_date = tb_ret.end_date.temporalParse('yyyy-MM');
|
|
|
|
+ tb_ret.replaceColumn!('end_date', v_end_date);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(tb_ret.isVoid() || tb_ret.size() == 0) return null;
|
|
|
|
+
|
|
// 取组合和基准的对照表
|
|
// 取组合和基准的对照表
|
|
- bfi_benchmark = SELECT portfolio_id AS entity_id, end_date, factor_id AS benchmark_id
|
|
|
|
|
|
+ bfi_benchmark = SELECT portfolio_id AS entity_id, end_date.temporalParse('yyyy-MM') AS end_date, factor_id AS benchmark_id
|
|
FROM get_portfolio_bfi_factors(portfolio_ids, start_month.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM'));
|
|
FROM get_portfolio_bfi_factors(portfolio_ids, start_month.temporalFormat('yyyy-MM'), end_day.temporalFormat('yyyy-MM'));
|
|
|
|
|
|
if(bfi_benchmark.isVoid() || bfi_benchmark.size() == 0) { return null; }
|
|
if(bfi_benchmark.isVoid() || bfi_benchmark.size() == 0) { return null; }
|
|
|
|
|
|
bmk_ret = get_benchmark_return(bfi_benchmark, end_day);
|
|
bmk_ret = get_benchmark_return(bfi_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);
|
|
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);
|
|
|
|
|
|
- t0 = cal_trailing_bfi_indicators(portfolio_info, bfi_benchmark, tb_ret, end_day, bmk_ret, risk_free_rate);
|
|
|
|
|
|
+ if(risk_free_rate.isVoid() || risk_free_rate.size() == 0) { return null; }
|
|
|
|
+
|
|
|
|
+ t0 = cal_trailing_bfi_indicators(portfolio_info, bfi_benchmark, end_day, tb_ret, 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'];
|
|
v_table_name = ['PBI-INCEP', 'PBI-YTD', 'PBI-6M', 'PBI-1Y', 'PBI-2Y', 'PBI-3Y', 'PBI-4Y', 'PBI-5Y', 'PBI-10Y'];
|
|
|
|
|