从零构建股息追踪仪表盘:Python+免费API,告别每月手动复制粘贴

👉 工具网址:https://www.alphavantage.co/

我手里有一个不算大的股息投资组合——大约25个标的,涵盖REITs、ETF和几只个股。头两年,我用Google表格记录一切。每月从券商对账单里复制股息金额到单元格,手动更新持股数量,再眯着眼看一个计算成本收益率的公式。能用,但烦人、容易出错,而且对六个月后能收多少股息一无所知。

付费工具(DividendMax、Simply Safe Dividends、TrackYourDividends)都能干这个活,但免费版限制持仓数量(10-15个),预测功能得付费,而且你的数据归它们所有。在被“已达到限制”弹窗骚扰了三次后,我决定自己动手造一个。

免费的API,够用就行

在写一行代码之前,先问:数据从哪来?我用了两个免费源,零售投资者完全够用。

Yahoo Finance(通过yfinance。这个Python库封装了Yahoo的公开接口,能获取历史价格、股息历史和基本信息,不需要API Key。代价是频率限制——猛刷会被限流。但个人仪表盘每天拉一次数据,永远触不到上限。

import yfinance as yf

# 获取Realty Income(O)的股息历史
ticker = yf.Ticker("O")
dividends = ticker.dividends  # 返回Pandas Series,索引为日期,值为每股分红

dividends属性返回一个Pandas Series,每行是一个支付日期,值是每股金额。这一行代码就替代了每月手动复制粘贴的苦差事。

Alpha Vantage免费版。万一yfinance挂了(Yahoo每两年改一次接口,常有的事),Alpha Vantage免费版每天提供25次API调用——足够25个标的一天拉一次。去alphavantage.co注册一个Key,就能拿到结构化的JSON响应,比爬HTML靠谱。

import requests

url = "https://www.alphavantage.co/query"
params = {
    "function": "DIVIDENDS",
    "symbol": "O",
    "apikey": "你的KEY"  # 替换成你注册的Key
}
response = requests.get(url, params=params)

设计数据模型

Google表格的问题在于把两件事混在一起:你的持仓状态(什么股票、什么成本价)和市场数据(什么时间、付多少)。干净的数据模型应该分开。

我用SQLite建了三张表——够轻量,不需要Postgres,结构又够灵活:

  • holdings:每行一个持仓。字段:ticker(主键)、shares(持股数量)、cost_basis_per_share(每股成本价)、first_purchased(首次买入日期)、account_type(账户类型,如 taxable、Roth IRA)。
  • dividends:每行一笔股息。字段:ticker(外键关联holdings)、ex_date(除息日)、pay_date(支付日)、amount_per_share(每股金额)、source(数据来源,如’yfinance’或’alphavantage’)。建议一开始就加上source字段,哪天yfinance缓存出问题,你还能知道数据来自哪个管道。
  • prices:每日收盘价,用于计算当前收益率和组合价值。字段:tickerdateclose

为什么用SQLite而不是CSV?因为GROUP BY tickerSUM(dividends.amount_per_share * holdings.shares)在SQL里轻轻松松,而Spreadsheet公式一旦超过10个按季度支付的标的,就是一坨乱麻。SQLite零配置,数据库就是一个文件,复制就能备份。

免责声明:这不是投资建议。代码和方法仅用于个人学习和组合追踪。过去的股息不代表未来收益,仅凭基于历史数据的收益率做投资决策是危险的。

计算成本收益率(唯一值得看的指标)

大多数股息追踪App显示的是当前收益率——年股息除以当前股价。这个数字对评价你自己的回报毫无意义。如果你在48美元买入Realty Income(O),现在股价62美元,当前收益率看起来比你实际获得的投资回报更低。

成本收益率解决了这个问题:

# 计算成本收益率
yield_on_cost = (annual_dividend_per_share / cost_basis_per_share) * 100

用Python实现——累加过去12个月的每股股息,除以你的成本价。注意处理股息不固定的标的(比如BDCs和某些REITs),不能拿最近一个季度乘以4,必须实际加总365天的股息。

def yield_on_cost(ticker_symbol, db_path):
    import sqlite3
    conn = sqlite3.connect(db_path)
    # 从holdings表获取成本价
    cost = conn.execute(
        "SELECT cost_basis_per_share FROM holdings WHERE ticker = ?",
        (ticker_symbol,)
    ).fetchone()[0]

    # 累加过去一年的股息
    annual_div = conn.execute("""
        SELECT SUM(amount_per_share)
        FROM dividends
        WHERE ticker = ?
        AND pay_date >= date('now', '-365 days')
    """, (ticker_symbol,)).fetchone()[0]

    return (annual_div / cost) * 100 if cost else 0

预测未来收入

历史数据告诉你发生了什么。预测告诉你接下来会怎样——这也是你为什么值得自己做追踪器,而不是用免费App的原因。

最简单且有用的预测:拿每个标的最新季度股息,假设它保持不变(不降不升),乘以当年剩余季度。这得到的是一个基线——一个下限,不是预测。以后可以叠加股息增长假设,但仅这个下限就有行动价值:它告诉你组合在一切不变的情况下至少能产生多少收入。

可视化是关键。用堆叠柱状图,每月一根柱子,每个片段按股票着色,你能一眼看出1月份的收入被某只股票的季度分红主导,而3月份是真空区。你会发现自己组合中在表格里永远注意不到的模式。

可视化用plotly,比matplotlib好在一处:交互性。鼠标悬停在柱子上,直接显示金额和股票名称,无需对照图例。代码很简洁:

import plotly.express as px

# monthly_projections 是包含月份、金额、股票名称的DataFrame
fig = px.bar(monthly_projections, x="month", y="amount",
             color="ticker", title="未来12个月股息收入预测")
fig.write_html("dashboard.html")  # 生成独立HTML文件,无需服务器

write_html生成一个自包含的HTML文件,不需要服务器和框架,浏览器直接打开。这就是最终的仪表盘。

让它自动运行

脚本只有定时跑才有用。我用cron每天执行:

0 8 * * * /usr/bin/python3 /home/owen/dividend-tracker/update.py

每天早上8点,脚本拉取最新股息、重新计算成本收益率、重新生成HTML仪表盘,然后放到静态文件服务器的目录里。

如果不想一直开着电脑,GitHub Actions可以在公共仓库上免费定时执行。创建一个.github/workflows/update.yml,cron触发运行python update.py,把更新后的数据提交回仓库,再将HTML部署到GitHub Pages。免费版每月2000分钟运行时间——每天30秒的数据拉取,总共只用15分钟。

免费工具仍做不到的三件事

  1. 未来除息日。yfinance和Alpha Vantage免费版都只回顾历史,不告诉你下个月哪天除息。这需要付费数据源,或者接受一个月的滞后。
  2. 股息安全评分。6%的收益率不告诉你派息率是否超过120%。Morningstar、Simply Safe Dividends做了分析,免费API没有。
  3. 税务批次追踪。上述模型把同一股票的所有持仓当作一个批次。如果需要按税务批次做资本利得规划,要么建更复杂的表,要么接受这个工具不能替代券商成本跟踪器。

我最终做出来的仪表盘不会跟付费服务拼功能,但它只花了一个周六下午,跑在免费的GitHub Actions上,回答了我关心的三个问题:我正在赚多少、我的成本收益率是多少、未来12个月会怎样。对于一个25个标的的组合,这就够了。

常见问题

能先用CSV再迁移到SQLite吗?
完全可以。先用CSV存ticker,shares,cost_basis,用pandas.read_csv()读取,等发现需要联表查询或历史快照时再迁移。起点越简单,越容易坚持完成。

yfinance需要API Key吗?
不需要。它直接爬Yahoo Finance公开接口。风险是Yahoo会改接口(大概每12-18个月一次),库维护者通常几天内修复。

如何处理股票拆分?
yfinance会自动调整股息历史数据。如果你买了100股后来2:1拆分,yfinance返回的拆分前股息已经是调整后的数值。但你的成本价需要自己维护——API不知道你多少钱买的。

能部署成Web应用吗?
文中静态HTML的方法最简单。如果想要带过滤器的实时仪表盘,Streamlit从Python脚本到Web应用最快——额外20行代码就能加上账户类型和日期范围筛选器。托管到Streamlit Cloud(免费版)就能得到公开URL,无需管理服务器。


直达网址:https://www.alphavantage.co/

类似文章