From a49002f62274a01c7b049400e8eae3cbfe7b3af6 Mon Sep 17 00:00:00 2001 From: aszerW Date: Thu, 14 May 2026 01:31:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(datasource):=20=E6=BA=A2=E4=BB=B7=E7=8E=87?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E6=94=B9=E7=94=A8=E5=90=8C=E4=B8=80=E5=A4=A9?= =?UTF-8?q?=E5=B8=82=E4=BB=B7=E4=B8=8E=E5=87=80=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:之前用 ffill 将前一天净值填充到当天,导致溢价率偏差过大 例如:5月13日市价 4.048 vs 5月12日净值 3.946 → 溢价率 2.58% 修复: - 不使用 ffill,只计算有净值日期的溢价率 - 使用 price_df 和 nav_df 的交集日期计算 - 溢价率 = (当天市价 - 当天净值) / 当天净值 - 5月12日市价 3.94 vs 净值 3.946 → 溢价率 ~0% 注意:净值 T+1 公布,最新一天溢价率可能无法计算 --- datasource/universal_fetcher.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/datasource/universal_fetcher.py b/datasource/universal_fetcher.py index e64b7ab..0400d58 100644 --- a/datasource/universal_fetcher.py +++ b/datasource/universal_fetcher.py @@ -236,34 +236,36 @@ class UniversalDataFetcher: 溢价率 = (ETF收盘价 - ETF净值) / ETF净值 - 注意:净值数据通常T+1公布,需要处理日期对齐问题 + 注意:净值数据通常T+1公布,只计算有净值日期的溢价率 + 不使用 ffill,只保留当天有净值数据的日期 Args: price_df: ETF价格数据(索引为日期) nav_df: ETF净值数据(索引为日期) Returns: - 溢价率Series(索引为日期,值为溢价率) + 溢价率Series(索引为净值日期,值为溢价率) """ - # 对齐日期:净值用ffill填充(因为T+1公布) - # 价格日期可能比净值日期多一天 - # 先去除重复日期 + # 去除重复日期 price_index = price_df.index if price_index.has_duplicates: price_df = price_df[~price_df.index.duplicated(keep='last')] - price_index = price_df.index nav_index = nav_df.index if nav_index.has_duplicates: nav_df = nav_df[~nav_df.index.duplicated(keep='last')] - aligned_nav = nav_df['nav'].reindex(price_index, method='ffill') + # 找到共同的日期(只有当天有净值数据才计算溢价率) + common_dates = price_df.index.intersection(nav_df.index) - # 计算溢价率 - close_prices = price_df['close'] - premium = (close_prices - aligned_nav) / aligned_nav + if len(common_dates) == 0: + return None - # 过滤掉无效值(净值缺失的日期) + # 只计算共同日期的溢价率 + close_prices = price_df.loc[common_dates, 'close'] + nav_values = nav_df.loc[common_dates, 'nav'] + + premium = (close_prices - nav_values) / nav_values premium = premium.dropna() return premium