KhueApps
Home/Python/Fetch Stock Dividend Data with Python (yfinance and pandas)

Fetch Stock Dividend Data with Python (yfinance and pandas)

Last updated: October 03, 2025

Overview

This guide shows how to fetch stock dividend data in Python using yfinance and pandas, batch tickers efficiently, and compute simple metrics like trailing 12-month (TTM) yield. It fits algorithmic trading workflows that need reproducible, scriptable data pulls.

Data source note: yfinance retrieves data from Yahoo Finance. Dates returned for dividends correspond to the ex-dividend date. Validate critical decisions with an official data vendor when necessary.

Quickstart

  1. Install dependencies.
  2. Fetch dividend history for a ticker.
  3. Compute TTM dividend yield.
  4. Batch multiple tickers.
  5. Save results for reuse.

Install

pip install yfinance pandas

Minimal working example

Fetch the dividend history for a single ticker and compute TTM yield.

import yfinance as yf
import pandas as pd

# 1) Fetch per-share cash dividends (indexed by ex-dividend date)
ticker = "AAPL"
div = yf.Ticker(ticker).dividends  # pandas Series: index=dates, values=cash per share
print("Last 5 dividends:\n", div.tail())

# 2) Compute TTM dividend sum and yield
now = pd.Timestamp.utcnow().tz_localize(None)
one_year_ago = now - pd.DateOffset(years=1)

ttm_div = div[div.index >= one_year_ago].sum()

# Latest close price (use Close; Adj Close already reflects dividends)
last_close = yf.Ticker(ticker).history(period="5d")["Close"].iloc[-1]

yield_pct = 100.0 * ttm_div / last_close if last_close > 0 else float("nan")
print(f"TTM dividend: ${ttm_div:.2f}")
print(f"Price: ${last_close:.2f}")
print(f"TTM dividend yield: {yield_pct:.2f}%")

Fetch dividends for multiple tickers (batched)

Use yf.download to reduce request overhead and obtain prices and corporate actions in one call.

import yfinance as yf
import pandas as pd

# Batch tickers
tickers = ["AAPL", "MSFT", "KO"]

# Download OHLCV plus corporate actions (dividends, splits)
# actions=True adds columns: Dividends, Stock Splits; auto_adjust=False keeps raw Close
raw = yf.download(
    tickers,
    period="5y",
    interval="1d",
    actions=True,
    auto_adjust=False,
    progress=False,
)

# raw has MultiIndex columns when multiple tickers are used
# Extract dividends and close, stack to long format: index=(Date, Ticker)
div = raw["Dividends"].stack().rename("dividend").to_frame()
close = raw["Close"].stack().rename("close").to_frame()

# Join to a tidy DataFrame with dividend amounts and prices
panel = close.join(div, how="left").fillna({"dividend": 0.0})
print(panel.head())

Compute simple total return including dividends

If you model returns from raw Close, add dividend yield on ex-dividend days. Do not add dividends if you use Adjusted Close (that would double-count).

# prices and dividends from prior section
prices = panel["close"]  # Series with MultiIndex (date, ticker)

# Daily close-to-close returns per ticker
ret = prices.groupby(level=1).pct_change().rename("ret").to_frame()

# Dividend yield applied on ex-dividend dates
div_yield = (panel["dividend"] / prices).rename("div_yield").to_frame().fillna(0.0)

# Total return approximation (no reinvestment slippage modeled)
ret["div_yield"] = div_yield["div_yield"]
ret["total_ret"] = ret["ret"].fillna(0.0) + ret["div_yield"]

print(ret.dropna().head())

Save to disk

Persist for backtests and to avoid re-downloading.

# Save long-form dividends
div.reset_index().rename(columns={"level_1": "Ticker", 0: "dividend"}).to_csv(
    "dividends_long.csv", index=False
)

# Save price + dividend panel to Parquet for compact storage
panel.to_parquet("panel_dividends.parquet")

Common fields and expectations

  • Dividend value: cash per share on the ex-dividend date.
  • Index (date): ex-dividend date (timezone-naive in UTC by default after conversion).
  • Currency: in the listing currency of the security.
  • Splits: available separately via the Stock Splits column when actions=True.
ComponentSourceNotes
DividendsTicker.dividends or download(..., actions=True)Ex-dividend dates; per-share cash
PricesClose or Adj CloseUse Close when adding dividends; Adj Close already accounts for dividends
Splitsdownload(..., actions=True)Split ratio per date

Pitfalls

  • Ex-dividend vs payment date: Series is keyed by ex-dividend date, not payment date. Payment date may lag by weeks.
  • Adjusted prices: Adj Close includes dividend adjustments. Do not add dividends to Adj Close returns.
  • Currency: Dividends are in the instrument’s currency; converting requires FX data for accurate portfolio aggregation.
  • Delistings and symbol changes: History for delisted tickers may be incomplete; map identifiers carefully.
  • Survivorship bias: Building universes from current constituents can drop historical payers that later delisted or moved indices.
  • Timezones: Convert to timezone-naive UTC for consistent joins; yfinance may return tz-aware indexes in some methods.
  • Sparse events: Many tickers pay quarterly or irregularly; resample or forward-fill with care when aligning to daily bars.

Performance notes

  • Batch downloads: Prefer yf.download with a list of tickers over per-ticker loops.
  • Minimize periods: Request the shortest period/granularity needed (e.g., period="2y" vs "max").
  • Caching: Save results (CSV/Parquet) and only update incrementally in subsequent runs.
  • Parallelism: If you must loop per ticker (e.g., Ticker().dividends), use ThreadPoolExecutor with small pools (e.g., 4–8) to avoid hammering the source.
  • Retry/backoff: Add light retries and backoff to handle transient network hiccups.
  • Memory: When stacking MultiIndex frames for thousands of tickers, process in batches and write to disk incrementally.

Tiny FAQ

  • Q: Are dividends split-adjusted?
    • A: The cash amount is reported per share as of the event; stock splits are separate events.
  • Q: What date am I getting?
    • A: Ex-dividend date per Yahoo Finance.
  • Q: Can I get ETFs and ADRs?
    • A: Yes; behavior and currency follow the listing. Check for withholding or irregular schedules.
  • Q: Why doesn’t my total return match Adj Close returns?
    • A: Adj Close already embeds dividend effects. Use Close+dividends or use Adj Close alone.
  • Q: How do I handle missing events?
    • A: Re-try fetch, cross-check with another source, and log discrepancies for manual review.

Next Article: Generating Real-Time Trading Signals with yfinance and Python

Series: Algorithmic Trading with Python

Python