DEV Community

Max
Max

Posted on Originally published at orthogonal.info

yfinance 1.6.0: Practical Python Stock Data, Live Streaming, and Equity Screening

I pulled yfinance 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, 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 Worth Knowing About

The most practically useful additions in recent 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 info for an exchange. Together these move yfinance closer to a self-contained data layer for personal projects.

One important caveat the PyPI page spells out: yfinance is an open-source tool using Yahoo's publicly available APIs, not affiliated with or endorsed by Yahoo, and their terms say the API is intended for personal use only. If you are building anything commercial, resolve that before writing a line of code.

pip install yfinance
Enter fullscreen mode Exit fullscreen mode

The default install now includes curl_cffi as a request fallback. If that is a problem in some corporate proxies, older OS images, or constrained containers, the docs cover an alternative install path.

Fetching Historical Data Without Shooting Yourself in the Foot

The Ticker object is the entry point for single-instrument data:

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)
Enter fullscreen mode Exit fullscreen mode

history() returns a pandas DataFrame with Open, High, Low, Close, Volume, Dividends, and Stock Splits columns. The index is a timezone-aware DatetimeIndex — that trips up new users who compare it against naive datetime objects. Normalize your date comparisons or the filtering silently returns wrong results.

One thing I missed longer than I should have: history() auto-adjusts for splits and dividends by default. If you want raw unadjusted prices — say, when cross-referencing a broker's records — pass auto_adjust=False. The default is almost always right for portfolio math, but it matters when you are debugging discrepancies against another source.

For multiple tickers at once, use yf.download():

tickers = ["AAPL", "GOOGL", "BRK-B", "VTI"]
data = yf.download(tickers, period="1y", group_by="ticker")
Enter fullscreen mode Exit fullscreen mode

The result has a MultiIndex column structure. If you only need closing prices, data["Close"] gives a clean DataFrame with one column per ticker — the shape most backtesting libraries expect.

Live Streaming and Where It Actually Helps

The WebSocket class is genuinely new territory. For personal projects that want live quote updates without paying for a proper market data feed, it is a workable starting point:

import yfinance as yf

ws = yf.WebSocket(["AAPL", "MSFT"])
ws.start()

for quote in ws.stream():
    print(quote)
    if some_condition:
        break

ws.stop()
Enter fullscreen mode Exit fullscreen mode

Practical notes: the stream reflects Yahoo's quote-feed latency and hours. During pre/post-market the gaps between ticks can be longer than in regular session — do not bake hard latency assumptions into logic that processes this stream. Also test reconnection behavior before depending on it; a dropped connection mid-session should resume gracefully, but verify that on your network first.

The AsyncWebSocket variant is better if you are integrating into an async app — alongside FastAPI, an async queue, or asyncio orchestration it avoids threading headaches.

Screening Equities with EquityQuery

The EquityQuery + Screener combo is the most underused feature I see people miss. Instead of downloading a universe and filtering in pandas, 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])
Enter fullscreen mode Exit fullscreen mode

The API mirrors Yahoo's internal screener query structure. Some fields behave differently than their names suggest — test on a small query first and validate the output shape before building business logic on top.

For backtesting infrastructure I run a weekly screener pull into a local SQLite database, then do all historical analysis offline. That keeps you out of rate-limit territory and gives reproducible inputs for strategy tests.

What It Cannot Do

yfinance does not give you tick data, Level 2 order-book depth, or historical intraday beyond what Yahoo's API exposes. For most personal finance projects and simple backtests, that is fine. Anything requiring precise intraday execution modeling needs a real market data vendor.

Rate limiting is worth understanding too. Yahoo publishes no official limits, and observed behavior varies with region, time of day, and residential vs cloud IP. If you fetch in bulk — five years of daily history for a thousand symbols — add delays and handle the occasional 429 or empty response gracefully:

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
Enter fullscreen mode Exit fullscreen mode

A Practical Starting Project

If you want a concrete thing to build rather than 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 to CSV, and optionally pushes a summary to a bot or local dashboard.

That forces you to handle the MultiIndex DataFrame, deal with corporate actions (splits and dividends) correctly, manage missing trading days across different exchanges, and think about where you store the output. Those four problems cover most of what you hit in more complex work.

yfinance 1.6.0 is a capable free data layer for personal finance work. It has real limits — not a production feed, personal-use terms — but within those limits it has grown into something genuinely useful. The screening API and live streaming components in particular are worth building time into if you have only ever used the historical-data path.

What are you pulling market data with these days — yfinance, a paid vendor, or something you rolled yourself?

Top comments (0)