|
@@ -1,34 +1,11 @@
|
|
|
module fundit::indicatorCalculator
|
|
|
|
|
|
+use fundit::sqlUtilities
|
|
|
use fundit::dataPuller
|
|
|
use fundit::returnCalculator
|
|
|
use fundit::navCalculator
|
|
|
|
|
|
/*
|
|
|
- * Annulized multiple
|
|
|
- */
|
|
|
-def get_annulization_multiple(freq) {
|
|
|
-
|
|
|
- ret = 1;
|
|
|
-
|
|
|
- if (freq == 'd') {
|
|
|
- ret = 252; // We have differences here between Java and DolphinDB, Java uses 365.25 days
|
|
|
- } else if (freq == 'w') {
|
|
|
- ret = 52;
|
|
|
- } else if (freq == 'm') {
|
|
|
- ret = 12;
|
|
|
- } else if (freq == 'q') {
|
|
|
- ret = 4;
|
|
|
- } else if (freq == 's') {
|
|
|
- ret = 2;
|
|
|
- } else if (freq == 'a') {
|
|
|
- ret = 1;
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
* 将VaR包裹一层,使之成为系统认可的聚集函数
|
|
|
* @param returns <DOUBLE VECTOR>: 非空收益率
|
|
|
* @param method <STRING>: 'normal', 'logNormal', 'historical', 'monteCarlo'
|
|
@@ -37,6 +14,8 @@ def get_annulization_multiple(freq) {
|
|
|
*/
|
|
|
defg aggVaR(returns, method, confidenceLevel) {
|
|
|
|
|
|
+ if(returns.form() != 1) return null;
|
|
|
+
|
|
|
return returns.VaR(method, confidenceLevel);
|
|
|
}
|
|
|
|
|
@@ -49,6 +28,8 @@ defg aggVaR(returns, method, confidenceLevel) {
|
|
|
*/
|
|
|
defg aggCVaR(returns, method, confidenceLevel) {
|
|
|
|
|
|
+ if(returns.form() != 1) return null;
|
|
|
+
|
|
|
return returns.CVaR(method, confidenceLevel);
|
|
|
}
|
|
|
|
|
@@ -78,6 +59,7 @@ defg maxDrawdown(navs) {
|
|
|
* 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)
|
|
|
+ * TODO: arith_mean & gerom_mean ARE NOT TESTED
|
|
|
*
|
|
|
*/
|
|
|
def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
@@ -87,6 +69,7 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
|
|
|
|
// 需要至少6个数才计算标准差、峰度、偏度
|
|
|
t0 = SELECT price_date.max() AS price_date, nav, ret,
|
|
|
+ ret.mean() AS arith_mean, (1+ret).prod().pow(1\count(entity_id))-1 AS geom_mean,
|
|
|
iif(count(entity_id) > 5, std(ret), null) AS std_dev,
|
|
|
iif(count(entity_id) > 5, skew(ret, false), null) AS skewness,
|
|
|
iif(count(entity_id) > 5, kurtosis(ret, false), null)-3 AS kurtosis,
|
|
@@ -95,7 +78,7 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
|
WHERE ret > -1
|
|
|
GROUP BY entity_id
|
|
|
CGROUP BY end_date
|
|
|
- ORDER BY end_date;
|
|
|
+ ORDER BY entity_id, end_date;
|
|
|
|
|
|
// 年化收益(给后面计算Calmar用)
|
|
|
t0.addColumn(['trailing_ret', 'trailing_ret_a'], [DOUBLE, DOUBLE]);
|
|
@@ -120,10 +103,11 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
|
t1 = SELECT t0.*, t_cvar.drawdown, t_cvar.var, t_cvar.cvar
|
|
|
FROM t0 LEFT JOIN t_cvar ON t0.entity_id = t_cvar.entity_id AND t0.end_date = t_cvar.end_date
|
|
|
ORDER BY t0.entity_id, t0.end_date;
|
|
|
-
|
|
|
+
|
|
|
} else if(trailing_month == 'ytd') {
|
|
|
|
|
|
t1 = SELECT entity_id, end_date, price_date.cummax() AS price_date, nav, ret,
|
|
|
+ ret.cumavg() AS arith_mean, (1+ret).cumprod().pow(1\cumcount(entity_id))-1 AS geom_mean,
|
|
|
cumprod(1+ret)-1 AS trailing_ret,
|
|
|
cumprod(1+ret)-1 AS trailing_ret_a, // no need annulization for ytd
|
|
|
iif(cumcount(entity_id) > 5, cumstd(ret), null) AS std_dev,
|
|
@@ -141,6 +125,7 @@ def cal_basic_performance(entity_info, ret, trailing_month) {
|
|
|
win = trailing_month$STRING$INT;
|
|
|
|
|
|
t1 = SELECT entity_id, end_date, price_date.mmax(win) AS price_date, nav, ret,
|
|
|
+ ret.mavg(win) AS arith_mean, (1+ret).mprod(win).pow(1\mcount(entity_id, win))-1 AS geom_mean,
|
|
|
mprod(1+ret, win)-1 AS trailing_ret,
|
|
|
iif(win > 12,
|
|
|
mprod(1+ret, win).pow(12\win)-1,
|