云计算百科
云计算领域专业知识百科平台

每日财经知识:博格公式选股——一个公式,筛出能长期持有的好公司(基于:TuShare API)

原创 | 来自北方狼 · StockStudy园地 | 2026年8月5日 17:41 重庆

前置说明:如需要下载本文代码(共有 360M 左右,基础数据),请大家关注微信公众号:“StockStudy园地” 后台回复:

  • 回复:基础数据,就可以下载基础数据。
  • 回复:博格选股代码,就可以下载本文算法代码。
  • 回复:博格选股结果,就可以下载本文代码运行的结果文件(基于 2026年8月5日 收盘数据为准),这样大家仅靠这个数据都可以参考很久,因为长期数据变化不大。

  • 【核心观点】

  • 长期收益 = 股息率 + 盈利增速,估值噪音抵消
  • 股息率 < 0.5% 淘汰,增速打折封顶 15%
  • 公式仅作初筛,须叠加基本面人工复核
  • 前言

    投资最核心的难点,是在纷繁复杂的市场中找到稳定赚钱的公司。很多散户追热点、炒题材,最后只拿到纸面浮盈,拿不到真实现金流。先锋集团创始人约翰·博格提出的博格公式,剥离股价短期波动噪音,只抓长期收益两大核心来源,普通人零基础也能学会,既可手动在炒股软件测算,也能用 Python + Tushare 全自动批量选股。


    一、通俗故事:看懂博格公式底层逻辑

    假设两个合作对象:

  • 朋友 A:每年稳定给你现金分红,分红逐年上涨,去年分 5 万,今年预期 5.5 万,收益实打实落袋;
  • 朋友 B:从不分红,只会口头承诺"明年暴富",年年画饼无现金兑现。
  • 理性人都会选择 A,但股市里大量投资者偏爱"讲故事、无分红"的 B 类公司。博格公式就是一套量化筛选标准,专门锁定持续分红、盈利稳定增长的优质企业。

    约翰·博格核心结论:持有周期拉长至 10 年以上,市盈率估值涨跌会相互抵消,股票长期年化收益仅由两部分决定:现金分红、企业净利润长期增长。

    简化核心公式(个股长期测算版):

    预期年化收益率 ≈ TTM 股息率 + 保守修正永续利润增速

    判定标准:两者相加 ≥ 10%,纳入长期观察池。


    二、三大核心基础概念(大众易懂版)

    2.1 TTM 股息率(确定现金收益)

  • 定义:过去 12 个月每股现金分红 ÷ 当前股价,反映当下买入每年能拿到的现金回报;
  • 实操举例:
    • 个股全年两次分红:10 派 5(每股 0.5 元)、10 派 3(每股 0.3 元),全年合计每股分红 0.8 元,现价 16 元。
    • TTM 股息率 = 0.8 ÷ 16 = 5%;
  • 作用:唯一不依赖市场行情、能直接到手的收益,是投资安全垫;快速过滤标准:股息率 < 0.5% 直接淘汰。
  • 2.2 CAGR 复合年均增长率(剔除短期水分)

  • 定义:把多年波动的净利润增速折算成匀速复利增长年化值,避免单一年份一次性收益(卖资产、政府补贴)干扰判断;
  • 错误算法:直接算术平均,忽略复利效应;
  • 标准计算公式:
  • CAGR = (期末值 / 期初值)^(1 / 年数) – 1

  • 举例:3 年净利润增速 15%、10%、9%。
  • 2.3 保守永续增速(历史增速打折,理性预判未来)

    核心逻辑:历史增速越高,长期维持难度越大,必须阶梯打折,同时设置上限 15%(没有企业能永久超 15% 复利增长),亏损企业保底 -5%。

    历史加权 CAGR 区间留存折算比例案例演示
    >25% 35% 历史 50% 增速,折算后 17.5%
    >20% 45% 历史 30% 增速,折算后 13.5%
    >15% 55% 历史 20% 增速,折算后 11%
    >10% 65% 历史 15% 增速,折算后 9.75%
    >5% 75% 历史 8% 增速,折算后 6%
    >0% 85% 历史 3% 增速,折算后 2.55%
    ≤0% 保底 -5% 盈利下滑,最低按 -5% 计算

    三、通达信软件手工完整测算流程(长城证券烽火版通用)

    步骤 1:提取 TTM 股息率

  • 输入股票代码,按 F10,进入「分红融资」,统计近 12 个月现金分红总额;
  • 行情页面右键自定义列,直接添加「股息率 (TTM)」一键查看;
  • 前置筛选:股息率低于 0.5% 直接放弃,无需后续计算。
  • 步骤 2:提取 7 年净利润同比增速

  • 快捷键 F11 打开成长能力页面,查看系统自带 3-5 年净利润同比;
  • 数据不足 7 年:F10 利润表翻历史年报,手动计算每年同比:
  • 当年净利润增速 = (当年净利润 – 上年净利润) ÷ |上年净利润| × 100%

    步骤 3:分别计算 3 / 5 / 7 年期 CAGR

    统一使用复利开方公式,取完整年度净利润增速数据代入。

    步骤 4:加权合并多周期增速

    权重分配:7 年 CAGR × 0.4 + 5 年 CAGR × 0.35 + 3 年 CAGR × 0.25

    示例数据:7 年 CAGR 13.38%、5 年 14.72%、3 年 11.29%

    加权原始 CAGR = 13.38 × 0.4 + 14.72 × 0.35 + 11.29 × 0.25 = 13.33%

    步骤 5:阶梯衰减打折

    13.33% 落在 10%~15% 区间,留存 65%:

    衰减后增速 = 13.33% × 0.65 = 8.66%

    步骤 6:增速封顶限制

    保守永续增速 = min(衰减后数值,15%) = 8.66%

    步骤 7:博格公式计算预期年化收益

    预期年化 = TTM 股息率 + 保守永续增速

    若个股股息率 5%,总收益 = 5% + 8.66% = 13.66% ≥ 10%,达标入选。


    四、Python + Tushare 自动化选股完整方案

    4.1 数据接口对应说明(Tushare 函数对照表)

    需要数据Tushare Pro 接口关键字段口径说明
    TTM 股息率、股价、市值、PE/PB daily_basic dv_ratio dv_ratio 原生为 TTM 股息率,与手工计算口径一致
    年报净利润同比增速 fina_indicator netprofit_yoy 仅筛选 end_date=1231 的年度数据,剔除季报
    股票名称、行业分类 stock_basic ts_code、name、industry 个股基础信息补充
    ROE、净利率 fina_indicator roe、netprofit_margin 辅助基本面校验指标

    4.2 完整代码分步实现

    1)环境初始化与 Token 配置

    import tushare as ts
    import pandas as pd
    import numpy as np
    import math

    # 替换为个人Tushare Pro Token
    ts.set_token('你的Tushare Token')
    pro = ts.pro_api()

    2)单只股票提取 7 年年报净利润同比增速

    def get_yoy_data(ts_code):
    """获取单只股票近7年年报净利润同比增速"""
    df = pro.fina_indicator(
    ts_code=ts_code,
    fields='ts_code,end_date,netprofit_yoy,ann_date'
    )
    # 仅保留12月31日年报数据
    df_annual = df[df['end_date'].str.endswith('1231')]
    # 按公告日期去重,保留最新年报
    df_annual = df_annual.sort_values('ann_date', ascending=False)
    df_annual = df_annual.drop_duplicates(subset=['end_date'])
    if df_annual.empty:
    return [], 0
    latest_year = int(df_annual['end_date'].iloc[0][:4])
    yoy_list = []
    # 提取近7年数据
    for year in range(latest_year 6, latest_year + 1):
    row = df_annual[df_annual['end_date'].str.startswith(str(year))]
    if not row.empty and pd.notna(row.iloc[0]['netprofit_yoy']):
    yoy_val = float(row.iloc[0]['netprofit_yoy'])
    yoy_list.append(yoy_val)
    return yoy_list, latest_year

    3)CAGR 计算函数(极端增速约束)

    def calc_cagr(yoy_list):
    """计算单周期复合年均增速,限制极端波动"""
    if not yoy_list or len(yoy_list) < 3:
    return None
    # 约束增速极值,避免异常值干扰
    ratios = []
    for y in yoy_list:
    y_clamp = max(95, min(300, y))
    ratios.append(1 + y_clamp / 100)
    product = 1.0
    for r in ratios:
    product *= r
    years = len(yoy_list)
    return product ** (1 / years) 1

    def get_cagrs(yoy_list):
    """分别输出3/5/7年期CAGR"""
    cagr_3y = calc_cagr(yoy_list[3:]) if len(yoy_list) >= 3 else None
    cagr_5y = calc_cagr(yoy_list[5:]) if len(yoy_list) >= 5 else None
    cagr_7y = calc_cagr(yoy_list[7:]) if len(yoy_list) >= 7 else None
    return cagr_3y, cagr_5y, cagr_7y

    4)历史增速加权 + 阶梯衰减 + 封顶函数

    def conservative_growth(cagr_3y, cagr_5y, cagr_7y):
    # 加权计算
    weight_map = []
    if cagr_7y is not None:
    weight_map.append((cagr_7y * 100, 0.40))
    if cagr_5y is not None:
    weight_map.append((cagr_5y * 100, 0.35))
    if cagr_3y is not None:
    weight_map.append((cagr_3y * 100, 0.25))
    if not weight_map:
    return 0.0
    total_w = sum(w for _, w in weight_map)
    weighted_cagr = sum(v * w for v, w in weight_map) / total_w
    # 阶梯打折
    if weighted_cagr > 25:
    decayed = weighted_cagr * 0.35
    elif weighted_cagr > 20:
    decayed = weighted_cagr * 0.45
    elif weighted_cagr > 15:
    decayed = weighted_cagr * 0.55
    elif weighted_cagr > 10:
    decayed = weighted_cagr * 0.65
    elif weighted_cagr > 5:
    decayed = weighted_cagr * 0.75
    elif weighted_cagr > 0:
    decayed = weighted_cagr * 0.85
    else:
    decayed = max(weighted_cagr, 5.0)
    # 增速上限15%
    capped = min(decayed, 15.0)
    return capped

    5)主选股函数(批量全市场筛选)

    def bogle_screening(target_return=10.0, trade_date="20260804"):
    # 获取全市场每日基础指标,过滤股息率≥0.5%
    df_daily = pro.daily_basic(
    trade_date=trade_date,
    fields='ts_code,dv_ratio,close,pe_ttm,pb,total_mv'
    )
    df_daily = df_daily[df_daily['dv_ratio'] > 0.5]
    result_list = []
    total_count = len(df_daily)
    # 遍历每只股票计算博格预期收益
    for idx, row in df_daily.iterrows():
    ts_code = row['ts_code']
    dv = row['dv_ratio']
    yoy_data, _ = get_yoy_data(ts_code)
    if len(yoy_data) < 3:
    continue
    c3, c5, c7 = get_cagrs(yoy_data)
    safe_growth = conservative_growth(c3, c5, c7)
    exp_return = dv + safe_growth
    result_list.append({
    "ts_code": ts_code,
    "TTM股息率": round(dv, 3),
    "保守永续增速%": round(safe_growth, 3),
    "博格预期年化%": round(exp_return, 3),
    "3年CAGR%": round(c3*100, 2) if c3 else None,
    "5年CAGR%": round(c5*100, 2) if c5 else None,
    "7年CAGR%": round(c7*100, 2) if c7 else None
    })
    # 每100只打印进度
    if (idx + 1) % 100 == 0:
    print(f"已处理 {idx+1}/{total_count}")
    # 筛选达标标的并排序
    df_res = pd.DataFrame(result_list)
    df_pass = df_res[df_res["博格预期年化%"] >= target_return]
    df_pass = df_pass.sort_values("博格预期年化%", ascending=False)
    return df_pass

    # 执行选股,trade_date替换为最新交易日
    qualified_df = bogle_screening(target_return=10.0, trade_date="20260804")
    print(f"博格公式筛选达标个股总数:{len(qualified_df)}")
    print(qualified_df.head(20))

    6)补充个股行业、ROE、净利率辅助信息

    def enrich_fundamental(df):
    enrich_list = []
    for _, row in df.iterrows():
    code = row["ts_code"]
    # 获取股票名称、行业
    stock_info = pro.stock_basic(ts_code=code, fields="ts_code,name,industry")
    name = stock_info.iloc[0]["name"] if not stock_info.empty else ""
    industry = stock_info.iloc[0]["industry"] if not stock_info.empty else ""
    # 获取最新ROE、净利率
    fin_ind = pro.fina_indicator(ts_code=code, limit=1, fields="roe,netprofit_margin")
    roe = round(fin_ind.iloc[0]["roe"], 2) if not fin_ind.empty else None
    margin = round(fin_ind.iloc[0]["netprofit_margin"], 2) if not fin_ind.empty else None
    line = row.to_dict()
    line.update({"股票名称": name, "行业": industry, "最新ROE%": roe, "净利率%": margin})
    enrich_list.append(line)
    return pd.DataFrame(enrich_list)

    # 调用补充信息
    full_df = enrich_fundamental(qualified_df)
    # 导出Excel本地保存
    full_df.to_excel("博格公式选股结果.xlsx", index=False)


    五、关键口径统一说明(手工计算与 Tushare 对齐)

  • dv_ratio:Tushare 原生为 TTM 过去 12 个月股息率,和软件 F10 手工统计分红计算结果完全匹配;
  • netprofit_yoy:单年度净利润同比增速,仅使用 1231 年报数据,季报、中报不参与 CAGR 运算;
  • 数据清洗规则:净利润增速正负极端值强制约束,避免一次性资产处置、政府补贴扭曲长期增长判断;
  • 时间窗口:仅上市满 3 年个股参与计算,新股无完整历史盈利数据直接剔除。

  • 六、博格公式选股局限性与风险提示

    1)适用范围限制

    • 仅适配持续稳定盈利、常年现金分红的消费、公用、高股息蓝筹;
    • 强周期行业(有色、煤炭、钢铁)净利润周期性大幅波动,CAGR 失真,筛选结果参考性低;
    • 银行、保险等金融行业财务指标特殊,ROE、盈利增速解读需额外专业分析;
    • 上市未满 3 年新股、常年亏损无分红企业无法使用该模型。

    2)模型本身短板

    博格公式只是量化初筛工具,非直接买入决策依据,筛选出标的后必须额外人工复核:

  • 企业商业模式、行业长期景气度;
  • 管理层经营稳定性、分红政策持续性;
  • 资产负债表、现金流健康度;
  • 当前估值历史分位,规避高位买入。
  • 3)投资核心逻辑重申

    博格公式放弃预测短期股价涨跌、主力资金、题材热点,只锚定两个长期核心:

  • 当下买入能稳定拿到多少现金分红;
  • 企业历史能否持续稳定创造净利润增长。
  • 长期投资不需要复杂指标堆砌,抓住现金流与成长两大锚点,即可大幅规避题材炒作陷阱。


    七、文档总结

  • 理论层:博格公式剥离短期估值波动,长期收益 = TTM 股息率 + 保守永续净利润增速,年化 ≥ 10% 为优质观察标的;
  • 实操层:通达信软件 7 步手工测算,零基础投资者可单只个股复盘;
  • 自动化层:依托 Tushare daily_basic、fina_indicator、stock_basic 三大接口,完整 Python 代码实现全市场批量选股,自动导出结果表格;
  • 风控层:明确行业、标的适配边界,量化筛选仅作初筛,必须叠加基本面人工复核,不可单一公式直接重仓。
  • 数据来源:Tushare Pro 金融数据 API
    创作时间:2026-08-05

    附:程序运行后,选出的部分股票参考(详见公众号后台回复"博格选股结果"下载)。


    本文转载自微信公众号「StockStudy园地」(作者:北方狼),原文发布于 2026年8月5日。仅供学习交流,版权归原作者所有。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 每日财经知识:博格公式选股——一个公式,筛出能长期持有的好公司(基于:TuShare API)
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!