用 Python 自动生成场外 QDII 基金申购限额和底层持仓 Excel

4 阅读6分钟

最近做了一个小工具,用来整理场外美股 QDII / 联接基金的公开数据,并生成一个 Excel 文件。

这个工具的目标不是做交易策略,也不是预测涨跌,而是解决一个很具体的问题:

```text
把分散的基金申购状态、单日限额、跟踪指数、底层持仓,整理成一张可读的 Excel。
```

最终输出大概是:

  1. 一个汇总页
  2. 每只基金一个明细页
  3. 汇总页展示申购状态和单日限额
  4. 明细页展示底层股票代码、名称和权重

一、为什么要做这个工具?

场外美股 QDII 基金经常会出现限购或暂停申购。

比如:

暂停申购
限额 100 元
限额 500 元
不限额

如果只关注一只基金,手动打开 App 看没问题。但如果想同时看多个纳斯达克 100、标普 500、标普信息科技方向的基金,手动维护就很麻烦。

另一个问题是底层持仓。

很多场外基金并不直接展示完整底层股票明细,尤其是联接基金。用户看到的是基金名称,但如果想知道它对应的底层股票权重,就需要进一步整理指数或代理 ETF 的公开持仓数据。

所以我把它拆成了两个任务:

  1. 整理场外基金列表和申购限额
  2. 整理底层指数持仓并写入 Excel

二、整体流程

整个脚本大概分成五步:

获取 QDII / 海外基金列表
筛选美股方向基金
匹配基金对应的跟踪指数
获取指数或代理 ETF 的底层持仓
生成 Excel 汇总页和基金明细页

在代码结构上,我把它拆成了几类文件:

config.py              # 基金和指数映射配置
data_fetcher.py        # 数据获取逻辑
purchase_limit.py      # 申购限额格式化和排序
main.py                # 主流程和 Excel 输出
tencent_docs_uploader.py # 可选:上传在线表格

三、基金和指数映射

核心配置是一个映射关系:

FUND_INDEX_MAP = {
    "006479": "纳斯达克100",
    "270042": "纳斯达克100",
    "050025": "标普500",
    "161125": "标普500",
    "007874": "标普科技",
    "160140": "道琼斯工业",
}

实际运行时不会只依赖手工配置,也会根据基金名称做关键词匹配。

例如:

AUTO_MATCH_RULES = [
    ("标普科技", ["标普科技", "标普信息科技"]),
    ("标普500", ["标普500", "标普 500"]),
    ("纳斯达克100", ["纳斯达克100", "纳指100", "纳指ETF"]),
    ("道琼斯工业", ["道琼斯美国精选"]),
]

这样可以覆盖一部分新增基金或命名相近的基金。

四、申购限额怎么处理?

申购限额字段的麻烦点在于,它不是单纯的数字。

可能出现:

暂停申购
0
100
500
空值
超大数值表示不限

所以我单独写了格式化逻辑,把它变成更适合展示和排序的形式。

示例逻辑:

def format_purchase_limit(purchase_status, purchase_limit):
    if "暂停" in str(purchase_status):
        return "暂停申购"

    if purchase_limit is None:
        return "不限"

    value = float(purchase_limit)

    if value <= 0:
        return "暂停申购"
    if value >= 1e10:
        return "不限"

    return f"{value:,.0f} 元"

汇总页里会优先把还能申购、限额更高的基金排在前面,把暂停申购的放到后面。

五、底层持仓怎么整理?

底层持仓这块,我使用“指数代理”的思路。

比如:

纳斯达克100 -> QQQ / Nasdaq-100 成分股
标普500 -> SPY
标普科技 -> XLK
道琼斯工业 -> DIA

配置大概长这样:

INDEX_PROXY = {
    "纳斯达克100": {
        "proxy_etf": "QQQ",
        "source": "invesco",
        "position_ratio": 0.93,
    },
    "标普500": {
        "proxy_etf": "SPY",
        "source": "ssga",
        "position_ratio": 0.93,
    },
}

最终整理出来的明细页包含:

排名
股票代码
股票名称
权重(%)

这一步的重点不是“精确预测”,而是把公开持仓数据结构化,方便在 Excel 里查看。

六、Excel 输出结构

生成的 Excel 主要分两层。

第一层是汇总页:

基金代码
基金名称
跟踪指数
最新净值
基金规模
申购状态
单日申购限额
成分股数量

第二层是基金明细页:

基金名称
基金代码
跟踪指数
最新净值
基金规模
申购状态
单日申购限额
仓位系数
数据日期

排名
股票代码
股票名称
权重(%)

这样既可以快速扫汇总,也可以点进单只基金看底层明细。

七、一个主流程示意

简化后的主流程大概是:

def main():
    qdii_df = get_qdii_fund_list()
    us_funds = filter_us_stock_funds(qdii_df, FUND_INDEX_MAP, AUTO_MATCH_RULES)
    us_funds = sort_funds_by_purchase_limit(us_funds)

    index_holdings_cache = {}
    for index_name in us_funds["跟踪指数"].unique():
        proxy_config = INDEX_PROXY[index_name]
        index_holdings_cache[index_name] = get_index_holdings(index_name, proxy_config)

    all_funds_data = []
    for _, row in us_funds.iterrows():
        code = row["基金代码"]
        name = row["基金简称"]
        index_name = row["跟踪指数"]
        holdings = index_holdings_cache[index_name]

        info, detail = build_fund_sheet_v2(
            fund_code=code,
            fund_name=name,
            index_name=index_name,
            purchase_limit=row.get("日累计限定金额"),
            purchase_status=row.get("申购状态"),
            holdings_df=holdings,
            position_ratio=INDEX_PROXY[index_name]["position_ratio"],
        )

        all_funds_data.append((f"{code}_{name[:12]}", info, detail))

    write_excel(all_funds_data, OUTPUT_EXCEL)

实际项目里还会做异常处理、列宽调整、在线表格同步等细节。

八、这个工具适合谁?

我觉得它适合这几类人:

  1. 想学习 Python 数据抓取和 Excel 自动化的人
  2. 想整理 QDII 基金公开数据的人
  3. 想维护个人复盘表格的人
  4. 想把分散信息统一到一个 Excel 文件里的人

它不适合用来做什么:

  1. 不适合当成投资建议
  2. 不适合预测涨跌
  3. 不适合替代基金公告和官方披露

九、后续可以怎么扩展?

这个工具后续还可以继续扩展:

  1. 增加更多指数方向,比如日经、印度、德国等
  2. 保存历史限额变化,做时间序列
  3. 增加邮件或飞书通知
  4. 生成在线文档,方便手机查看
  5. 做一个轻量 Web 页面展示汇总结果

十、结尾

这个项目本质上是一个公开数据整理和自动化报表生成工具。

对我来说,它比较有意思的地方不在“金融判断”,而在于如何把分散、格式不统一、需要每天查看的信息,变成一个稳定可复用的 Excel 工作流。

如果你也对这个方向感兴趣,可以私信关键词:

QDII脚本

说明:本文只做技术实现和公开数据整理方法分享,不提供任何投资建议,不承诺收益,不指导买卖。