I pulled yfinance Python stock data for the first time in 2021, back when the library was still fighting Yahoo’s API changes every few months. In 2026, yfinance 1.6.0 landed on PyPI on August 13th, and the gap between what it could do then and what it can do now is significant enough to revisit. This is not a documentation mirror. These are notes from working with it on a personal portfolio tracker and a couple of backtesting scripts.
What Changed in Recent Versions Worth Knowing About
The most practically useful additions in recent yfinance releases are the live data components and the screening API. The WebSocket and AsyncWebSocket classes now expose real-time quote streaming. The Screener and EquityQuery objects let you build structured queries to filter equities without leaving Python. The Market class gives you status and session information for a given exchange. These additions move yfinance closer to being a self-contained data layer for personal projects.
One important caveat that the PyPI page spells out clearly: Yahoo!, Y!Finance, and Yahoo! finance are registered trademarks of Yahoo, Inc. yfinance is an open-source tool using Yahoo’s publicly available APIs and is not affiliated with or endorsed by Yahoo. Their terms of use explicitly say the API is intended for personal use only. If you are building anything commercial, that is your problem to resolve before writing a single line of code.
Install is straightforward:
pip install yfinance
The default install now includes curl_cffi as a fallback for requests. If you are in an environment where that is a problem — some corporate proxies, older OS images, or constrained containers — the documentation at ranaroussi.github.io/yfinance covers an alternative install path.
Fetching Historical Data Without Shooting Yourself in the Foot
The Ticker object is the entry point for single-instrument data. Most people start here and never need anything else.
import yfinance as yf
msft = yf.Ticker("MSFT")
# Last 3 months of daily data
hist = msft.history(period="3mo")
print(hist.tail())
# Specific date range
hist2 = msft.history(start="2026-01-01", end="2026-08-01")
print(hist2.shape)
The history() call returns a pandas DataFrame with Open, High, Low, Close, Volume, Dividends, and Stock Splits columns. The index is a timezone-aware DatetimeIndex. That last part trips up new users who try to compare it against naive datetime objects. Always normalize your date comparisons or the filtering will silently return wrong results.
One thing I missed for longer than I should have: history() auto-adjusts for splits and dividends by default. If you want raw unadjusted prices — for example, when you are cross-referencing a specific broker’s records — pass auto_adjust=False. The default is almost always what you want for portfolio math, but it matters when you are debugging discrepancies with another data source.
For fetching multiple tickers at once, use yf.download():
tickers = ["AAPL", "GOOGL", "BRK-B", "VTI"]
data = yf.download(tickers, period="1y", group_by="ticker")
The resulting DataFrame has a MultiIndex column structure. If you only need closing prices, data["Close"] gives you a clean DataFrame with one column per ticker. That is the shape most backtesting libraries expect.
Live Streaming and Where It Actually Helps
The WebSocket class is genuinely new territory for yfinance. For personal projects that want live quote updates without paying for a proper market data feed, it is a workable starting point. Here is a minimal example:
import yfinance as yf
ws = yf.WebSocket(["AAPL", "MSFT"])
ws.start()
# Access streaming quotes
for quote in ws.stream():
print(quote)
if some_condition:
break
ws.stop()
A few practical notes from using this: the streaming data reflects Yahoo’s quote feed latency and hours. During pre-market and post-market, the data you receive may have longer gaps between ticks than during regular session. Do not build hard latency assumptions into logic that processes this stream. Also test the reconnection behavior before depending on it — a dropped connection during the middle of a session should gracefully resume, but verify that on your network before assuming it.
The AsyncWebSocket version is more suitable if you are integrating this into an async application. If you are running alongside FastAPI, an async queue, or asyncio-based orchestration, the async variant avoids threading headaches.
Screening Equities with EquityQuery
The EquityQuery and Screener combination is the most underused feature I have seen people miss. Instead of downloading a universe and filtering in pandas, you can push the filter criteria upstream:
from yfinance import EquityQuery, Screener
# Stocks with market cap over $10B in technology sector
q = EquityQuery("and", [
EquityQuery("gt", ["marketcap", 10_000_000_000]),
EquityQuery("eq", ["sector", "Technology"])
])
screener = Screener()
results = screener.set_predefined_body(q).fetch()
print(results["quotes"][:5])
The API mirrors the query structure Yahoo’s screener uses internally. The available fields and their exact names are documented at the yfinance docs site. Some fields behave differently than their names suggest — test on a small query first and validate the shape of the output before building business logic on top of it.
For backtesting infrastructure, I have found it useful to run a weekly screener pull into a local SQLite database, then do all the historical analysis offline. That pattern keeps you out of rate-limit territory and gives you reproducible inputs for your strategy tests. If you are keeping local databases and want to understand the storage hardware decisions that support that kind of setup, the post on NVMe SSDs for Docker and development workloads covers storage endurance and capacity considerations that apply equally well here.
What the Library Cannot Do and What to Reach for Instead
yfinance does not give you tick data, Level 2 order book depth, or historical intraday data beyond what Yahoo’s API exposes. For most personal finance projects and simple backtests, that is fine. If you are doing anything that requires precise intraday execution modeling, you need a real market data vendor.
The rate-limiting situation is also worth understanding. Yahoo does not publish official rate limits, and the community’s observed behavior varies with region, time of day, and whether you are using a residential or cloud IP. If you are fetching data in bulk — downloading five years of daily history for a thousand symbols — add delays between calls and handle the occasional 429 or empty response gracefully. A simple retry with exponential backoff covers most cases:
import time
import yfinance as yf
def fetch_with_retry(ticker, retries=3, delay=2):
for attempt in range(retries):
try:
t = yf.Ticker(ticker)
data = t.history(period="1y")
if not data.empty:
return data
except Exception as e:
print(f"Attempt {attempt+1} failed: {e}")
time.sleep(delay * (2 ** attempt))
return None
For a homelab or self-hosted setup where you want to run these scripts on a schedule, having a proper server matters more than the script itself. The homelab hardware guide covers what to look for if you are building out a machine that runs financial data pipelines alongside other services.
Books are still the most efficient way to build up the conceptual foundation. The Amazon searches below are a useful starting point for the adjacent topics — Python finance programming, algorithmic trading implementations, and the hardware side of running your own infrastructure. These are affiliate links, which means I may earn a commission from qualifying purchases at no extra cost to you.
- Python finance programming books on Amazon — good for foundational pandas, NumPy, and portfolio math before touching live data
- Algorithmic trading with Python books on Amazon — strategy backtesting, risk modeling, and execution concepts
- Raspberry Pi 5 on Amazon — low-power always-on board suitable for running scheduled market data pulls and small portfolio trackers
- Portable 2TB SSDs on Amazon — if you are archiving years of market data locally, a fast portable SSD is a practical secondary store
A Practical Starting Project
If you want a concrete thing to build with yfinance rather than just experimenting in a notebook, try a weekly portfolio snapshot script. Once a week, it downloads the last 52 weeks of price history for every position you hold, computes each position’s percentage return against the index of your choice, writes the output to a CSV, and optionally pushes a summary to a Telegram bot or local dashboard.
That project forces you to handle the MultiIndex DataFrame structure, deal with corporate actions (splits and dividends) correctly, manage missing trading days across different exchanges, and think about where and how you store the output. Those four problems cover most of what you will encounter in more complex work.
yfinance 1.6.0 is a capable free data layer for personal finance work. It has real limits — it is not a production market data feed, and Yahoo’s terms are personal-use only — but within those limits, the library has grown into something genuinely useful. The screening API and live streaming components in particular are worth building time into if you have been using only the historical data path.
For more notes on Python tools, financial data workflows, and market research signals, subscribe to Alpha Signal on Telegram.
📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.
Leave a Reply