# Unusual Options Activity Scanner — Stock Options Flow (`0xgollum/unusual-options-activity`) Actor

Scan any stock tickers and surface unusual options activity — contracts trading on abnormal volume versus open interest, big-premium prints, and net call/put sentiment. Turns raw option chains into a smart-money flow signal.

- **URL**: https://apify.com/0xgollum/unusual-options-activity.md
- **Developed by:** [0xGollum](https://apify.com/0xgollum) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 17 total users, 7 monthly users, 48.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Unusual Options Activity Scanner 📈

### Changelog

- **2026-07-29** — Reliability fix: runs launched via API/integrations with unset optional fields sent as `null` could fail outright instead of using the documented defaults. Fixed, covered by tests.

**Give it a list of tickers and get the option contracts that are actually being traded today on abnormal volume — the fresh, big-money positioning that raw option chains bury.**

### What "unusual" means here

An option chain is thousands of rows. Almost all of it is noise. What matters is the handful of contracts where **today's volume is far bigger than the open interest that was already there** — that means new positions are being opened *right now*, not old ones being closed. Layer on the dollar premium behind the trade, and you get the same signal the "unusual options activity" services sell: where the smart money is quietly building.

This actor turns a raw chain into that signal. For each ticker it pulls the full chain, then keeps only the contracts that clear **three gates at once**:

1. **Liquidity** — traded at least `min_volume` contracts today.
2. **Fresh positioning** — today's volume is at least `min_vol_oi_ratio`× the standing open interest (contracts with no prior open interest qualify on volume alone).
3. **Real money** — estimated premium traded (volume × price × 100) is at least `min_premium_usd`.

### What you get

Two kinds of rows in one dataset:

**`contract` rows** — each unusual contract found:

| Field | Description |
|-------|-------------|
| **ticker** | Underlying symbol |
| **option\_type** | `call` or `put` |
| **strike / expiry** | Contract strike and expiration date |
| **spot** | Underlying price at scan time |
| **moneyness** | ITM / ATM / OTM relative to spot |
| **volume** | Contracts traded today |
| **open\_interest** | Contracts outstanding before today |
| **vol\_oi\_ratio** | Volume ÷ open interest (how fresh the positioning is) |
| **last\_price** | Last traded contract price |
| **premium\_usd** | Estimated dollar premium traded (volume × price × 100) |
| **implied\_volatility** | IV for the contract, when priced |
| **unusual\_score** | Sortable blend of ratio and premium — biggest signals on top |

**`sentiment` rows** — one summary per ticker: net **call vs put premium** across its unusual contracts, labelled **BULLISH**, **BEARISH** or **MIXED**. This is the headline read — is the unusual flow leaning up or down?

Rows are sorted with the strongest `unusual_score` first, and the per-ticker sentiment summaries are always included.

**Nothing unusual = never billed.** You only pay for runs that actually return signals.

### Source & why it's deliberately slow

Data comes from **CBOE's public delayed-quote feed** — one login-free request per ticker returns the full chain with volume, open interest, implied volatility and Greeks. Because the data is end-of-session delayed, **the scanner works 24/7**, not only during US market hours.

This actor scrapes **slowly on purpose**: it spaces every request and backs off politely if the source pushes back, so it stays reliable on large watchlists rather than fast and brittle. A scan of a handful of tickers takes a few seconds; a big watchlist takes proportionally longer. That is by design — reliability over speed.

### Use cases

- **Smart-money tracking** — see which strikes and expiries are getting unusual fresh flow.
- **Sentiment at a glance** — the per-ticker BULLISH/BEARISH read on option positioning.
- **Watchlist monitoring** — scan your names daily and log the standout contracts.
- **Model inputs** — feed unusual-flow signals into your own screening or alerts.
- **Earnings & event runups** — spot positioning building ahead of a catalyst.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| **tickers** | array | \["AAPL","TSLA","NVDA","SPY","AMD"] | US stock/ETF symbols to scan |
| **max\_expiries** | integer | 3 | Nearest expiration dates to scan per ticker |
| **min\_volume** | integer | 500 | Ignore contracts trading below this many contracts today |
| **min\_vol\_oi\_ratio** | number | 2.0 | Flag when volume ≥ this multiple of open interest |
| **min\_premium\_usd** | integer | 50000 | Only report contracts with at least this much premium traded |
| **include\_sentiment** | boolean | true | Append a per-ticker call/put sentiment summary row |
| **max\_results** | integer | 100 | Cap on unusual contracts returned (sentiment rows are always kept) |
| **request\_timeout\_secs** | integer | 30 | HTTP timeout in seconds |

#### Example input

```json
{
  "tickers": ["AAPL", "NVDA", "SPY"],
  "max_expiries": 2,
  "min_volume": 500,
  "min_vol_oi_ratio": 2.0,
  "min_premium_usd": 50000
}
```

### Example output

```json
{
  "row_type": "contract",
  "ticker": "SPY",
  "option_type": "put",
  "strike": 751.0,
  "expiry": "2026-07-10",
  "spot": 751.71,
  "moneyness": "ATM",
  "volume": 101234,
  "open_interest": 2492,
  "vol_oi_ratio": 40.62,
  "last_price": 1.39,
  "premium_usd": 14071526.0,
  "implied_volatility": 11.19,
  "unusual_score": 47.35
}
```

```json
{
  "row_type": "sentiment",
  "ticker": "NVDA",
  "sentiment": "BULLISH",
  "call_premium_usd": 156450000.0,
  "put_premium_usd": 45480000.0,
  "call_share": 0.775,
  "unusual_contracts": 22,
  "premium_usd": 201934426.0
}
```

### Tips

- Start with the defaults, then raise `min_premium_usd` to focus only on the biggest prints.
- Lower `min_vol_oi_ratio` toward 1.0 for wider coverage, raise it for only the freshest positioning.
- A high `vol_oi_ratio` on a contract with near-zero open interest is the classic "brand-new position" tell.
- Widen `max_expiries` to catch positioning further out (earnings, macro events).

### Disclaimer

This actor returns delayed public market data for **informational purposes only**. It is **not** financial, investment or trading advice. "Unusual" volume is a mechanical signal, **not** a prediction — large prints can be hedges, spreads, or closing trades, and premium is an estimate from last price, not a confirmed fill. Always do your own research. You are responsible for your own decisions and for complying with CBOE's terms and your local laws.

# Actor input Schema

## `tickers` (type: `array`):

US stock/ETF symbols to scan for unusual options activity (e.g. AAPL, TSLA, SPY).

## `max_expiries` (type: `integer`):

How many upcoming expiration dates to pull per ticker (nearest first). More = deeper scan, slower run.

## `min_volume` (type: `integer`):

Ignore contracts trading below this many contracts today. Filters out illiquid noise.

## `min_vol_oi_ratio` (type: `number`):

Flag a contract as unusual when today's volume is at least this multiple of its open interest (fresh positioning). Contracts with zero open interest qualify on volume alone.

## `min_premium_usd` (type: `integer`):

Only report contracts whose estimated traded premium (volume x price x 100) is at least this much. Focuses on big-money prints.

## `max_results` (type: `integer`):

Cap on the number of unusual-activity rows returned per run.

## `include_sentiment` (type: `boolean`):

If true, append one summary row per ticker with net call vs put premium (bullish/bearish flow).

## `request_timeout_secs` (type: `integer`):

HTTP request timeout.

## Actor input object example

```json
{
  "tickers": [
    "AAPL",
    "TSLA",
    "NVDA",
    "SPY",
    "AMD"
  ],
  "max_expiries": 3,
  "min_volume": 500,
  "min_vol_oi_ratio": 2,
  "min_premium_usd": 50000,
  "max_results": 100,
  "include_sentiment": true,
  "request_timeout_secs": 30
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "tickers": [
        "AAPL",
        "TSLA",
        "NVDA",
        "SPY",
        "AMD"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("0xgollum/unusual-options-activity").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "tickers": [
        "AAPL",
        "TSLA",
        "NVDA",
        "SPY",
        "AMD",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("0xgollum/unusual-options-activity").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "tickers": [
    "AAPL",
    "TSLA",
    "NVDA",
    "SPY",
    "AMD"
  ]
}' |
apify call 0xgollum/unusual-options-activity --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=0xgollum/unusual-options-activity",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/WygUq8Jp0mwXQ4Mkt/builds/bFB3X2qKrAF5CzSmm/openapi.json
