# SEC Insider Trading API (Form 4): live + history since 2006 (`bosco_labs/sec-insider-trades`) Actor

Insider trading data from SEC Form 4: every insider purchase and sale by directors, officers and 10% owners, from official EDGAR filings, 2006 to today. Filter by ticker, CIK, transaction code, role, value and date; adds cluster-buy and cluster-sell signals. Use for insider screens and alerts.

- **URL**: https://apify.com/bosco_labs/sec-insider-trades.md
- **Developed by:** [Bosco Labs](https://apify.com/bosco_labs) (community)
- **Categories:** Business, News, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 insider transactions

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## SEC Insider Trading API (Form 4): live + history since 2006

Get **every insider purchase and sale reported to the SEC on Form 4**, from today's filings back
to 2006, as clean JSON rows: who traded (director, CEO, 10% owner), what, when, how many shares,
at what price, and how many they hold afterwards. Plus **cluster-buy and cluster-sell
signals**: the moment two or more directors or officers of the same company buy, or sell,
their own stock within a few weeks. Filter by ticker, CIK, transaction code, insider role,
value and date.

**Pricing (pay per event):** $0.0018 per transaction row ($1.80 per 1,000) and $0.02 per cluster
signal. No start fee. You only pay for rows delivered, a transaction is never charged twice in
a scheduled feed, and the Actor stops at your max charge limit.

Data comes straight from the SEC: the official EDGAR Form 4 filings (parsed from their XML, no
AI) and the SEC's quarterly "Insider Transactions Data Sets" for the history. No scraping of
third-party sites, no logins.

### What you get

One row per Form 4 transaction (non-derivative table: common stock and similar). Real output,
Chesapeake Energy director Archie Dunham's $14M purchase in March 2015:

```json
{
  "record_type": "transaction",
  "accession_number": "0000895126-15-000082",
  "form": "4",
  "issuer_name": "CHESAPEAKE ENERGY CORP",
  "issuer_cik": "0000895126",
  "ticker": "CHK",
  "insider_name": "DUNHAM ARCHIE W",
  "insider_cik": "0001192053",
  "insider_roles": ["director"],
  "officer_title": null,
  "owner_count": 1,
  "transaction_date": "2015-03-27",
  "filing_date": "2015-03-31",
  "transaction_code": "P",
  "transaction_type": "Open-market or private purchase",
  "acquired_disposed": "A",
  "shares": 1000000,
  "price": 13.98,
  "value_usd": 13980000.0,
  "shares_owned_after": 2635270,
  "ownership": "direct",
  "plan_10b5_1": false,
  "cluster_insiders": 2,
  "cluster_value_usd": 14029455.0,
  "in_cluster": true,
  "cluster_date": "2015-03-31",
  "filing_url": "https://www.sec.gov/Archives/edgar/data/895126/000089512615000082/0000895126-15-000082-index.htm",
  "source": "dera",
  "source_url": "https://www.sec.gov/files/structureddata/data/insider-transactions-data-sets/2015q1_form345.zip",
  "retrieved_at": "2026-11-05T16:15:49+00:00"
}
```

And the cluster signal it belongs to (`record_type: "cluster"`):

```json
{
  "record_type": "cluster",
  "issuer_name": "CHESAPEAKE ENERGY CORP",
  "ticker": "CHK",
  "filing_date": "2015-03-31",
  "first_filing_date": "2015-03-13",
  "cluster_insiders": 2,
  "cluster_value_usd": 14029455.0,
  "cluster_window_days": 30,
  "insider_names": ["DUNHAM ARCHIE W", "PIGOTT M. JASON"],
  "accession_numbers": ["0000895126-15-000079", "0000895126-15-000082"]
}
```

**Fields:** issuer name, CIK and ticker (as filed), insider name, CIK and roles
(`director`, `officer`, `ten_percent_owner`, `other`), officer title, transaction date, filing
date, EDGAR acceptance time (live rows), transaction code and its meaning, shares, price, value,
shares owned after, direct/indirect ownership, Rule 10b5-1 plan flag, security title, accession
number, links to the filing and to the exact SEC file the row came from. Insider names are
mandatory public disclosures; addresses are never output.

### Cluster buys and cluster sells

A **cluster** is the classic insider-buying signal: **at least 2 different directors or officers
of the same company buying in the open market (code P), filed within 30 days, together worth at
least $100,000**. Amendments, 10% owners and "other" filers don't count, and after a cluster
fires, the next one needs new buys. A **cluster sell** is the same rule for open-market sales
(code S), with pre-planned 10b5-1 plan sales left out because they are scheduled in advance.
Forms only flag plan sales since April 2023, so older sell clusters can include some. Buys and
sells are counted separately. Every purchase and sale row gets:

- `cluster_insiders` / `cluster_value_usd`: how many distinct insiders bought (and for how much)
  in the window up to that filing date, with no look-ahead, so you can backtest with it;
- `in_cluster` / `cluster_date`: whether the purchase is part of a cluster signal, and which.

Signal rows have `cluster_side` = `buy` or `sell`. Set `clusterBuysOnly` and/or
`clusterSellsOnly` to get only those trades plus the signal rows; change the window with
`clusterWindowDays`. The counts are `null` when the window reaches back before the data the run
read (for example the newest rows of a short "latest trades" run).

### Input

```json
{ "tickers": ["NVDA", "AAPL"], "transactionCodes": ["P", "S"], "minValueUsd": 100000,
  "dateFrom": "2024-01-01", "maxResults": 1000 }
```

| Field | Meaning |
|---|---|
| `tickers` / `ciks` | Companies (issuers). Empty = the whole market |
| `transactionCodes` | Default `P` (purchases) and `S` (sales). Empty = all codes |
| `insiderRoles` | `director`, `officer`, `ten_percent_owner`, `other` |
| `minValueUsd` | Skip smaller transactions |
| `dateFrom` / `dateTo` | Filing date range, back to 2006-01-01 |
| `lookbackDays` | Without `dateFrom`: the last N days. Empty: 90 days with tickers/CIKs, 7 days for the whole market |
| `clusterBuysOnly`, `clusterSellsOnly`, `clusterWindowDays`, `includeClusterSignals` | Cluster options above |
| `maxResults` | Newest first, default 100, up to 200,000 per run |
| `onlyNewSinceLastRun` | For schedules: only rows you haven't received with the same filters |

Running without input returns the 100 newest open-market purchases and sales of the whole market.

### How fresh, how fast

- **Today's filings** come from the EDGAR live feed, minutes after the SEC accepts them; each
  Form 4 is then read from its XML (one request per filing).
- **Recent quarters** (after the latest SEC data set, usually the last 1 to 4 months) are read
  from the EDGAR indexes and the Form 4 XML. For one or a few companies this takes seconds. A
  whole-market scan reads about 600 filings per trading day at the SEC's rate limit, roughly
  1.5 minutes per day of filings; it stops early once `maxResults` is reached. Completed days
  are pre-read every night, so a whole-market run (for example 30 days of cluster buys) reads
  only today's filings one by one and usually finishes in a minute or two, with the same results.
- **History (2006 to the last quarter)** comes from the SEC's quarterly data sets, about 10 to
  15 seconds per quarter. A whole-market year of cluster buys took under a minute in our test.

### Use cases

- **Trading signals and screening:** insider buying clusters, large CEO purchases, heavy selling.
- **Backtesting:** 20 years of point-in-time insider data with filing dates (no look-ahead).
- **Alerts:** schedule hourly or daily with `onlyNewSinceLastRun` and pipe new rows to Slack,
  email or a sheet.
- **Due diligence and compliance:** every trade of an executive or a company, with the filing link.
- **AI agents:** small, typed JSON with a source link on every row.

### Use with AI agents (MCP)

Agents can call this Actor as a tool through the
[Apify MCP server](https://github.com/apify/apify-mcp-server). Add this server URL to your MCP
client (Claude, Cursor, VS Code, ...):

```text
https://mcp.apify.com?tools=bosco_labs/sec-insider-trades
```

It loads this Actor as a tool, plus the tools that read its results (`get-actor-run`,
`get-dataset-items`). The hosted server signs you in with OAuth, or accepts your Apify token as
`Authorization: Bearer <APIFY_TOKEN>`. On the default server (`https://mcp.apify.com`), agents
can also find this Actor with `search-actors` and run it with `call-actor`.

Example prompts this Actor answers:

- *"Did any Tesla insiders buy shares in the last 90 days?"*
- *"Show insider cluster buys across the US market this month."*
- *"List Nvidia insider sales over $1 million filed in 2024, with links to the Form 4s."*

For the first one, the agent passes:

```json
{"tickers": ["TSLA"], "transactionCodes": ["P"]}
```

**Output for agents:** stable, typed JSON, one row per Form 4 transaction (and one per cluster signal). Every row has `schema_version` and a `source_url` pointing to the exact SEC file the row came from (plus `filing_url` for the Form 4 itself), so the agent can cite its source.

**Cost:** $0.0018 per transaction row and $0.02 per cluster signal, billed to the Apify account the MCP server is signed in with.

### FAQ

**Is this the same data as OpenInsider and similar sites?** Same source (SEC Form 4), but you get
raw, complete rows through an API, 2006 onward, including amendments (`form: "4/A"`), joint
filings and the 10b5-1 flag.

**What about options?** Grants, exercises and sales of options and other derivatives sit in the
derivative table of Form 4 and are not included. Shares received from an exercise (code `M`) and
sold (code `S`) are.

**Joint filings?** One row per transaction; `insider_name` is the first reporting person,
`owner_count` the number of joint filers, and roles are combined.

**Tickers that changed?** Tickers are mapped to companies with the SEC's current list. For a
delisted or renamed company, pass its CIK, or the old ticker for history (it matches the ticker
written in the filings).

**Why are some prices empty?** Some filings give no price (awards, gifts) or only a footnote;
`price` and `value_usd` are then `null` or 0, exactly as filed.

**Legal basis?** SEC filings are US government public records. See LEGAL.md. This is data, not
investment advice.

# Actor input Schema

## `lookbackDays` (type: `integer`):

Used only when `dateFrom` is empty: read filings from this many days back until today, e.g. 30. Empty = 90 days when `tickers` or `ciks` are set, 7 days for the whole market. Handy for schedules.

## `dateFrom` (type: `string`):

Earliest filing date, YYYY-MM-DD, e.g. "2024-01-01". Data starts 2006-01-01. Empty = `lookbackDays` days before today (90 for tickers/CIKs, 7 for the whole market).

## `dateTo` (type: `string`):

Latest filing date, YYYY-MM-DD, e.g. "2024-12-31". Empty = today, including today's filings from the live EDGAR feed.

## `clusterBuysOnly` (type: `boolean`):

true = only open-market purchases that are part of a cluster: at least 2 different directors or officers of the same company buying, filed within `clusterWindowDays`, together worth at least $100,000. Default false. Also reads the window before the date range.

## `clusterSellsOnly` (type: `boolean`):

true = only open-market sales that are part of a cluster (same rule as cluster buys, for sales). Pre-planned 10b5-1 plan sales are left out (filings flag them since April 2023). Default false. Can be combined with `clusterBuysOnly`.

## `includeClusterSignals` (type: `boolean`):

true (default) = also output one row per cluster signal (record_type = "cluster"): the day a company's insider buying or selling first met the cluster rule, with the insiders and total value. Charged as a separate, higher-priced event. false = transaction rows only.

## `clusterWindowDays` (type: `integer`):

How many days of filings count as one cluster of insider buying or selling, e.g. 14. Default 30.

## `transactionCodes` (type: `array`):

Form 4 transaction codes to return, e.g. \["P"] for open-market purchases only. Default \["P", "S"] (open-market purchases and sales). Pass \[] for all codes, including awards (A), tax withholding (F) and option exercises (M).

## `insiderRoles` (type: `array`):

Only insiders with one of these roles: director, officer, ten_percent_owner, other, e.g. \["director", "officer"]. Empty = all roles.

## `minValueUsd` (type: `integer`):

Minimum transaction value in USD (shares x price), e.g. 100000. Default 0 = no minimum. Transactions without a price count as 0.

## `maxResults` (type: `integer`):

Maximum transaction rows, newest first, e.g. 500. Default 100, up to 200,000 per run (split bigger exports by date range). The run stops reading once it has this many, and returns at most this many cluster signals.

## `onlyNewSinceLastRun` (type: `boolean`):

true = skip (and don't charge for) transactions and signals an earlier run with the same filters already delivered. For scheduled runs. Default false. Remembered in a named key-value store in your account.

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

Optional: issuer stock tickers, e.g. \["AAPL", "TSLA"]. Leave empty to scan the whole market (the usual use: insider buying anywhere). Mapped to the company's CIK with the SEC's ticker list; history is also matched on the ticker as written in the filing.

## `ciks` (type: `array`):

Issuer SEC Central Index Keys as digits, leading zeros optional, e.g. \["320193"] for Apple. Use for delisted or renamed companies the SEC's ticker list no longer has. Empty = no CIK filter.

## Actor input object example

```json
{
  "clusterBuysOnly": false,
  "clusterSellsOnly": false,
  "includeClusterSignals": true,
  "clusterWindowDays": 30,
  "transactionCodes": [
    "P",
    "S"
  ],
  "minValueUsd": 0,
  "maxResults": 50,
  "onlyNewSinceLastRun": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "transactionCodes": [
        "P",
        "S"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("bosco_labs/sec-insider-trades").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 = {
    "transactionCodes": [
        "P",
        "S",
    ],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("bosco_labs/sec-insider-trades").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "transactionCodes": [
    "P",
    "S"
  ],
  "maxResults": 50
}' |
apify call bosco_labs/sec-insider-trades --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bosco_labs/sec-insider-trades"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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