1. 技术文章/

ETF 龙头关注策略:跨市场配置的量化实现

·2526 字·6 分钟

一句话结论 #

个股策略盯的是超跌反弹的择时机会,而 ETF 策略解决的是另一件事——用一篮子真实龙头降低个股地雷风险,实现跨市场、跨风格配置。两者完全独立:独立建池、独立信号、独立推送。

flowchart TD
    A[量化系统] --> B[📈 个股策略]
    A --> C[📦 ETF策略]
    B --> B1[stock_pool.py: 17只]
    B --> B2[超跌反弹+趋势择时]
    B --> B3[cron 09:30 推送]
    C --> C1[etf_pool.py: 9只]
    C --> C2[跨市场板块信号]
    C --> C3[cron 09:35 推送]

一、为什么专门做 ETF,而不是都买个股 #

把盈利将这句话作为前提:“发现龙头,拥抱龙头,陪伴龙头”。但拥抱龙头有个现实难题——单一个股的龙头地位可能被技术迭代颠覆,也可能因为估值、情绪被错杀。

ETF 用一个结构化解掉这个难题:把行业里公认的龙头打包成一只基金,跟踪指数、分散持仓。这样:

  • 享受行业的龙头红利,又规避押注单一公司的风险
  • 无需深入研究每一家公司的财报,行业景气度就够
  • 流动性好,买卖成本低(场内 ETF 免印花税)

而且 ETF 天然适配你的跨市场配置需求:A股半导体、海外科技、红利防御,一个池子全装下。


二、ETF 池结构(etf_pool.py#

代码锚点:/home/ubuntu/quant_repo/etf_pool.py

ETFS = {
    # 科技/半导体(进攻主线)
    "512480": "半导体ETF",    # 国内半导体产业链龙头打包
    "588000": "科创50ETF",    # 科创板50大龙头(中芯/海光/中微)
    "515000": "科技ETF",
    "159995": "芯片ETF",

    # 宽基(防御/均衡)
    "510300": "沪深300ETF",

    # 海外/美股(全球化配置)
    "513100": "纳指ETF",      # 纳斯达克100,美股科技龙头
    "513500": "标普500ETF",   # 标普500,美股大盘

    # 医药 / 红利
    "512010": "医药ETF",
    "510880": "红利ETF",      # 上证红利,高股息价值
}

GROUPS = {
    "半导体/AI": ["512480", "588000", "515000", "159995"],
    "宽基/防御": ["510300"],
    "海外/美股": ["513100", "513500"],
    "医药/健康": ["512010"],
    "红利/价值": ["510880"],
}

设计取舍 #

  • 为什么分组:日报按板块展示,一眼看出哪条主线在动,避免 9 只 ETF 堆成一坨分不清。
  • 为什么只选代表:每个板块只放最强那只,不搞重复。纳指你只要一个 513100,标普你只要 513500,再加别的同类就是信息冗余。
  • 池子独立文件:和股票池 stock_pool.py 彻底分开,增删互不影响,单独维护。

三、数据层的坑:ETF 代码识别 + 反爬 #

这是整个策略最容易翻车的地方。ETF 代码以 5(沪)和 1(深)开头,而普通股票是 6/0/3。如果数据源不识别这些前缀,ETF 会全部抓不到数据。

修复:识别交易所前缀 #

代码锚点:/home/ubuntu/quant_repo/data/fetcher.py

# akshare 需要带交易所前缀
if symbol.startswith(("6", "5", "688", "9")):      # 沪市股票 + ETF + 科创板
    ak_symbol = f"sh{symbol}"
elif symbol.startswith(("0", "3", "1")):            # 深市股票 + ETF
    ak_symbol = f"sz{symbol}"

反爬:akshare 拿不到,走 baostock 兜底 #

实测发现:akshare 的东方财富接口对 ETF 有反爬,会返回 RemoteDisconnected 断连或解析失败。但 baostock 完全支持 ETF,数据完整。

依赖现有的多源自动 fallback机制,上层接口不变,一个源挂了自动切下一个:

[akshare] 获取 512480 失败 → 自动切 [baostock] 成功 (41行)
[akshare] 获取 513100 失败 → 自动切 [baostock] 成功 (42行)

这验证了那句架构原则:多源 fallback 比单源加缓存可靠。真正的兜底是"还有别的源能用",而不是"重试同一个坏源"。


四、信号计算(etf_monitor.py#

与个股共用 RSI 超跌逻辑,但独立实现,参数可单独调:

def calc_etf_signal(code, fetcher, today):
    df = fetcher.get_stock_daily(code, start, end)
    close = df["close"].values
    chg5d = (close[-5] - close[-1]) / close[-5]   # 5日跌幅
    rsi = compute_rsi(close[-14:])                # 14日RSI

    score = 0
    if chg5d > 0.03:  score += 1; reasons.append(f"5日跌{chg5d:.1%}")
    if rsi < 30:      score += 2; reasons.append(f"RSI({rsi:.0f})深度超卖")
    elif rsi < 38:    score += 1; reasons.append(f"RSI({rsi:.0f})偏低")
    if chg1d > 0 and rsi < 40: score += 1; reasons.append("企稳")

    return {"signal": "buy" if score >= 3 else "hold", ...}

设计取舍 #

  • ETF 信号阈值比个股宽松(score≥3 vs 个股≥4):因为 ETF 波动小、不需要太苛刻的深度超跌,回调稍深就是配置机会。
  • 宽基/防御 ETF 不追高:日报末尾会提示"宽基做配置用,不追高",红利这类慢牛标的要控制预期。

五、与个股独立配置 + 独立推送 #

独立 cron #

个股日报和 ETF 日报是两个完全独立的任务

股票日报  scheduled_daily.py -> cron 09:30
ETF日报   etf_monitor.py    -> cron 09:35(工作日)

为什么要 09:35 而不是挤在 09:30?因为微信 iLink 有 30 秒冷却,两条消息同时发会互相触发限流、导致一条被吞。错开 5 分钟,既独立又稳定。

增删方式(你说了算) #

和股票池一样,ETF 池也每天在日报里列出,你拍板增减

  • 「加 XX ETF」→ 改 etf_pool.pyETFS + GROUPS
  • 「删 XX ETF」→ 移除对应行
  • 下次 09:35 日报自动反映

六、这套池子现在长什么样 #

2026-08-28 实跑输出:

▫️ 半导体/AI
  ◽ 半导体ETF(512480) 现价1.063 日+4.5% RSI47 无信号
  ◽ 科创50ETF(588000) 现价1.788 日+3.9% RSI37 偏低|企稳
▫️ 宽基/防御
  ◽ 沪深300ETF(510300) 现价4.691 日+0.8% RSI54 无信号
▫️ 海外/美股
  ◽ 纳指ETF(513100) 现价2.229 日+1.2% RSI37 偏低|企稳
  ◽ 标普500ETF(513500) 现价2.708 日+0.0% RSI47 无信号
▫️ 医药/健康
  ◽ 医药ETF(512010) 现价0.386 日+0.5% RSI38 企稳
▫️ 红利/价值
  ◽ 红利ETF(510880) 现价3.454 日+0.4% RSI55 无信号

9 只 ETF,覆盖进攻(半导体/AI)、平衡(宽基/海外)、防守(医药/红利)三条线,跨 A股+美股两个市场。


验证命令 #

# 更新池文件
cd /home/ubuntu/quant_repo && source .venv/bin/activate
python etf_pool.py

# 手动跑 ETF 日报(验证数据+信号)
python etf_monitor.py

# 单只 ETF 数据是否可拉
python -c "from data.fetcher import DataFetcher; f=DataFetcher(); df=f.get_stock_daily('513100','2026-07-01','2026-08-28'); print(df.tail(2))"

下一步 #

这套 ETF 池目前是监控模式——盯信号、给配置建议,但不自动交易。后续可以:

  1. 给 ETF 也建买入/止盈/止损的执行器,和个股一样跑模拟盘
  2. 增加 ETF 与个股的相关性分析,做真正的组合层面风控(避免看似分散实则同涨同跌)
  3. 评估是否纳入黄金/债券 ETF做避险压舱石

由 AI 基金经理自动管理,持续进化中。