Browse Source

性能优化

Joey 4 months ago
parent
commit
bd7299f185

+ 66 - 38
modules/performanceDataPuller.dos

@@ -36,7 +36,8 @@ def get_data_by_updatetime(table_name, updatetime, isFromMySQL=true) {
 /*
  *  取有周收益更新的基金组合列表及其最早日期
  *  
- *  TODO: entity_type 是否要区分MF,HF,MI,FI 待查
+ *  @param entity_type <STRING>: MF,HF,MI,FI
+ *  @param entity_ids <VECTOR|STRING>
  * 
  *  Example: get_entity_list_by_weekly_return_updatetime('PF', NULL, 2024.11.20, true);
  */
@@ -52,6 +53,8 @@ def get_entity_list_by_weekly_return_updatetime(entity_type, entity_ids, updatet
     	sql_entity_id = " AND " + tmp.sec_id_col[0] + " IN (" + s_entity_ids + ")";
     }
 
+    sql_entity_id += iif(entity_type == 'PF', '', " AND " + tmp.sec_id_col[0] + " LIKE '" + tmp.prefix[0] + "%'");
+
     if(isFromMySQL == true) {
 
         s_query = "SELECT " + tmp.sec_id_col[0] + " AS entity_id, MIN(price_date) AS price_date 
@@ -249,24 +252,40 @@ def get_risk_free_rate(start_date, end_date) {
 
 
 /*
- * 取基金最新收益及净值
+ *  取基金最新收益及净值
  *
- * get_fund_latest_nav_performance("'HF000004KN','HF00018WXG'")
+ *  Example: get_entity_list_by_latest_return_updatetime('HF', ['HF000004KN','HF00018WXG'], 2024.01.01, true)
+ *  		 get_entity_list_by_latest_return_updatetime('HF', NULL, 2024.11.01, true)
  */
-def get_fund_latest_nav_performance(fund_ids, isFromMySQL) {
+def get_entity_list_by_latest_return_updatetime(entity_type, entity_ids, updatetime, isFromMySQL=true) {
+
+
+    tmp = get_latest_performance_table_description(entity_type);
+
+    s_entity_ids = ids_to_string(entity_ids);
+
+    sql_entity_id = '';
+
+    if(s_entity_ids != NULL) {
+    	sql_entity_id = " AND " + tmp.sec_id_col[0] + " IN (" + s_entity_ids + ")";
+    }
+
+    sql_entity_id += iif(entity_type == 'PF', '', " AND " + tmp.sec_id_col[0] + " LIKE '" + tmp.prefix[0] + "%'");
 
     if(isFromMySQL == true) {
-    
-        s_query = "SELECT *
-                   FROM mfdb.fund_latest_nav_performance
-                   WHERE fund_id IN (" + fund_ids + ")
-                     AND isvalid = 1
-                     ORDER BY fund_id"
 
+        s_query = "SELECT " + tmp.sec_id_col[0] + " AS entity_id, price_date, end_date
+                   FROM " + tmp.table_name[0] + "
+                   WHERE isvalid = 1 " +
+                     sql_entity_id + "
+                     AND " + tmp.cumulative_nav_col[0] + " > 0
+                     AND updatetime >= '" + updatetime$STRING + "'
+                   ORDER BY " + tmp.sec_id_col[0];
+     
         conn = connect_mysql()
-    
+     
         t = odbc::query(conn, s_query)
-    
+     
         conn.close()
 
     } else {
@@ -275,7 +294,7 @@ def get_fund_latest_nav_performance(fund_ids, isFromMySQL) {
 
         s_col = sqlCol("*")
 
-        s_where = expr(<fund_id>, in, fund_ids.strReplace("'", "").split(","))
+        s_where = expr(<fund_id>, in, entity_ids.strReplace("'", "").split(","))
         
         t = sql(s_col, tb_local, s_where).eval()
 
@@ -435,29 +454,6 @@ def get_entity_list_by_nav_updatetime(entity_type, entity_ids, updatetime, isFro
 
 
 /*
- * 取私募基金用于月末 fund_performance 表更新的净值
- * 
- * @param fund_ids: 逗号分隔的ID字符串, 每个ID都有''
- * @param month_end: 月末日期字符串  YYYY-MM
- * 
- * 
- */
-def get_nav_for_hedge_fund_performance(fund_ids, month_end) {
-   
-    s_query = "CALL pfdb.sp_get_nav_for_fund_performance(" + fund_ids + ", '" + month_end + "', 1);"
-
-    conn = connect_mysql()
-
-    t = odbc::query(conn, s_query)
-
-    conn.close()
-
-    return t
-
-}
-
-
-/*
  *  取基金证券从某日期后的所有净值及前值
  *  
  *  @param entity_type <STRING>: MF, HF, EQ, CF, MI, TI, CI, FA, PF
@@ -735,11 +731,43 @@ def get_entity_nav_by_date(entity_type, s_json, isFromMySQL=true) {
 
     if(isFromMySQL == true) {
 
-        s_query = "SELECT t.entity_id, t.price_date, nav." + desc.nav_col + " AS cumulative_nav
+        s_query = "SELECT t.entity_id, nav.price_date, nav." + desc.cumulative_nav_col + " AS cumulative_nav, nav." + desc.nav_col + " AS nav
                    FROM JSON_TABLE ( '" + s_json + "', '$[*]'
                            COLUMNS ( entity_id " + iif(entity_type=='PF', 'INT', 'VARCHAR(10)') + " PATH '$.entity_id',
                                      price_date DATE PATH '$.price_date' ) ) t
-                   LEFT JOIN " + desc.table_name + " nav ON t.entity_id = nav." + desc.sec_id_col + " AND t.price_date = nav.price_date;";
+                   LEFT JOIN " + desc.table_name + " nav ON t.entity_id = nav." + desc.sec_id_col + " AND t.price_date = nav.price_date
+                   WHERE nav.isvalid = 1
+                     AND nav." + desc.cumulative_nav_col + " > 0
+                   ORDER BY t.entity_id;";
+
+        conn = connect_mysql();
+
+        t = odbc::query(conn, s_query);
+     
+        conn.close();
+    }
+
+    return t;
+	
+}
+
+
+/*
+ *  通用取Json中指定日期后(含当日)的证券收益
+ *  
+ *  @param freq <STRING>: m, w
+ * 
+ *
+ *  Example: get_entity_ret_by_date('PF', '[{"entity_id": 166002,"price_date": "2024.10.25"},{"entity_id": 166114,"price_date": "2024.03.13"}]', 'm', true);
+ *           get_entity_ret_by_date('MF', '[{"entity_id": "MF00003PW1","price_date": "2023.12.28"}]', 'w', true);
+ */
+def get_entity_ret_by_date(entity_type, s_json, freq, isFromMySQL=true) {
+
+    t = null;
+
+    if(isFromMySQL == true) {
+
+        s_query = "CALL pfdb.sp_get_return_by_json('" + entity_type + "', '" + freq + "', '" + s_json + "');";
 
         conn = connect_mysql();
 

+ 105 - 9
modules/rbsaCalculator.dos

@@ -1,7 +1,8 @@
 module fundit::rbsaCalculator
 
-use fundit::performanceDataPuller
-use fundit::operationDataPuller
+use fundit::sqlUtilities;
+use fundit::performanceDataPuller;
+use fundit::operationDataPuller;
 
 /*
  *   RBSA 计算
@@ -78,7 +79,7 @@ def cal_rolling_rbsa(ret, index_ret, is_long, window, step) {
     i = (t.size() - window) % step
 
     // 运行rbsa计算次数
-    cnt = (t.size() - i - window) / step;
+    cnt = (t.size() - i - window) / step + 1;
     
     tb = table(max(cnt,1):0, ["effective_date", "price_date", "index_id", "weights", "alpha", "r2", "adj_r2"], [STRING, DATE, STRING, DOUBLE, DOUBLE, DOUBLE, DOUBLE]);
 
@@ -125,7 +126,7 @@ def cal_rolling_rbsa(ret, index_ret, is_long, window, step) {
             
             cnt -= 1
     
-        } while( cnt >= 0)
+        } while( cnt > 0)
         
     }
 
@@ -150,11 +151,11 @@ def cal_rolling_rbsa(ret, index_ret, is_long, window, step) {
  *  
  *  TODO: 数字与界面和数据库都对不上
  *  
- *  Example: cal_entity_RBSA('MF', 'MF00003PW1', ['IN00000008', 'IN00000077', 'IN0000007G', 'IN0000009M'], 'w', 1900.01.01, 2024.11.15, true, 24, 24);
- *           cal_entity_RBSA('PF', 166002, ['FA00000VML', 'FA00000VMM', 'FA00000VMN', 'FA00000VMO', 'IN0000007G'], 'w', 2020.01.01, 2024.11.08, true, 24, 24);
- *           cal_entity_RBSA('MF', 'MF000200KQ', ['IN00000008', 'IN00000077', 'IN0000007G', 'IN0000009M'], 'w', 1900.01.01, 2024.11.16, true, 24, 24);
+ *  Example: cal_single_entity_RBSA('MF', 'MF00003PW1', ['IN00000008', 'IN00000077', 'IN0000007G', 'IN0000009M'], 'w', 1900.01.01, 2024.11.15, true, 24, 24);
+ *           cal_single_entity_RBSA('PF', 166002, ['FA00000VML', 'FA00000VMM', 'FA00000VMN', 'FA00000VMO', 'IN0000007G'], 'w', 2020.01.01, 2024.11.08, true, 24, 24);
+ *           cal_single_entity_RBSA('MF', 'MF000200KQ', ['IN00000008', 'IN00000077', 'IN0000007G', 'IN0000009M'], 'w', 1900.01.01, 2024.11.16, true, 24, 24);
  */
-def cal_entity_RBSA(entity_type, entity_id, index_ids, freq='w', start_day=1900.01.01, end_day=2099.12.31, is_long=true, window=24, step=24) {
+def cal_single_entity_RBSA(entity_type, entity_id, index_ids, freq='w', start_day=1900.01.01, end_day=2099.12.31, is_long=true, window=24, step=24) {
 // entity_type='MF'
 // entity_id= 'MF00003PW1'
 // index_ids=['IN00000008', 'IN00000077', 'IN0000007G', 'IN0000009M']
@@ -173,7 +174,7 @@ def cal_entity_RBSA(entity_type, entity_id, index_ids, freq='w', start_day=1900.
     
 	entity_ret = get_entity_return(entity_type, v_entity, freq, start_day, end_day, true);
 
-	// 数据长度不够,按照顺序依次分别用母基金(4), 指数(3)的数据来代替
+	// 数据长度不够,按照顺序依次分别用母基金(4), 指数(3)的数据来代替 (level=2, 基金经理的数据在Java里好像没用?)
 	level = 1
 	alternative_id = NULL;
 	if(entity_ret.isVoid() || entity_ret.size() < window) {
@@ -218,3 +219,98 @@ def cal_entity_RBSA(entity_type, entity_id, index_ids, freq='w', start_day=1900.
 	
 }
 
+
+/*
+ *  计算单基金或组合的RBSA
+ * 
+ *  @param entity_type <STRING>: 目标基金/组合的类型
+ *  @param entity_id <STRING>: 目标基金/组合的ID
+ *  @param index_ids <VECTOR>: 基准指数IDs
+ *  @param freq <STRING>: m, w, d
+ *  @param start_day <DATE>
+ *  @param end_day <DATE>
+ *  @param is_long <BOOL>: 是否只考虑纯多头
+ *  @param window <INT>: 窗口(必须多于基准指数个数)
+ *  @param step <INT>: 步长
+ *  
+ *  @return <TABLE>: entity_id, effective_date, price_date, index_id, weights, alternative_id, level, alpha, r2, adj_r2
+ *  
+ *  TODO: 数字与界面和数据库都对不上
+ *  
+ */
+def cal_entity_RBSA(entity_type, entity_ret, index_ret, freq='w', start_day=1900.01.01, end_day=2099.12.31, is_long=true, window=24, step=24) {
+// entity_type='MF'
+// freq='w'
+// start_day=2023.12.28
+// end_day=today()
+// is_long=true
+// window=48
+// step=13
+
+    tb_result = table(100:0, ["entity_id", "effective_date", "index_id", "weights", "alpha", "r2", "adj_r2"], 
+                             [iif(entity_type=='PF', INT, STRING), STRING, STRING, DOUBLE, DOUBLE, DOUBLE, DOUBLE]);
+
+	if(index_ret.isVoid() || index_ret.size() == 0) return tb_result;
+
+	tb_entity_ret = entity_ret;
+
+	// 数据长度不够,按照顺序依次分别用母基金(4), 指数(3)的数据来代替 (level=2, 基金经理的数据在Java里好像没用?)
+	level = 1
+	alternative_id = NULL;
+	if(tb_entity_ret.isVoid() || tb_entity_ret.size() < window) {
+		if(entity_type IN ['MF', 'HF']) {
+
+			fund_info = get_fund_info(tb_entity_ret.entity_id);
+			p_fund_id = fund_info.p_fund_id;
+			primary_benchmark_id = fund_info.benchmark_id;
+			if(p_fund_id != NULL) {
+				tb_entity_ret = get_entity_return(entity_type, p_fund_id , freq, start_day, end_day, true);
+				alternative_id = p_fund_id[0];
+				level = 4;
+			} else if(primary_benchmark_id != NULL) {
+				tb_entity_ret = get_entity_return(entity_type, primary_benchmark_id, freq, start_day, end_day, true);
+				alternative_id = primary_benchmark_id[0];
+				level = 3;
+			} else {
+				return tb_result;
+			}
+		} else if(entity_type == 'PF'){
+
+			portfolio_info = get_portfolio_info(tb_entity_ret.entity_id);
+			primary_benchmark_id = portfolio_info.benchmark_id;
+			if(primary_benchmark_id != NULL) {
+				tb_entity_ret = get_entity_return(entity_type, primary_benchmark_id, freq, start_day, end_day, true);
+				alternative_id  = primary_benchmark_id[0];
+				level = 3;
+			} else
+				return tb_result;
+		}
+	}
+
+	tb_entity_ret.addColumn('effective_date', STRING);
+	tb_index_ret = index_ret;
+	tb_index_ret.addColumn('effective_date', STRING);
+
+	if(freq == 'm') {
+
+		UPDATE tb_entity_ret SET effective_date = price_date.temporalFormat('yyyy-MM');
+		UPDATE tb_index_ret SET effective_date = price_date.temporalFormat('yyyy-MM');
+		
+	} else if(freq == 'w') {
+
+		UPDATE tb_entity_ret SET effective_date = get_year_week(price_date);
+		UPDATE tb_index_ret SET effective_date = get_year_week(price_date);
+
+	} else {
+
+		UPDATE tb_entity_ret SET effective_date = price_date$STRING;
+		UPDATE tb_index_ret SET effective_date = price_date$STRING;
+	}
+
+	tb_result = SELECT entity_ret.entity_id[0] AS entity_id, effective_date, price_date, index_id, weights, alternative_id, level, alpha, r2, adj_r2
+	            FROM cal_rolling_rbsa(tb_entity_ret, tb_index_ret, is_long, window, step);
+
+	return tb_result;
+	
+}
+

+ 12 - 8
modules/sqlUtilities.dos

@@ -156,15 +156,17 @@ def get_nav_table_description(entity_type) {
 def get_performance_table_description(entity_type) {
 
     tmp_universe = table(100:0, 
-                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col'],
-                         [STRING, STRING, STRING, STRING]);
+                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col', 'ret_col', 'prefix'],
+                         [STRING, STRING, STRING, STRING, STRING, STRING]);
 
     // 分别对应:私募,公募,私有基金,股票,市场指数,图译指数,私有指数,图译因子,组合
     INSERT INTO tmp_universe VALUES ( 
         ['HF', 'MF', 'CF', 'EQ', 'MI', 'FI', 'CI', 'FA', 'PF', 'PL', 'CO'],
         ['mfdb.fund_performance', 'mfdb.fund_performance', 'pfdb.pf_cus_fund_performance', 'mfdb.stock_performance', 'mfdb.fund_performance', 'mfdb.fund_performance', 'pfdb.cm_udf_index_performance', 'pfdb.cm_factor_performance', 'pfdb.pf_portfolio_performance', 'mfdb.manager_performance', 'mfdb.company_performance'],
         ['fund_id', 'fund_id', 'fund_id', 'sec_id', 'fund_id', 'fund_id', 'index_id', 'factor_id', 'portfolio_id', 'manager_id', 'company_id'],
-        ['cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'factor_value', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav'] );
+        ['cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'factor_value', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav'],
+        ['ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m', 'ret_1m'],
+        ['HF', 'MF', 'CF', 'EQ', 'IN', 'IN', 'CI', 'FA', '', 'PL', 'CO']);
 
     return (SELECT * FROM tmp_universe u WHERE u.type = entity_type);
     
@@ -176,8 +178,8 @@ def get_performance_table_description(entity_type) {
 def get_performance_weekly_table_description(entity_type) {
 
     tmp_universe = table(100:0, 
-                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col', 'prefix'],
-                         [STRING, STRING, STRING, STRING, STRING]);
+                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col', 'ret_col', 'prefix'],
+                         [STRING, STRING, STRING, STRING, STRING, STRING]);
 
     // 分别对应:私募,公募,私有基金,股票,市场指数,图译指数,私有指数,图译因子,组合
     INSERT INTO tmp_universe VALUES ( 
@@ -185,6 +187,7 @@ def get_performance_weekly_table_description(entity_type) {
         ['mfdb.fund_performance_weekly', 'mfdb.fund_performance_weekly', 'pfdb.pf_cus_fund_performance_weekly', 'mfdb.stock_performance_weekly', 'mfdb.fund_performance_weekly', 'mfdb.fund_performance_weekly', 'pfdb.cm_udf_index_performance_weekly', 'pfdb.cm_factor_performance_weekly', 'pfdb.pf_portfolio_performance_weekly'],
         ['fund_id', 'fund_id', 'fund_id', 'sec_id', 'fund_id', 'fund_id', 'index_id', 'factor_id', 'portfolio_id'],
         ['cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'factor_value', 'cumulative_nav'],
+        ['ret_1w', 'ret_1w', 'ret_1w', 'ret_1w', 'ret_1w', 'ret_1w', 'ret_1w', 'ret_1w', 'ret_1w'],
         ['HF', 'MF', 'CF', 'EQ', 'IN', 'IN', 'CI', 'FA', '']);
 
     return (SELECT * FROM tmp_universe u WHERE u.type = entity_type);
@@ -198,15 +201,16 @@ def get_performance_weekly_table_description(entity_type) {
 def get_latest_performance_table_description(entity_type) {
 
     tmp_universe = table(100:0, 
-                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col'],
-                         [STRING, STRING, STRING, STRING]);
+                         ['type', 'table_name', 'sec_id_col', 'cumulative_nav_col', 'prefix'],
+                         [STRING, STRING, STRING, STRING, STRING]);
 
     // 分别对应:私募,公募,私有基金,股票,市场指数,图译指数,私有指数,图译因子,组合
     INSERT INTO tmp_universe VALUES ( 
         ['HF', 'MF', 'CF', 'EQ', 'MI', 'FI', 'CI', 'FA', 'PF'],
         ['mfdb.fund_latest_nav_performance', 'mfdb.fund_latest_nav_performance', 'pfdb.pf_cus_fund_latest_nav_performance', 'mfdb.stock_latest_nav_performance', 'mfdb.fund_latest_nav_performance', 'mfdb.fund_latest_nav_performance', 'pfdb.cm_udf_index_latest_nav_performance', 'pfdb.pf_factor_latest_nav_performance', 'pfdb.pf_portfolio_latest_nav_performance'],
         ['fund_id', 'fund_id', 'fund_id', 'sec_id', 'fund_id', 'fund_id', 'index_id', 'factor_id', 'portfolio_id'],
-        ['cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'factor_value', 'cumulative_nav'] );
+        ['cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'cumulative_nav', 'factor_value', 'cumulative_nav'],
+        ['HF', 'MF', 'CF', 'EQ', 'IN', 'IN', 'CI', 'FA', '']);
 
     return (SELECT * FROM tmp_universe u WHERE u.type = entity_type);
     

+ 2 - 2
modules/task_portfolioPerformance.dos

@@ -418,7 +418,7 @@ def CalFactorPerformanceTask(updatetime) {
  *   TODO: M* category average, manager, company
  * 
  * 
- *   Example: CalCategoryAverageNavTask(2024.11.01);
+ *   Example: CalCategoryAverageNavTask(2024.11.01); (22min)
  *            CalCategoryAverageNavTask(1989.01.01);  -- 【初始化专用】
  */
 def CalCategoryAverageNavTask(updatetime) {
@@ -453,7 +453,7 @@ def CalCategoryAverageNavTask(updatetime) {
 
 			t_index_value = SELECT entity_id AS index_id, price_date, nav AS index_value, incl_cal_count AS incl_cal_fund_count, total_cnt AS total_fund_count
 			                FROM ej(t_tmp, t_ret, ['entity_id', 'price_date']);
-			indexes_ty_index
+
 			save_and_sync(t_index_value, 'raw_db.indexes_ty_index', );
 	
 			if(is_save_local == true) {

+ 22 - 7
modules/task_weeklyPerformnce.dos

@@ -15,7 +15,8 @@ use fundit::dataSaver;
  *   
  *   @param entityType <STRING>: MF, HF, PF   (MF和HF等效)
  *   
- *   TODO: portfolio 未测试
+ *   TODO: 是否要 monthly 运行,并写入 history 表?
+ *         portfolio 未测试
  * 
  *   Example: CalEntityRBSATask('MF', ['MF00003PW1'], 2024.10.14T10:00:00);
  *            CalEntityRBSATask('MF', NULL, 2024.11.25T10:00:00);
@@ -25,7 +26,7 @@ def CalEntityRBSATask(entityType, entityIds, updateTime) {
 //entityIds = ['MF00003PW1']
 //updateTime = 2024.10.14T10:00:00
 
-	t_cal = get_entity_list_by_weekly_return_updatetime(entityType, entityIds, updateTime, true);
+	t_cal = get_entity_list_by_latest_return_updatetime(entityType, entityIds, updateTime, true);
 
 	window = 48;
 	step = 13;
@@ -34,6 +35,12 @@ def CalEntityRBSATask(entityType, entityIds, updateTime) {
 
 	d_rbsa = get_rbsa_index();
 
+	// 拿到所有指数ID
+	v_index = d_rbsa.values().flatten().distinct();
+	
+    // 因为用来做基准指数的可能是指数、因子、基金等等任何时间序列数据,所以不用填 entity_type
+    t_index_ret = get_entity_return(NULL, v_index, 'w', t_cal.price_date.min().temporalAdd(-window, 'w'), today(), true);
+
 	i = 0;
 	batch_size = 200;
 	total_cnt = t_cal.size();
@@ -44,15 +51,23 @@ def CalEntityRBSATask(entityType, entityIds, updateTime) {
 						  ["entity_id", "asset_type_id", "index_id", "effective_date", "level", "alternative_id", "weighting"], 
 		                  [iif(entityType=='PF', INT, STRING), STRING, STRING, STRING, INT, STRING, DOUBLE]);
 
-		t = t_cal[i:i+batch_size];
+		t = t_cal[i: min(total_cnt, i+batch_size)];
+
+		// 起始日期是最早更新的净值日期再向前推一个时间窗口
+		s_json = (SELECT entity_id, price_date.temporalAdd(-window, 'w') AS price_date FROM t).toStdJson();
+		t_entity_ret = get_entity_ret_by_date(entityType, s_json, 'w', true);
 
 		for(entity in t) {
-	
+
+			entity_ret = SELECT * FROM t_entity_ret WHERE entity_id = entity.entity_id;
+
 			for(asset_type in d_rbsa.keys()) {
-	
+
+				index_ret = SELECT entity_id, price_date, ret FROM t_index_ret WHERE entity_id IN d_rbsa[asset_type] AND price_date IS NOT NULL;
+
 				// 起始日期是最早更新日期再向前推一个时间窗口
-				res = cal_entity_RBSA(entityType, entity.entity_id, d_rbsa[asset_type], 'w', 
-				                    t.price_date.temporalAdd(-window, 'w')[0], today(), true, window, step);
+				res = cal_entity_RBSA(entityType, entity_ret, index_ret, 'w', 
+				                      entity.price_date.temporalAdd(-window, 'w')[0], today(), true, window, step);
 	
 				if(res.isVoid() || res.size() == 0) continue;