Back To Top

August 14, 2025

Finding Big Money Options

Score option chains using open interest, OI/volume, and strike distance to highlight active contracts in Python.

Most options data is noise. However, there are a few contracts that can tell a story worth knowing.

If we zero in on where open interest and volume surge together, we can spot which strikes attract serious capital.

We produce a composite score aiming to identify such capital by ranking contracts by size, stickiness, and distance from the current price.

The approach gives us a live heatmap of where big money is actually betting and which contracts pull in the largest flows.

The complete Python notebook for the analysis is provided below.

Big Money Options Google Colab Demo AVIF

1. Finding Where the Big Money Plays

Large, unusual trades set the tone for price action. Institutions show intent not in single trades, but in where size persists and grows over time.

Traditional scanners show volume spikes or unusual activity, but miss the subtle footprints left by accumulation, sticky open interest, or far-out bets.

To cut through the noise, we derive a composite score. This method ranks every contract using three inputs:

  • Open Interest: measures size. Contracts with more open positions signal where the crowd commits.
  • OI/Volume Ratio: measures stickiness. High ratios flag contracts where traders open positions and hold, not just churn for liquidity.
  • Strike Distance (OTM): measures risk appetite. Big money concentrates near-the-money but sometimes places significant OTM bets.

The Scoring Formula

We normalize open interest and OI/volume within each expiry using a z-score:

Finding Big Money Options

Here:

  • OIi is the open interest for contract i
  • (OI/Volume)i​ is the open interest-to-volume ratio for contract i
  • μ and σ are the mean and standard deviation for each expiry date.

We then rank these z-scores on a percentile basis within each expiry.

This keeps contracts with abnormal size or stickiness at the top, regardless of overall market mood.

Strike distance is scaled as:

Finding Big Money Options

K_OTM​ is a scaling factor.

Shorter-dated options are penalized using:

Finding Big Money Options

DTEi​ is days to expiry.

The final composite score for each contract:

Finding Big Money Options

Weights are tuned for practical signal:

  • wOI​=0.4
  • wOV​=0.4
  • wOTM​=0.2

Practical Example

Suppose there is a call option with:

  • High open interest relative to peers
  • OI/volume ratio in the top decile
  • Strike close to spot
  • 30 days to expiry

This contract scores near the top. It reflects big money building a position.

By contrast, a weekly put with low OI and high churn scores low, even if it trades heavy volume.

2. Identifying Big Money Options in Python

2.1 Get the Data and Compute Score

We use yfinance to pull the full option chain, apply liquidity filters, and rank contracts by the composite score.

To make the code adjustable, we state the parameters at the beginning of the workflow.

Step 1: Set Parameters and Pull Data

Each parameter is explained in the code comments below, from liquidity filters to scoring weights.

				
					import pandas as pd
import numpy as np
import yfinance as yf
from datetime import date
from math import erf, log, sqrt
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")

# PARAMETERS
TICKER     = "NVDA"   # Ticker symbol; set to any liquid underlying
TOP_N      = 50       # Number of top contracts to return; higher values include more noise
K_OTM      = 2.0      # Out-of-the-money scaling; higher = more penalty for far strikes
MAX_DTE    = 360      # Maximum days to expiry; lower to focus on short-term flows
MIN_VOLUME = 10       # Minimum daily volume; raises threshold for “active” contracts
MIN_OI     = 100      # Minimum open interest; filters out illiquid/ignored contracts
CAP_OI_VOL = 100      # Cap for OI/Volume ratio; prevents outliers from distorting scores
W_OI_Z     = 0.4      # Weight on open interest z-score; higher = more focus on total size
W_OV_Z     = 0.4      # Weight on OI/volume z-score; higher = more focus on stickiness
W_OTM      = 0.2      # Weight on OTM (strike distance); higher = more penalty for contracts far from spot
				
			

We use NVDA as an example and loop through every listed expiry, for both calls and puts.

We keep only fields needed for scoring: strike, open interest, volume, last price, and IV.

				
					# fetch full chain with IV
tkr   = yf.Ticker(TICKER)
spot  = tkr.history(period="1d")["Close"].iloc[-1]
today = pd.to_datetime(date.today())

rows = []
for exp in tkr.options:
    oc = tkr.option_chain(exp)
    for side, df in (("call", oc.calls), ("put", oc.puts)):
        part = df[[
            "contractSymbol",
            "strike",
            "openInterest",
            "volume",
            "lastPrice",
            "impliedVolatility"
        ]].copy()
        part["side"]  = side
        part["exp"]   = pd.to_datetime(exp)
        part["snap"]  = today
        part["spot"]  = spot
        rows.append(part)
raw = pd.concat(rows, ignore_index=True)
				
			

Step 2: Apply Filters and Compute Score Inputs

We then remove contracts with short expiry, low OI, or low volume.

Each contract gets features for days-to-expiry, OTM weighting, and the OI/Volume ratio.

We then normalize OI and OI/Volume for each expiry using z-scores, then percentile rank within expiry.

The composite score is finally computed.

Prev Post

Future Prices with NIG Distributions

Next Post

Visualizing Reversal Probability Zones

post-bars
Mail Icon

Newsletter

Get Every Weekly Update & Insights

[mc4wp_form id=]

Leave a Comment