---
title: "Equity Options"
description: "Some of the Equity Options data you can get include prices, open interest, Greeks, and universe selection data."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/asset-classes/equity-options
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/historical-data/asset-classes/equity-options.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/20%20Historical%20Data/04%20Asset%20Classes/02%20Equity%20Options
modified: 2026-10-30
index: https://www.quantconnect.com/llms.txt
---

# Equity Options

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Historical Data > Asset Classes > Equity Options

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

This page explains how to get historical data for Equity Options. Some of the data you can get include prices, open interest, Greeks, and universe selection data.

## Trades

To get historical [trade data](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/handling-data.md#02-Trades), call the `history` method with the `TradeBar` type and a security's `Symbol`. This method returns a DataFrame with columns for the open, high, low, close, and volume.

```python
class EquityOptionTradeBarHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        equity = self.add_equity('SPY', data_normalization_mode=DataNormalizationMode.RAW)
        symbol = sorted(self.option_chain(equity.symbol), key=lambda c: c.open_interest)[-1].symbol
        # Get the 5 trailing daily TradeBar objects of the security in DataFrame format.
        history = self.history(TradeBar, symbol, 5, Resolution.DAILY)
```

| expiry | strike | type | symbol | time | close | high | low | open | volume |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-12 16:00:00 | 0.20 | 0.23 | 0.20 | 0.21 | 99.0 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-13 16:00:00 | 0.20 | 0.21 | 0.17 | 0.18 | 543.0 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-16 16:00:00 | 0.18 | 0.19 | 0.17 | 0.17 | 58.0 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-17 16:00:00 | 0.24 | 0.24 | 0.19 | 0.19 | 101.0 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 16:00:00 | 0.85 | 0.85 | 0.21 | 0.21 | 160.0 |

```python
# Calculate the daily returns.
daily_returns = history.close.pct_change().iloc[1:]
```

```python
expiry      strike  type  symbol                              time
2025-01-17  440.0   1     SPY 32OCGBPPW6DTY|SPY R735QTJ8XC9X  2024-12-13 16:00:00    0.000000
                                                              2024-12-16 16:00:00   -0.100000
                                                              2024-12-17 16:00:00    0.333333
                                                              2024-12-18 16:00:00    2.541667
Name: close, dtype: float64
```

If you intend to use the data in the DataFrame to create `TradeBar` objects, request that the history request returns the data type you need. Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame. To get a list of `TradeBar` objects instead of a DataFrame, call the `history[TradeBar]` method.

```python
# Get the 5 trailing daily TradeBar objects of the security in TradeBar format.
history = self.history[TradeBar](symbol, 5, Resolution.DAILY)
# Iterate through the TradeBar objects and access their volumes.
for trade_bar in history:
    t = trade_bar.end_time
    volume = trade_bar.volume
```

Request minute, hour, or daily resolution data. Otherwise, the history request won't return any data.

## Quotes

To get historical [quote data](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/handling-data.md#03-Quotes), call the `history` method with the `QuoteBar` type and a security's `Symbol`. This method returns a DataFrame with columns for the open, high, low, close, and size of the bid and ask quotes. The columns that don't start with "bid" or "ask" are the mean of the quote prices on both sides of the market.

```python
class EquityOptionsQuoteBarHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        equity = self.add_equity('SPY', data_normalization_mode=DataNormalizationMode.RAW)
        symbol = sorted(self.option_chain(equity.symbol), key=lambda c: c.open_interest)[-1].symbol
        # Get the 5 trailing minute QuoteBar objects of the security in DataFrame format.
        history = self.history(QuoteBar, symbol, 5, Resolution.MINUTE)
```

| expiry | strike | type | symbol | time | askclose | askhigh | asklow | askopen | asksize | bidclose | bidhigh | bidlow | bidopen | bidsize | close | high | low | open |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 15:56:00 | 0.76 | 0.85 | 0.71 | 0.75 | 72.0 | 0.74 | 0.74 | 0.17 | 0.60 | 72.0 | 0.75 | 0.795 | 0.440 | 0.675 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 15:57:00 | 0.79 | 0.80 | 0.76 | 0.76 | 143.0 | 0.77 | 0.78 | 0.73 | 0.74 | 60.0 | 0.78 | 0.790 | 0.745 | 0.750 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 15:58:00 | 0.80 | 0.80 | 0.78 | 0.79 | 169.0 | 0.78 | 0.78 | 0.75 | 0.77 | 60.0 | 0.79 | 0.790 | 0.765 | 0.780 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 15:59:00 | 0.82 | 0.83 | 0.79 | 0.80 | 72.0 | 0.80 | 0.80 | 0.76 | 0.78 | 72.0 | 0.81 | 0.815 | 0.775 | 0.790 |
| 2025-01-17 | 440.0 | 1 | SPY 32OCGBPPW6DTY\|SPY R735QTJ8XC9X | 2024-12-18 16:00:00 | 0.91 | 0.91 | 0.82 | 0.82 | 346.0 | 0.87 | 0.89 | 0.80 | 0.80 | 72.0 | 0.89 | 0.900 | 0.810 | 0.810 |

```python
# Calculate the spread at each minute.
spread = history.askclose - history.bidclose
```

```python
expiry      strike  type  symbol                              time
2025-01-17  440.0   1     SPY 32OCGBPPW6DTY|SPY R735QTJ8XC9X  2024-12-18 15:56:00    0.02
                                                              2024-12-18 15:57:00    0.02
                                                              2024-12-18 15:58:00    0.02
                                                              2024-12-18 15:59:00    0.02
                                                              2024-12-18 16:00:00    0.04
dtype: float64
```

If you intend to use the data in the DataFrame to create `QuoteBar` objects, request that the history request returns the data type you need. Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame. To get a list of `QuoteBar` objects instead of a DataFrame, call the `history[QuoteBar]` method.

```python
# Get the 5 trailing minute QuoteBar objects of the security in QuoteBar format.
history = self.history[QuoteBar](symbol, 5, Resolution.MINUTE)
# Iterate through each QuoteBar and calculate the dollar volume on the bid.
for quote_bar in history:
    t = quote_bar.end_time
    bid_dollar_volume = quote_bar.last_bid_size * quote_bar.bid.close
```

Request minute, hour, or daily resolution data. Otherwise, the history request won't return any data.

## Slices

To get historical [Slice](https://www.quantconnect.com/docs/v2/writing-algorithms/key-concepts/time-modeling/timeslices.md) data, call the `history` method without passing any `Symbol` objects. This method returns `Slice` objects, which contain data points from all the datasets in your algorithm. If you omit the `resolution` argument, it uses the resolution that you set for each security and dataset when you created the subscriptions.

```python
class SliceHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 1)
        self.set_end_date(2024, 12, 31)
        # Add some securities and datasets.
        equity = self.add_equity('SPY', data_normalization_mode=DataNormalizationMode.RAW)
        contract = sorted(self.option_chain(equity.symbol), key=lambda c: c.open_interest)[-1]
        self.add_option_contract(contract.symbol)
        # Get the historical Slice objects over the last 5 days for all the subcriptions in your algorithm.
        history = self.history(5, Resolution.DAILY)
        # Iterate through each historical Slice.
        for slice_ in history:
            # Iterate through each TradeBar in this Slice.
            for symbol, trade_bar in slice_.bars.items():
                close = trade_bar.close
```

## Open Interest

To get historical [open interest data](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/handling-data.md#05-Option-Contracts), call the `history` method with the `OpenInterest` type and a security's `Symbol`. This method returns a DataFrame with a single column.

```python
class EquityOptionOpenInterestHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of a security.
        equity = self.add_equity('SPY', data_normalization_mode=DataNormalizationMode.RAW)
        symbol = sorted(self.option_chain(equity.symbol), key=lambda c: c.open_interest)[-1].symbol
        # Get the 5 trailing daily OpenInterest objects of the security in DataFrame format.
        history = self.history(OpenInterest, symbol, 5, Resolution.DAILY)
```

| expiry | strike | type | symbol | time | openinterest |
| --- | --- | --- | --- | --- | --- |
| 2025-01-17 | 440.0 | 1 | SPY 250117P00440000 | 2024-12-13 | 171751.0 |
| 2025-01-17 | 440.0 | 1 | SPY 250117P00440000 | 2024-12-16 | 172190.0 |
| 2025-01-17 | 440.0 | 1 | SPY 250117P00440000 | 2024-12-17 | 172157.0 |
| 2025-01-17 | 440.0 | 1 | SPY 250117P00440000 | 2024-12-18 | 172147.0 |
| 2025-01-17 | 440.0 | 1 | SPY 250117P00440000 | 2024-12-19 | 172099.0 |

```python
# Calculate the daily change in open interest.
oi_delta = history.openinterest.diff().iloc[1:]
```

```python
expiry      strike  type  symbol                 time
2025-01-17  440.0   1     SPY   250117P00440000  2024-12-16    439.0
                                                 2024-12-17    -33.0
                                                 2024-12-18    -10.0
                                                 2024-12-19    -48.0
Name: openinterest, dtype: float64
```

If you intend to use the data in the DataFrame to create `OpenInterest` objects, request that the history request returns the data type you need. Otherwise, LEAN consumes unnecessary computational resources populating the DataFrame. To get a list of `OpenInterest` objects instead of a DataFrame, call the `history[OpenInterest]` method.

```python
# Get the 5 trailing daily OpenInterest objects of the security in OpenInterest format.
history = self.history[OpenInterest](symbol, 5, Resolution.DAILY)
# Iterate through the TradeBar objects and access their volumes.
for oi in history:
    t = oi.end_time
    open_interest = oi.value
```

## Daily Option Chains

To get historical [daily Option chain data](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/equity-options.md#08-Navigate-Daily-Option-Chains), call the `history` method with the Option `Symbol` object. The data this method returns contains information on all the currently tradable contracts, not just the contracts that pass your filter. If you pass `flatten=True`, this method returns a DataFrame with columns for the data point attributes.

```python
class EquityOptionDailyOptionChainHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 23)
        self.set_end_date(2024, 12, 31)
        # Add an Equity Option universe.
        option = self.add_option('SPY')
        # Get the trailing 5 daily Option chains in DataFrame format.
        history = self.history(option.symbol, 5, flatten=True)
```

| time | symbol | close | delta | gamma | high | impliedvolatility | low | open | openinterest | rho | theta | underlying | value | vega | volume |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 2024-12-13 | SPY YOGVNNCO8QDI\|SPY R735QTJ8XC9X | 484.815 | 1.000000 | 0.000000 | 487.945 | 3.212331 | 484.225 | 486.74 | 1539.0 | 0.000000 | 0.000000 | SPY: ¤604.33 | 484.815 | 0.000000 | 0.0 |
| 2024-12-13 | SPY YOGVNNCU72FA\|SPY R735QTJ8XC9X | 474.210 | 1.000000 | 0.000000 | 477.970 | 3.055466 | 474.210 | 476.91 | 26.0 | 0.000000 | 0.000000 | SPY: ¤604.33 | 474.210 | 0.000000 | 0.0 |
| 2024-12-13 | SPY YOGVNND05EH2\|SPY R735QTJ8XC9X | 464.835 | 1.000000 | 0.000000 | 467.965 | 2.910873 | 464.230 | 466.91 | 4.0 | 0.000000 | 0.000000 | SPY: ¤604.33 | 464.835 | 0.000000 | 0.0 |
| 2024-12-13 | SPY YOGVNND63QIU\|SPY R735QTJ8XC9X | 454.845 | 1.000000 | 0.000000 | 458.000 | 2.775398 | 454.245 | 456.92 | 18.0 | 0.000000 | 0.000000 | SPY: ¤604.33 | 454.845 | 0.000000 | 0.0 |
| 2024-12-13 | SPY YTG30NXW11QE\|SPY R735QTJ8XC9X | 456.345 | 1.000000 | 0.000000 | 459.235 | 0.687831 | 456.270 | 458.77 | 33.0 | 0.000000 | 0.000000 | SPY: ¤604.33 | 456.345 | 0.000000 | 0.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2024-12-19 | SPY 33899RRUZK23Q\|SPY R735QTJ8XC9X | 314.995 | -0.865013 | 0.000496 | 317.045 | 0.145628 | 293.900 | 297.42 | 1.0 | -5.866155 | 0.038392 | SPY: ¤586.28 | 314.995 | 0.573632 | 0.0 |
| 2024-12-19 | SPY 337HP99QFUJJA\|SPY R735QTJ8XC9X | 319.995 | -0.874953 | 0.000412 | 321.765 | 0.142599 | 299.020 | 302.42 | 0.0 | -5.754009 | 0.039155 | SPY: ¤586.28 | 319.995 | 0.452253 | 0.0 |
| 2024-12-19 | SPY 33899RVZ5ZO12\|SPY R735QTJ8XC9X | 319.990 | -0.868866 | 0.000447 | 321.805 | 0.143224 | 298.995 | 302.47 | 0.0 | -5.954058 | 0.039088 | SPY: ¤586.28 | 319.990 | 0.511173 | 0.0 |
| 2024-12-19 | SPY 337HP95ZTK8HY\|SPY R735QTJ8XC9X | 324.995 | -0.876073 | 0.000389 | 326.715 | 0.142820 | 304.030 | 307.43 | 0.0 | -5.842472 | 0.040096 | SPY: ¤586.28 | 324.995 | 0.428058 | 0.0 |
| 2024-12-19 | SPY 33899RS8JPCZQ\|SPY R735QTJ8XC9X | 324.995 | -0.868426 | 0.000446 | 326.745 | 0.145502 | 303.975 | 307.46 | 1.0 | -6.048355 | 0.039695 | SPY: ¤586.28 | 324.995 | 0.517696 | 0.0 |

```python
# Select the 2 contracts with the greatest volume each day.
most_traded = history.groupby('time').apply(lambda x: x.nlargest(2, 'volume')).reset_index(level=1, drop=True).volume
```

```python
time        symbol
2024-12-13  SPY 32NDZOIHRHLRA|SPY R735QTJ8XC9X    166689.0
            SPY 32NDZOIHXFXT2|SPY R735QTJ8XC9X    160265.0
2024-12-14  SPY YOCXVCLWHPT2|SPY R735QTJ8XC9X     137597.0
            SPY YOCXVCM2G1UU|SPY R735QTJ8XC9X     100401.0
2024-12-17  SPY 32NHXGVYLQYG6|SPY R735QTJ8XC9X    104700.0
            SPY YODXBFZKFH46|SPY R735QTJ8XC9X     103635.0
2024-12-18  SPY 32NIWWZBFX1IE|SPY R735QTJ8XC9X    106804.0
            SPY YOEWRJCELK6E|SPY R735QTJ8XC9X      75769.0
2024-12-19  SPY 32NKVT60AHJDY|SPY R735QTJ8XC9X    109298.0
            SPY YOFW7MPKOBC6|SPY R735QTJ8XC9X      94823.0
Name: volume, dtype: float64
```

To get the data in the format of `OptionUniverse` objects instead of a DataFrame, call the `history[OptionUniverse]` method.

```python
# Get the historical OptionUniverse data over the last 30 days.
history = self.history[OptionUniverse](option.symbol, timedelta(30))
# Iterate through each daily Option chain.
for option_universe in history:
    t = option_universe.end_time
    # Select the contract with the most volume.
    most_traded = sorted(option_universe, key=lambda contract: contract.volume)[-1]
```

## Indicators

To get historical [indicator](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/key-concepts.md) values, call the `indicator_history` method with an indicator and the security's `Symbol`.

```python
class EquityOptionIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of the Option contract.
        underlying = self.add_equity('SPY').symbol
        symbol = sorted(self.option_chain(underlying), key=lambda c: c.open_interest)[-1].symbol
        # Get the 21-day SMA values of the contract for the last 5 trading days.
        history = self.indicator_history(SimpleMovingAverage(21), symbol, 5, Resolution.DAILY)
```

To organize the data into a DataFrame, use the `data_frame` property of the result.

```python
# Organize the historical indicator data into a DataFrame to enable pandas wrangling.
history_df = history.data_frame
```

|  | current | rollingsum |
| --- | --- | --- |
| 2024-12-12 16:00:00 | 0.377619 | 7.930 |
| 2024-12-13 16:00:00 | 0.366190 | 7.690 |
| 2024-12-16 16:00:00 | 0.353810 | 7.430 |
| 2024-12-17 16:00:00 | 0.336667 | 7.070 |
| 2024-12-18 16:00:00 | 0.356429 | 7.485 |

```python
# Get the maximum of the SMA values.
sma_max = history_df.current.max()
```

The `indicator_history` method resets your indicator, makes a history request, and updates the indicator with the historical data. Just like with regular history requests, the `indicator_history` method supports time periods based on a trailing number of bars, a trailing period of time, or a defined period of time. If you don't provide a `resolution` argument, it defaults to match the resolution of the security subscription.

To make the `indicator_history` method update the indicator with an [alternative price field](https://www.quantconnect.com/docs/v2/writing-algorithms/indicators/automatic-indicators.md#07-Alternative-Price-Fields) instead of the close (or mid-price) of each bar, pass a `selector` argument.

```python
# Get the historical values of an indicator over the last 30 days, applying the indicator to the security's volume.
history = self.indicator_history(indicator, symbol, timedelta(30), selector=Field.VOLUME)
```

Some indicators require the prices of multiple securities to compute their value (for example, the [indicators for the Greeks and implied volatility](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/equity-options/greeks-and-implied-volatility/indicators.md)). In this case, pass a list of the `Symbol` objects to the method.

```python
class EquityOptionMultiAssetIndicatorHistoryAlgorithm(QCAlgorithm):

    def initialize(self) -> None:
        self.set_start_date(2024, 12, 19)
        self.set_end_date(2024, 12, 31)
        # Get the Symbol of the underlying asset.
        underlying = self.add_equity('SPY').symbol
        # Get the Option contract Symbol.
        option = sorted(self.option_chain(underlying), key=lambda c: c.open_interest)[-1].symbol
        # Get the Symbol of the mirror contract.
        mirror = Symbol.create_option(
            underlying, option.id.market, option.id.option_style,
            OptionRight.CALL if option.id.option_right == OptionRight.PUT else OptionRight.PUT,
            option.id.strike_price, option.id.date
        )
        # Create the indicator.
        indicator = ImpliedVolatility(
            option, self.risk_free_interest_rate_model, DividendYieldProvider(underlying),
            mirror, OptionPricingModelType.FORWARD_TREE
        )
        # Get the historical values of the indicator over the last 60 trading minutes.
        history = self.indicator_history(indicator, [underlying, option, mirror], 60, Resolution.MINUTE)
        # Get the average IV value.
        iv_avg = history.data_frame.current.mean()
```

## Examples

The following examples demonstrate some common practices for trading using historical requests.

### Example 1: Trend Following on 0DTE Option Contract

This algorithm strategically trades 0DTE SPY options by analyzing bid and ask volumes shortly after the market opens. Using scheduled events, it effectively executes trades based on historical quote data, optimizing decision-making. The algorithm aims for timely entries and exits, ensuring efficient capital management and quick adaptability in volatile markets.

```python
class ZeroDTEOptionsTradingAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 12, 1)
        self.set_end_date(2024, 12, 10)  # Limit to a single day for 0DTE
        self.set_cash(100000)  # Starting cash

        # Request SPY option data for trading and signal generation.
        option = self.add_option("SPY")
        # We are interested in ATM 0DTE options since they are the most popular.
        option.set_filter(lambda u: u.expiration(0, 0).strikes(-3, 3))
        self._option = option.symbol

        # Schedule event to enter and exit option contract position.
        self.schedule.on(self.date_rules.every_day(self._option), self.time_rules.after_market_open(self._option, 16), self.trade_option)
        self.schedule.on(self.date_rules.every_day(self._option), self.time_rules.before_market_close(self._option, 15), self.liquidate)

    def trade_option(self) -> None:
        # Get the option chain for SPY to trade.
        option_chain = self.current_slice.option_chains.get(self._option, None)
        if option_chain:
            for option in option_chain:
                # Request historical quote data for signal generation.
                history = self.history(QuoteBar, option.symbol, 15, Resolution.MINUTE)
                if not history.empty:
                    # Calculate total bid and ask dollar volume to determine the capital directional force.
                    total_bid_volume = (history['bidclose'] * history['bidsize']).sum()
                    total_ask_volume = (history['askclose'] * history['asksize']).sum()

                    # Follow the capital flow to trade.
                    if total_bid_volume > total_ask_volume:
                        self.market_order(option.symbol, 1)
                    else:
                        self.market_order(option.symbol, -1)
```
