If you’re diving into financial data analysis with Python, chances are you’ve come across yfinance. This handy library lets you tap into Yahoo Finance data with just a few lines of code. In this post, we’ll explore how to extract options chain data for a stock, then save it cleanly to CSV files — one for calls, one for puts.
Whether you're analyzing volatility, building trading strategies, or just curious, having structured access to options data is gold. So let’s jump into the code!
🔧 Prerequisites
You'll need the yfinance library, which you can install with:
pip install yfinance
We're also using Python’s built-in csv and datetime modules — no extra dependencies there.
📦 The Goal
We’ll write a function that:
- Accepts a stock ticker and expiration date,
- Retrieves the options chain for that date (calls & puts),
- Formats the data neatly,
- Writes the results to two CSV files:
<symbol>_calls.csvand<symbol>_puts.csv.
🧠 The Code
import yfinance as yf
import csv
from datetime import datetime
def fetch_and_save_options(symbol, expiration_date):
stock = yf.Ticker(symbol)
if expiration_date not in stock.options:
print(f"Invalid expiration date. Available options dates: {stock.options}")
return
options = stock.option_chain(expiration_date)
calls_data = []
puts_data = []
for call in options.calls.itertuples():
call_data = {
"Contract Name": call.contractSymbol,
"Last Trade Date (EDT)": call.lastTradeDate.strftime("%m/%d/%Y %I:%M %p") if call.lastTradeDate else "",
"Strike": call.strike,
"Last Price": call.lastPrice,
"Bid": call.bid,
"Ask": call.ask,
"Change": call.change,
"% Change": call.percentChange,
"Volume": call.volume if call.volume is not None else "-",
"Open Interest": call.openInterest if call.openInterest is not None else "-",
"Implied Volatility": f"{call.impliedVolatility * 100:.2f}%" if call.impliedVolatility else "-"
}
calls_data.append(call_data)
for put in options.puts.itertuples():
put_data = {
"Contract Name": put.contractSymbol,
"Last Trade Date (EDT)": put.lastTradeDate.strftime("%m/%d/%Y %I:%M %p") if put.lastTradeDate else "",
"Strike": put.strike,
"Last Price": put.lastPrice,
"Bid": put.bid,
"Ask": put.ask,
"Change": put.change,
"% Change": put.percentChange,
"Volume": put.volume if put.volume is not None else "-",
"Open Interest": put.openInterest if put.openInterest is not None else "-",
"Implied Volatility": f"{put.impliedVolatility * 100:.2f}%" if put.impliedVolatility else "-"
}
puts_data.append(put_data)
with open(f"{symbol}_calls.csv", mode="w", newline="") as file:
writer = csv.DictWriter(file, fieldnames=calls_data[0].keys())
writer.writeheader()
writer.writerows(calls_data)
with open(f"{symbol}_puts.csv", mode="w", newline="") as file:
writer = csv.DictWriter(file, fieldnames=puts_data[0].keys())
writer.writeheader()
writer.writerows(puts_data)
print(f"Options data for {symbol} on {expiration_date} saved to CSV files.")
▶️ Example Usage
fetch_and_save_options("LLY", "2025-06-06")
This will create:
-
LLY_calls.csv– with detailed call options data -
LLY_puts.csv– with detailed put options data
Each row contains:
- Contract symbol
- Last trade timestamp
- Strike price
- Bid/ask prices
- Volume, open interest
- Implied volatility
- And more!
⚠️ Notes & Tips
- Be sure the expiration date is in
YYYY-MM-DDformat and is valid for the symbol. Usestock.optionsto list available dates. - The output uses U.S. Eastern Time for last trade timestamps.
- Missing data (like
volumeorimplied volatility) is replaced with"-"for cleaner output.
💡 Use Cases
- Options backtesting — pair this with historical data.
- Volatility screening — sort by IV or OI for trade ideas.
- Automated reporting — schedule daily runs via cron or Airflow.
🧵 Wrapping Up
With just a few lines of Python, you can gain powerful access to real-time options data using yfinance. This script is a solid starting point for financial data exploration, quantitative research, or even building your own trading dashboard.
Top comments (1)
thank you so much for this code, which will be tremendously helpful. I am getting an error message, though:
def fetch_and_save_options (LLY, 2025-12-19)
SyntaxError: invalid syntax
Process finished with exit code 1
with a cursor under the first 2 in 2025. I removed the quotes from LLY so that there is no longer an error on "LLY". Is there a package or configuration I am missing, that would fix this error? tyia