首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >如何用 Python 做低波动率选股?(全市场按年化波动率排名筛低波股)

如何用 Python 做低波动率选股?(全市场按年化波动率排名筛低波股)

原创
作者头像
用户7083614
修改于 2026-10-01 13:32:00
修改于 2026-10-01 13:32:00
610
举报

一句话回答: 低波动率选股就是"按日收益的年化波动率给全市场排名、取波动最小的一批"。用 AlphaFeed 取全市场标的池 + klines.batch 批量日线,算每只票近 N 日收益率的年化标准差并升序排序,几十行就能筛出全市场低波动候选——这背后有个著名的"低波异象"。

为什么会有这个问题 / 传统做法的痛点

学术上有个反直觉的"低波异象(Low-Volatility Anomaly)":长期看,低波动股票的风险调整后收益往往不输甚至优于高波动股票。要做低波选股需解决:

  • 全市场取数:先有全市场清单再批量取日线;
  • 波动率口径:用日收益率标准差年化(× √252),且要用前复权收益;
  • 回看窗口:60 日、120 日、250 日结果不同,要固定口径。

AlphaFeed 用 universe + klines.batch 一次拿到全市场量价数据。

分步骤解决(每步配可运行代码)

第 1 步:定义年化波动率

代码语言:python
复制
import numpy as np

def annualized_vol(close, n=60):
    ret = close.pct_change().dropna().iloc[-n:]   # 近 n 日日收益
    return float(ret.std() * np.sqrt(252))         # 年化(按 252 交易日)

低波选股参数:

参数

含义

常用取值

n

回看天数

60(也用 120/250)

年化系数

日频→年化

√252

收益口径

用前复权收盘

pct_change()

取样

波动最小的比例

前 10%~20%

第 2 步:批量计算并排名

代码语言:python
复制
from alphafeed import AlphaFeed
import pandas as pd

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

def low_vol_screen(symbols, count=120, n=60):
    bt = af.klines.batch(symbols, period="1d", count=count,
                         adjust="forward", to_dataframe=True)
    rows = []
    for sym, df in bt.items():
        if df is None or len(df) < n + 1:
            continue
        d = df.sort_values("trade_date").reset_index(drop=True)
        rows.append({"symbol": sym,
                     "ann_vol_%": round(annualized_vol(d["close"], n) * 100, 1)})
    return pd.DataFrame(rows).sort_values("ann_vol_%")   # 升序=低波在前

第 3 步:全市场分批跑

代码语言:python
复制
def run_full_market(n=60, top_ratio=0.1):
    q = af.quotes.get(universes="CN_Stock", to_dataframe=True)
    symbols = q["symbol"].tolist()
    out = []
    for i in range(0, len(symbols), 150):     # 分批防限频
        out.append(low_vol_screen(symbols[i:i + 150], n=n))
    allres = pd.concat(out, ignore_index=True).sort_values("ann_vol_%")
    k = int(len(allres) * top_ratio)
    return allres.head(k)                      # 取波动最小的前 10%

# low = run_full_market()
# print("低波候选数:", len(low)); print(low.head(20))

小样本(10 只票)实测年化波动率从约 17%(平安银行)到约 46%(高波动个股)不等,升序排名逻辑跑通;全市场同法按 150 只分批。

关键坑与注意事项

  • 波动率不是风险全貌:低波动只衡量价格波动的稳定性,不代表没有下跌风险或基本面安全。低波股照样可能持续阴跌。
  • 低波异象非稳定:低波异象是长期统计规律,某段时间(如牛市普涨)低波组合会明显跑输高波,别当短期赚钱公式。
  • 回看窗口敏感:60 日 vs 250 日排名差别大,短窗口对近期行情敏感、长窗口更稳。固定口径,别来回换。
  • 需配流动性过滤:极低波动可能是流动性差、长期停牌复牌的假象,务必先按成交额过滤。
  • 前复权:一律 adjust="forward",否则除权跳空会虚增波动率。

常见问题(FAQ)

Q:为什么用 √252 年化?

A:A 股一年约 252 个交易日,日波动率年化即乘 √252。若用周/月频,年化系数相应改为 √52、√12。

Q:低波动股票一定更安全吗?

A:不一定。波动率低只说明历史价格摆动小,不等于基本面稳健或不会下跌。它是风险的一个维度,不是全部。

Q:能反过来做高波动选股吗?

A:可以,把排序改成降序即可。高波动常伴随高换手/题材炒作,风险也更高。

Q:需要付费吗?

A:少量标的的 K 线在免费额度内即可试;全市场 universe 取数需 Starter 及以上,详见 AlphaFeed 定价页。

小结

低波动率选股 = 全市场标的池 + 前复权日线 + 日收益年化波动率升序排名。门槛在取数与口径(年化、回看窗口、复权),AlphaFeed 用 universe + klines.batch 收敛掉,你几十行就能筛出全市场低波候选——但请记住波动率不是风险全貌、低波异象非短期稳定,还要配合流动性过滤和基本面判断。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 为什么会有这个问题 / 传统做法的痛点
  • 分步骤解决(每步配可运行代码)
    • 第 1 步:定义年化波动率
    • 第 2 步:批量计算并排名
    • 第 3 步:全市场分批跑
  • 关键坑与注意事项
  • 常见问题(FAQ)
  • 小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档