Browse Source

支持分类平均指数的点位计算

Joey 4 months ago
parent
commit
37ce9c2c03

+ 51 - 0
modules/navCalculator.dos

@@ -52,6 +52,57 @@ def convert_transaction_to_snapshot(portfolio_ids, end_day) {
 }
 
 /*
+ *   通用净值计算,由收益反推 
+ *    
+ *   @param entity_type <STRING>:
+ *   @param entity_ret <TABLE>: [COLUMNS] entity_id, price_date, ret
+ *   @param freq <STRING>: d, w, m
+ * 
+ *   NOTE: 如果没有成立日,则无法计算
+ */
+def cal_entity_nav_by_return(entity_type, entity_ret, freq) {
+
+	t_nav = table(1000:0, ['entity_id', 'price_date', 'ret', 'nav' ], [iif(entity_type=='PF', INT, SYMBOL), DATE, DOUBLE, DOUBLE]);
+
+	if(entity_ret.isVoid() || entity_ret.size() == 0) return t_nav;
+
+	t_entity_info = get_entity_info(entity_type, entity_ret.entity_id.distinct());
+	UPDATE t_entity_info SET inception_date = 1900.01.01 WHERE inception_date IS NULL;
+
+	// 筛掉早于成立日的脏数据
+	t_ret = SELECT * FROM ej(entity_ret, t_entity_info, 'entity_id') WHERE price_date >= inception_date;
+
+	s_json = (SELECT entity_id.last() AS sec_id, price_date.min() AS price_date FROM t_ret GROUP BY entity_id).toStdJson();
+
+	// 取净值前值
+	t_pre_nav = get_nav_for_return_calculation(entity_type, freq, s_json, 1);
+	
+	INSERT INTO t_nav
+		SELECT entity_id, price_date, ret, double(NULL) FROM t_ret;
+
+	// 设置成立日当天的净值和收益
+	UPDATE t_nav
+		SET nav = ini_value, ret = NULL
+	FROM ej(t_nav, t_entity_info, ['entity_id', 'price_date'], ['entity_id', 'inception_date']);
+
+	// 没有前值时,做一个假记录,把成立日净值和日期填入
+	INSERT INTO t_pre_nav
+		SELECT entity_id AS sec_id, price_date, nav AS cumulative_nav, nav
+		FROM t_nav
+		WHERE nav > 0
+		  AND NOT exists ( SELECT * FROM tb_pre_nav 
+		                   WHERE t_nav.entity_id = tb_pre_nav.sec_id );
+
+    // 通过收益反算净值: nav_i = nav_0 * ∏(1 + ret_i)
+    UPDATE t_nav 
+        SET nav = (t_pre_nav.cumulative_nav * (1+ret).cumprod()).round(6) 
+    FROM ej(t_nav, t_pre_nav, 'entity_id', 'sec_id')
+    CONTEXT BY entity_id;
+
+    return t_nav;
+}
+
+/*
  *   根据持仓收益计算组合净值
  * 
  *   @param entity_cal_dates <TABLE>: 组合净值计算时间区间表,记录 [COLUMNS] entity_id, first_cal_date, latest_cal_date

+ 86 - 6
modules/performanceDataPuller.dos

@@ -34,9 +34,11 @@ def get_data_by_updatetime(table_name, updatetime, isFromMySQL=true) {
 }
 
 /*
- *  取有更新的最早周收益数据日期
+ *  取有周收益更新的基金组合列表及其最早日期
+ *  
+ *  TODO: entity_type 是否要区分MF,HF,MI,FI 待查
  * 
- *  Example: 
+ *  Example: get_entity_list_by_weekly_return_updatetime('PF', NULL, 2024.11.20, true);
  */
 def get_entity_list_by_weekly_return_updatetime(entity_type, entity_ids, updatetime, isFromMySQL=true) {
 
@@ -52,8 +54,6 @@ def get_entity_list_by_weekly_return_updatetime(entity_type, entity_ids, updatet
 
     if(isFromMySQL == true) {
 
-        nav_table_name = tmp.table_name[0];
-    
         s_query = "SELECT " + tmp.sec_id_col[0] + " AS entity_id, MIN(price_date) AS price_date 
                    FROM " + tmp.table_name[0] + "
                    WHERE isvalid = 1 " +
@@ -79,6 +79,54 @@ def get_entity_list_by_weekly_return_updatetime(entity_type, entity_ids, updatet
 
 
 /*
+ *  取有更新的最早周收益数据日期
+ *  
+ *  @return <DATE>
+ * 
+ *  Example: get_oldest_date_by_weekly_return_updatetime('MF', 2024.11.20, true);
+ */
+def get_oldest_date_by_weekly_return_updatetime(entity_type, updatetime, isFromMySQL=true) {
+
+	rt = null;
+
+    tmp = get_performance_weekly_table_description(entity_type);
+
+	if(tmp.isVoid() || tmp.size() == 0 ) return rt;
+
+    sql_entity_id = iif(entity_type == 'PF', '', " AND " + tmp.sec_id_col[0] + " LIKE '" + tmp.prefix[0] + "%'");
+
+    if(isFromMySQL == true) {
+
+        nav_table_name = tmp.table_name[0];
+    
+        s_query = "SELECT MIN(price_date) AS price_date 
+                   FROM " + tmp.table_name[0] + "
+                   WHERE updatetime >= '" + updatetime$STRING + "'" +
+                     sql_entity_id + "
+                     AND " + tmp.cumulative_nav_col[0] + " > 0
+                   GROUP BY " + tmp.sec_id_col[0];
+
+        conn = connect_mysql()
+     
+        t = odbc::query(conn, s_query)
+     
+        conn.close()
+
+		if(t.isVoid() || t.size() == 0) return rt;
+
+		rt = t[0].price_date;
+
+
+    } else {
+        
+    
+    }
+
+    return rt;
+}
+
+
+/*
  *   通用取周净值
  * 
  *   Example: get_weekly_ret('MF', ['MF00003PW1'], 2024.06.01, today(), true);
@@ -414,12 +462,15 @@ def get_nav_for_hedge_fund_performance(fund_ids, month_end) {
  *  
  *  @param entity_type <STRING>: MF, HF, EQ, CF, MI, TI, CI, FA, PF
  *  @param freq <STRING>: m, w, d
+ *  @param pre_nav_incld <INT>: 0- no pre_nav; 1- pre_nav only; 2- pre_nav + afters
  *  @param json_query <JSON>: [{sec_id:xxx, price_date: yyyy-mm-dd}]
  * 
+ *  Example: get_nav_for_return_calculation('MI', 'm', '[{"sec_id": "IN00000008","price_date": "2004-12-31"}, {"sec_id": "IN00000077","price_date": "2003-12-31"}]', 1)
+ *  
  */
-def get_nav_for_return_calculation(entity_type, freq, json_query) {
+def get_nav_for_return_calculation(entity_type, freq, json_query, pre_nav_incld=2) {
 
-    s_query = "CALL pfdb.sp_get_nav_after_date('" + entity_type + "', '" + freq + "', '" + json_query + "')";
+    s_query = "CALL pfdb.sp_get_nav_for_return_cal('" + entity_type + "', '" + freq + "', " + pre_nav_incld + ", '" + json_query + "')";
 
     conn = connect_mysql();
 
@@ -901,3 +952,32 @@ def get_bfi_index_list() {
 
 	return t;
 }
+
+
+/*
+ *  取基金分类平均的周收益
+ *  
+ *  TODO: 需要跑1分钟,待优化
+ * 
+ *  Example: get_category_avg_weekly_return('bfi', 2024.09.28, 5, 30, true);
+ *           get_category_avg_weekly_return('strategy', 2014.06.27, 5, 30, true);
+ */
+def get_category_avg_weekly_return(category_type, begin_day, trim_pct=5, min_cnt=30, isFromMySQL=true) {
+
+    t = null;
+
+    if(isFromMySQL == true) {
+
+        s_query = "CALL pfdb.sp_get_category_avg_weekly_return('" + category_type + "', '" + begin_day + "', " + trim_pct + ", " + min_cnt + ")";
+
+	    conn = connect_mysql();
+	
+	    t = odbc::query(conn, s_query);
+	
+	    conn.close();
+
+    }
+
+    return t
+}
+

+ 4 - 3
modules/sqlUtilities.dos

@@ -176,15 +176,16 @@ 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'],
-                         [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_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'] );
+        ['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);
     

+ 62 - 128
modules/task_portfolioPerformance.dos

@@ -95,7 +95,6 @@ def calEntityPerformance(entity_type, navs) {
 /*
  *   计算组合净值并存入数据库
  * 
- *   TODO: release 时改变同步目标表为正式表
  */
 def cal_and_save_portfolio_nav(cal_portfolio_info, is_save_local) {
 
@@ -150,136 +149,14 @@ def cal_and_save_portfolio_nav(cal_portfolio_info, is_save_local) {
     return rt;
 }
 
-/*
- *  计算组合标准指标并存入数据库
- * 
- *  TODO: release 时改变同步目标表为正式表
- */
-def cal_and_save_portfolio_indicators(cal_portfolio_info, is_save_local) {
-
-    rt = '';
-
-    // 准备类似MySQL结构的数据表
-    tb_portfolio_performance = create_entity_performance(true);
-
-    tb_portfolio_indicator = create_entity_indicator(true);
-    tb_portfolio_risk_stats = create_entity_risk_stats(true);
-    tb_portfolio_riskadjret_stats = create_entity_riskadjret_stats(true);
-    tb_portfolio_style_stats = create_entity_style_stats(true);
-
-    tb_portfolio_performance_weekly = create_entity_performance_weekly(true);
-    tb_portfolio_latest_performance = create_entity_latest_performance(true);
-
-
-    // 分批跑
-    i = 0;
-    batch_size = 1000;
-
-    all_portfolio_id = EXEC DISTINCT portfolio_id FROM cal_portfolio_info;
-
-    do { 
-
-        cal_port = SELECT * FROM cal_portfolio_info
-                   WHERE portfolio_id IN all_portfolio_id[i : min(all_portfolio_id.size(), i+batch_size)];
-
-        if(cal_port.isVoid() || cal_port.size() == 0) break;
-
-        // 取数据库月度净值及前值 5 sec
-        s_json = (SELECT portfolio_id, 1900.01.01 AS price_date FROM cal_port GROUP BY portfolio_id).rename!('portfolio_id', 'sec_id').toStdJson();
-        tb_monthly_nav = get_nav_for_return_calculation('PF', 'm', s_json);
-
-        // 把 portfolio id 字段从字符串换回整型,不然后面Join table的时候会出错
-        v_portfolio_id = tb_monthly_nav.sec_id$INT;
-        tb_monthly_nav.replaceColumn!('sec_id', v_portfolio_id);
-        tb_monthly_nav.dropColumns!('nav').rename!(['sec_id', 'cumulative_nav'], ['portfolio_id', 'nav']);
-
-        // 计算各标准指标
-        indicators = calPortfolioPerformance(tb_monthly_nav);
-
-        // 仿照MySQL的表结构准备好记录 (1s)
-        port_info = (SELECT portfolio_id, start_cal_date.min() AS price_date FROM cal_port GROUP BY portfolio_id).rename!('portfolio_id', 'entity_id');
-        
-        generate_entity_performance(port_info, indicators, true, tb_portfolio_performance);
-        generate_entity_indicator(port_info, indicators, true, tb_portfolio_indicator);
-        generate_entity_risk_stats(port_info, indicators, true, tb_portfolio_risk_stats);
-        generate_entity_riskadjret_stats(port_info, indicators, true, tb_portfolio_riskadjret_stats);
-        generate_entity_style_stats(port_info, indicators, true, tb_portfolio_style_stats);
-
-        // 计算周收益 (49s)
-        port_info = SELECT * FROM ej(port_info, get_entity_info('PF', all_portfolio_id[i : min(all_portfolio_id.size(), i+batch_size)]), 'entity_id')
-        rets_w = cal_weekly_returns('PF', port_info);
-
-        if(! rets_w.isVoid() && rets_w.size() > 0) {
-            // 把 portfolio id 字段从字符串换回整型,不然后面Join table的时候会出错
-            v_portfolio_id = rets_w.entity_id$INT;
-            rets_w.replaceColumn!('entity_id', v_portfolio_id);
-            
-            generate_entity_performance_weekly(port_info, rets_w, true, tb_portfolio_performance_weekly);
-        }
-
-        // 计算最新收益 (23s)
-        perf_latest = cal_latest_performance('PF', port_info, true);
-
-        if(! perf_latest.isVoid() && perf_latest.size() > 0) {
-            generate_entity_latest_performance(port_info, perf_latest, true, tb_portfolio_latest_performance);
-        }
-
-        i += batch_size;
-
-    } while (i <= cal_portfolio_info.size());
-
-
-    if(! tb_portfolio_performance.isVoid() && tb_portfolio_performance.size() > 0) {
-
-        // save data to MySQL  
-        try {
-
-            chg_columns_for_mysql(tb_portfolio_performance, 'portfolio_id');
-            save_and_sync(tb_portfolio_performance, 'raw_db.pf_portfolio_performance', 'raw_db.pf_portfolio_performance');
-
-            chg_columns_for_mysql(tb_portfolio_indicator, 'portfolio_id');
-            save_and_sync(tb_portfolio_indicator, 'raw_db.pf_portfolio_indicator', 'raw_db.pf_portfolio_indicator');
-
-            chg_columns_for_mysql(tb_portfolio_risk_stats, 'portfolio_id');
-            save_and_sync(tb_portfolio_risk_stats, 'raw_db.pf_portfolio_risk_stats', 'raw_db.pf_portfolio_risk_stats');
-
-            chg_columns_for_mysql(tb_portfolio_riskadjret_stats, 'portfolio_id');
-            save_and_sync(tb_portfolio_riskadjret_stats, 'raw_db.pf_portfolio_riskadjret_stats', 'raw_db.pf_portfolio_riskadjret_stats');
-
-            chg_columns_for_mysql(tb_portfolio_style_stats, 'portfolio_id');
-            save_and_sync(tb_portfolio_style_stats, 'raw_db.pf_portfolio_style_stats', 'raw_db.pf_portfolio_style_stats');
-
-            save_and_sync(tb_portfolio_performance_weekly, 'raw_db.pf_portfolio_performance_weekly', 'raw_db.pf_portfolio_performance_weekly');
-
-            save_and_sync(tb_portfolio_latest_performance, 'raw_db.pf_portfolio_latest_performance', 'raw_db.pf_portfolio_latest_performance');
-
-            // 数据初始化时将指标存入本地
-            if(is_save_local == true) {
-            	save_table(tb_portfolio_performance, 'pfdb.pf_portfolio_performance', false);
-            	save_table(tb_portfolio_indicator, 'pfdb.pf_portfolio_indicator', false);
-            	save_table(tb_portfolio_risk_stats, 'pfdb.pf_portfolio_risk_stats', false);
-            	save_table(tb_portfolio_riskadjret_stats, 'pfdb.pf_portfolio_riskadjret_stats', false);
-            	save_table(tb_portfolio_style_stats, 'pfdb.pf_portfolio_style_stats', false);
-	           	save_table(tb_portfolio_performance_weekly, 'pfdb.pf_portfolio_performance_weekly', false);
-            	save_table(tb_portfolio_latest_performance, 'pfdb.pf_portfolio_latest_performance', false);	
-            }
-
-        } catch(ex) {
-
-            //TODO: Log errors
-            rt = ex;
-        }
-    }
-
-    return rt;
-
-}
-
 
 /*
  *  通用计算标准指标并存入数据库
+ *  
+ *  @param entity_type <STRING>
+ *  @param cal_entity_info <TABLE>: [COLUMNS] entity_id, start_cal_date
+ *  @param is_save_local <BOOL>
  * 
- *  TODO: release 时改变同步目标表为正式表
  */
 def cal_and_save_entity_indicators(entity_type, cal_entity_info, is_save_local) {
 
@@ -486,7 +363,7 @@ def cal_and_save_factor_nav(cal_factor_info, is_save_local) {
 
 		if(!t_tmp.isVoid() && t_tmp.size() > 0) {
 	    	INSERT INTO t_factor_value 
-	        	SELECT entity_id AS factor_id, price_date, nav AS factor_value FROM cal_nav_by_return('FA', t_factor, t);
+	        	SELECT entity_id AS factor_id, price_date, nav AS factor_value FROM t_tmp;
 		}
 	}
 
@@ -505,6 +382,8 @@ def cal_and_save_factor_nav(cal_factor_info, is_save_local) {
  *   [定时任务]批量计算bfi因子净值、收益及指标
  *   
  *   @param updatetime <DATETIME>: 成分指数净值更新时间,忽略或传入1989.01.01及更早的日期被认为在做数据初始化
+ *   
+ *   TODO: 由减运算合成的BFI还未涉及,如FA00000SMB
  * 
  * 
  *   Example: CalFactorPerformanceTask(2024.10.28);
@@ -531,3 +410,58 @@ def CalFactorPerformanceTask(updatetime) {
 }
 
 
+/*
+ *   [定时任务]批量计算各类平均指数的点位
+ *   
+ *   @param updatetime <DATETIME>: 成分指数净值更新时间,忽略或传入1989.01.01及更早的日期被认为在做数据初始化
+ *   
+ *   TODO: M* category average, manager, company
+ * 
+ * 
+ *   Example: CalCategoryAverageNavTask(2024.11.01);
+ *            CalCategoryAverageNavTask(1989.01.01);  -- 【初始化专用】
+ */
+def CalCategoryAverageNavTask(updatetime) {
+
+	rt = '';
+
+	v_category_type = ['strategy', 'substrategy', 'bfi'];
+
+	// 取有周收益有更新的最早日期
+	date_hedge_fund = get_oldest_date_by_weekly_return_updatetime('PF', updatetime, true);
+	date_mutual_fund = get_oldest_date_by_weekly_return_updatetime('MF', updatetime, true);
+
+    if(date_hedge_fund.isNull() && date_mutual_fund.isNull()) return rt;
+
+    is_save_local = iif(updatetime <= get_ini_data_const()['date'], true, false);
+
+    // 
+    for(category_type in v_category_type) {
+
+		oldest_date = min([date_hedge_fund, date_mutual_fund]);
+
+    	// it could take mysql a few minutes to get results
+	    t_ret = get_category_avg_weekly_return(category_type, oldest_date, 5, 30, true);
+
+	    if(t_ret.isVoid() || t_ret.size() == 0) continue;
+
+	    t_ret.rename!('index_id', 'entity_id');
+
+	    t_tmp = cal_entity_nav_by_return('FI', t_ret, 'w');
+
+		if(! t_tmp.isVoid() && t_tmp.size() > 0) {
+
+			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) {
+				save_table(t_index_value, 'mfdb.indexes_ty_index', false);
+			}
+		}
+    }
+
+    return rt;
+}
+

+ 42 - 21
modules/task_weeklyPerformnce.dos

@@ -14,45 +14,66 @@ use fundit::dataSaver;
  *   根据收益更新日期计算 RBSA
  *   
  *   @param entityType <STRING>: MF, HF, PF   (MF和HF等效)
+ *   
+ *   TODO: portfolio 未测试
  * 
- *   Example: CalFundRBSATask('MF', ['MF00003PW1'], 2024.10.14T10:00:00);
+ *   Example: CalEntityRBSATask('MF', ['MF00003PW1'], 2024.10.14T10:00:00);
+ *            CalEntityRBSATask('MF', NULL, 2024.11.25T10:00:00);
  */
 def CalEntityRBSATask(entityType, entityIds, updateTime) {
 // entityType = 'MF'
 //entityIds = ['MF00003PW1']
 //updateTime = 2024.10.14T10:00:00
 
-	tb_result = table(100:0,
-					  ["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 = get_entity_list_by_weekly_return_updatetime(entityType, entityIds, updateTime, true);
+	t_cal = get_entity_list_by_weekly_return_updatetime(entityType, entityIds, updateTime, true);
 
 	window = 48;
 	step = 13;
 
-	if(t.isVoid() || t.size() == 0) return;
+	if(t_cal.isVoid() || t_cal.size() == 0) return;
 
 	d_rbsa = get_rbsa_index();
 
-	for(entity in t) {
+	i = 0;
+	batch_size = 200;
+	total_cnt = t_cal.size();
 
-		for(asset_type in d_rbsa.keys()) {
+	do {
 
-			// 起始日期是最早更新日期再向前推一个时间窗口
-			res = cal_entity_RBSA(entityType, entity.entity_id, d_rbsa[asset_type], 'w', 
-			                    t.price_date.temporalAdd(-window, 'w')[0], today(), true, window, step);
+		tb_result = table(1000:0,
+						  ["entity_id", "asset_type_id", "index_id", "effective_date", "level", "alternative_id", "weighting"], 
+		                  [iif(entityType=='PF', INT, STRING), STRING, STRING, STRING, INT, STRING, DOUBLE]);
 
-			// 每日任务只负责更新最新的rbsa结果
-			latest_date = (EXEC price_date.max() AS price_date FROM res)[0];
+		t = t_cal[i:i+batch_size];
 
-			tb_result.tableInsert(SELECT entity_id, asset_type, index_id, price_date, level, alternative_id, weights 
-			                      FROM res WHERE price_date = latest_date);
+		for(entity in t) {
+	
+			for(asset_type in d_rbsa.keys()) {
+	
+				// 起始日期是最早更新日期再向前推一个时间窗口
+				res = cal_entity_RBSA(entityType, entity.entity_id, d_rbsa[asset_type], 'w', 
+				                    t.price_date.temporalAdd(-window, 'w')[0], today(), true, window, step);
 	
+				if(res.isVoid() || res.size() == 0) continue;
+	
+				// 每日任务只负责更新最新的rbsa结果
+				latest_date = (EXEC price_date.max() AS price_date FROM res)[0];
+	
+				tb_result.tableInsert(SELECT entity_id, asset_type, index_id, price_date, level, alternative_id, weights 
+				                      FROM res WHERE price_date = latest_date);
+		
+			}
 		}
-	}
 	
-	save_and_sync(tb_result, 'raw_db.pf_fund_rbsa_breakdown', 'raw_db.pf_fund_rbsa_breakdown');
+		if(entityType IN ['MF', 'HF'])
+			save_and_sync(tb_result, 'raw_db.pf_fund_rbsa_breakdown', 'raw_db.pf_fund_rbsa_breakdown');
+		else
+			save_and_sync(tb_result, 'raw_db.pf_portfolio_rbsa_breakdown', 'raw_db.pf_portfolio_rbsa_breakdown');
+
+		i += batch_size;
+
+	} while (i < total_cnt);
+
 }
 
 
@@ -67,15 +88,15 @@ def CalEntityRBSATask(entityType, entityIds, updateTime) {
  *   Example: MatchEntityBFITask('MF', 2024.11.20);
  */
 def MatchEntityBFITask(entityType, date) {
-//entityType = 'MF'
+//entityType = 'PF'
 //date = 2024.11.20
 
 	rt = '';
 
     if(find(['HF', 'MF', 'PF'], entityType) < 0) return null;
 
-    // 取有最新净值变动的基金列表 (1s)
-    tb_cal_entity = get_entity_list_by_nav_updatetime(entityType, NULL, date, true);
+    // 取有最新周收益变动的基金列表 (1s)
+    tb_cal_entity = get_entity_list_by_weekly_return_updatetime(entityType, NULL, date, true);
 
     if(tb_cal_entity.isVoid() || tb_cal_entity.size() == 0 ) return;