# SEC 13F Holdings Changes API – Hedge Fund Buys & Sells (`groundplanes/sec-13f-holdings-changes`) Actor

Compare any manager's two latest SEC 13F filings: every position change (NEW, ADDED, TRIMMED, SOLD_OUT) with shares, values & portfolio weight. Follow smart-money moves.
Free sample (15 rows, real output): https://drive.google.com/uc?export=download\&id=1VagFPzqpEfPshTkamUot8N4DWvKFkDcf

- **URL**: https://apify.com/groundplanes/sec-13f-holdings-changes.md
- **Developed by:** [John](https://apify.com/groundplanes) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 position changes

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/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 13F Hedge Fund Holdings Scraper - Quarterly Changes

See what a hedge fund or other institutional manager bought, added to, trimmed and sold between its two latest SEC 13F filings. Give it one or more fund CIKs and get one row per position with shares, values, portfolio weight and a clear change label: `NEW`, `ADDED`, `TRIMMED`, `SOLD_OUT` or `UNCHANGED`.

Found a problem or need a field? Open an issue on the Issues tab; we respond quickly.

### Free sample

Download a free sample (15 rows, real actor output, CSV): https://drive.google.com/uc?export=download\&id=1VagFPzqpEfPshTkamUot8N4DWvKFkDcf — check the columns and data quality before you run anything.

### What it does

Institutional investment managers with more than $100 million in US equities file Form 13F-HR with the SEC each quarter. The filing's information table lists every reported position. Raw tables are awkward to compare. One stock is often split across many rows for different sub-managers, file names change from filing to filing, and amendments can either restate a filing or add positions that were previously confidential.

For each fund, this Actor:

- Reads the fund's filing history from SEC EDGAR and picks the two newest quarters with a 13F-HR. 13F-NT notice filings are skipped.
- Finds the information-table XML through the filing index. It is not always named `infotable.xml`.
- Applies amendments. A `13F-HR/A` restatement replaces the original. A "NEW HOLDINGS" amendment, which discloses positions that were previously confidential, is merged in.
- Adds up shares and value per `cusip` + `putCall` across all sub-managers.
- Converts values to whole US dollars. Filings made before January 3, 2023 reported value in thousands and are multiplied by 1,000.
- Returns every position held in either quarter, with its quarter-over-quarter change.

### Who it's for

- **Investors and analysts** tracking what well-known funds bought and sold last quarter.
- **Newsletter and alert builders** who need clean, structured 13F change data.
- **Investor relations teams** watching institutional ownership changes in their own stock.
- **Researchers** building datasets of institutional positioning.

### Input

- **`fundCiks`** *(array of strings, required)*: SEC CIKs of 13F filers. Leading zeros are optional (`0001067983` or `1067983`). Up to 50 per run. Default: `["0001067983"]` (Berkshire Hathaway).
- **`changeTypes`** *(array)*: any of `NEW`, `ADDED`, `TRIMMED`, `SOLD_OUT`, `UNCHANGED`. Leave empty to get everything except `UNCHANGED`. Default: `[]`.
- **`minPositionValueUsd`** *(integer)*: keep positions worth at least this much in either quarter. For `SOLD_OUT` rows, the prior-quarter value is used. Default: `0`.
- **`includeOptions`** *(boolean)*: include put and call option positions. Default: `true`.
- **`secUserAgent`** *(string, secret)*: optional SEC fair-access User-Agent such as `Your Company admin@yourcompany.com`. Leave blank to use the built-in one. It is never logged.
- **`maxItems`** *(integer)*: maximum rows to return. Default: `200`.

#### Example input JSON

```json
{
  "fundCiks": ["0001067983"],
  "changeTypes": [],
  "minPositionValueUsd": 0,
  "includeOptions": true,
  "maxItems": 200
}
```

#### Example run options (default max charge $50)

When you start a run from the Apify API or Console, set a default maximum charge of **$50** in the run options:

```json
{
  "maxTotalChargeUsd": 50
}
```

The Actor stops cleanly when the limit is reached and keeps the rows it already returned. A run that hit the charge limit (or had any other problem) ends with a `PARTIAL:` status message naming the problem — it never reports a partial result as complete.

#### Canary (health check)

```json
{
  "fundCiks": ["0001067983"],
  "maxItems": 5
}
```

Expected healthy result: the run succeeds in a few seconds, returns **5 rows** for Berkshire Hathaway's two latest quarters, and the status message reads `Complete: 5 rows (reached maxItems=5)`. A `PARTIAL:` status on this input means something upstream needs attention.

### Output

Rows are sorted newest first by `filingDate`, then by `valueUsd` (largest first). Each fund + quarter + CUSIP + put/call appears once.

| Field | Type | Description |
|---|---|---|
| `fundCik` | string | 10-digit SEC CIK of the filer. |
| `fundName` | string | null | Filer name from SEC EDGAR. |
| `periodOfReport` | string | Quarter-end date of the newest 13F (`YYYY-MM-DD`). |
| `priorPeriodOfReport` | string | null | Quarter-end date compared against. Null if the fund has only one 13F. |
| `filingDate` | string | Filing date of the filing that reported this position (`YYYY-MM-DD`). For `SOLD_OUT` rows it is the current quarter's filing date — the filing that shows the position is gone. |
| `accessionNumber` | string | SEC accession number of that filing (for `SOLD_OUT` rows, the current quarter's filing). |
| `issuerName` | string | null | Issuer name as reported. |
| `titleOfClass` | string | null | Class of security, e.g. `COM`, `CL A`. |
| `cusip` | string | 9-character CUSIP. |
| `putCall` | string | null | `PUT` or `CALL` for options; null for shares or principal amounts. |
| `shares` | number | Shares (or principal amount) this quarter. |
| `priorShares` | number | Shares (or principal amount) last quarter. |
| `shareChange` | number | `shares - priorShares`. |
| `shareChangePct` | number | null | Percent change in shares. Null for `NEW`. |
| `changeType` | string | `NEW`, `ADDED`, `TRIMMED`, `SOLD_OUT` or `UNCHANGED`. |
| `valueUsd` | number | Reported market value this quarter, in US dollars. |
| `priorValueUsd` | number | Reported market value last quarter, in US dollars. |
| `portfolioWeightPct` | number | null | `valueUsd` as a percent of the fund's total reported 13F value this quarter. |
| `infoTableUrl` | string | Link to the information-table XML on sec.gov. |

#### Sample output row (synthetic example)

```json
{
  "fundCik": "0009999999",
  "fundName": "Example Capital Management LP",
  "periodOfReport": "2026-06-30",
  "priorPeriodOfReport": "2026-03-31",
  "filingDate": "2026-08-14",
  "accessionNumber": "0009999999-26-000003",
  "issuerName": "EXAMPLE INDUSTRIES INC",
  "titleOfClass": "COM",
  "cusip": "000000000",
  "putCall": null,
  "shares": 1250000,
  "priorShares": 1000000,
  "shareChange": 250000,
  "shareChangePct": 25.0,
  "changeType": "ADDED",
  "valueUsd": 62500000,
  "priorValueUsd": 45000000,
  "portfolioWeightPct": 4.1667,
  "infoTableUrl": "https://www.sec.gov/Archives/edgar/data/9999999/000999999926000003/infotable.xml"
}
```

### How pricing works

Pay per result. You only pay for rows returned. The Actor respects your run's maximum charge (recommended default `"maxTotalChargeUsd": 50`) and stops cleanly when it is reached.

### Data source and terms

- **Official source:** SEC EDGAR submissions API (`data.sec.gov/submissions`) and filing archives (`sec.gov/Archives`). See [SEC: Accessing EDGAR Data](https://www.sec.gov/search-filings/edgar-search-assistance/accessing-edgar-data) and the [SEC Form 13F FAQ](https://www.sec.gov/rules-regulations/staff-guidance/division-investment-management-frequently-asked-questions/frequently-asked-questions-about-form-13f).
- **Fair access:** requests are limited to 6 per second with a descriptive User-Agent, below the SEC's 10-per-second limit.
- **Update frequency:** managers file 13F-HR up to 45 days after each quarter ends (mid-February, mid-May, mid-August and mid-November). Holdings can therefore be up to 45 days old when filed, plus however long since the filing.
- **Not investment advice.** This data is for information and research only.
- This Actor is independent and is **not affiliated with or endorsed by the U.S. Securities and Exchange Commission (SEC)**.
- Output contains company and fund data only. No personal contact information is collected.

### Limits and FAQ

- **Why are different funds on different quarters?** Each fund is compared on its own two newest 13F quarters. A fund that hasn't filed the latest quarter yet shows the quarter before.
- **What counts as a change?** It is based on share count only. A position with the same shares but a different value (price movement) is `UNCHANGED`.
- **Why can options make `portfolioWeightPct` look large?** 13F reports options at the value of the underlying shares, not the premium paid, and those values are included in the fund's total.
- **13F gaps.** 13F covers long positions in "Section 13(f) securities" only. It excludes short positions, most non-US holdings and cash. Positions under confidential treatment appear only once a NEW HOLDINGS amendment is filed.
- **Pre-2023 values.** The SEC switched value reporting from thousands to whole dollars for filings made on or after January 3, 2023. The Actor converts by filing date, so a Q4 2022 report filed in February 2023 is already in dollars and is not multiplied.
- **Only one 13F on file?** Every position is marked `NEW` and `priorPeriodOfReport` is null.
- **Very old filings** (before mid-2013) have no XML information table and can't be parsed.
- **How do I find a CIK?** Search the manager on [EDGAR company search](https://www.sec.gov/edgar/search/). The CIK is shown next to the name.

### Troubleshooting

- **The run failed with "no matching 13F positions".** Your filters excluded everything. Add `UNCHANGED` to `changeTypes`, lower `minPositionValueUsd`, turn `includeOptions` back on, or add more `fundCiks`.
- **A fund CIK was skipped / the status says `PARTIAL:`.** One or more requested funds had a problem — for example the CIK is not a 13F filer (operating companies like Apple do not file 13F-HR), EDGAR returned an error, or a filing's amendment type or information table could not be verified. The `PARTIAL:` status message names the fund and the exact problem, and the rows from the healthy funds are still returned. The Actor never guesses an amendment type or invents missing table data, so an unverifiable filing is reported, not silently skipped.
- **The run stopped at the max charge limit.** Raise `maxTotalChargeUsd` in the run options, or narrow the run (fewer funds, higher `minPositionValueUsd`, smaller `maxItems`). Rows already returned are kept.
- **A value looks 1,000× too large (or too small) for an old quarter.** Filings made before January 3, 2023 reported values in thousands of dollars; the Actor converts by filing date. If a specific filing still looks wrong, open an issue with the accession number.
- **A position you expected is missing.** 13F excludes short positions, most non-US holdings and cash, and positions under confidential treatment appear only after a NEW HOLDINGS amendment. Also check that the fund has actually filed for that quarter — filings can arrive up to 45 days after quarter end.
- **SEC EDGAR is slow or returns errors.** The Actor retries with backoff and respects the SEC's fair-access limit (6 requests/second, under the 10/second ceiling). If EDGAR is down, rerun later; a run affected by an EDGAR outage ends `PARTIAL:` or fails with the failing fund named, never with silently incomplete data.

### Changelog

- **v0.2 (2026-10-27):** docs: free-sample section + store refresh; no code changes.

- **v0.1 (2026-10-23):** Initial release. Two-quarter comparison, restatement and NEW HOLDINGS amendment handling, sub-manager aggregation, value-unit conversion and max-charge stop.

# Actor input Schema

## `changeTypes` (type: `array`):

Which position changes to return. Leave empty for everything except UNCHANGED.

## `fundCiks` (type: `array`):

SEC CIK numbers of 13F filers (institutional investment managers). Leading zeros are optional, e.g. 0001067983 or 1067983 for Berkshire Hathaway. Find a CIK with EDGAR company search. Up to 50 per run.

## `includeOptions` (type: `boolean`):

When off, drops option positions (rows where putCall is PUT or CALL) and keeps only shares and principal amounts.

## `maxItems` (type: `integer`):

Maximum number of position rows to return.

## `minPositionValueUsd` (type: `integer`):

Keep only positions worth at least this much in either quarter (current value, or prior value for SOLD_OUT rows). 0 keeps everything.

## `secUserAgent` (type: `string`):

Optional SEC fair-access User-Agent, e.g. 'Your Company admin@yourcompany.com'. Leave blank to use the built-in compliant User-Agent. Never logged.

## Actor input object example

```json
{
  "changeTypes": [],
  "fundCiks": [
    "0001067983"
  ],
  "includeOptions": true,
  "maxItems": 200,
  "minPositionValueUsd": 0
}
```

# 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 = {
    "changeTypes": [],
    "fundCiks": [
        "0001067983"
    ],
    "includeOptions": true,
    "maxItems": 200,
    "minPositionValueUsd": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("groundplanes/sec-13f-holdings-changes").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 = {
    "changeTypes": [],
    "fundCiks": ["0001067983"],
    "includeOptions": True,
    "maxItems": 200,
    "minPositionValueUsd": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("groundplanes/sec-13f-holdings-changes").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 '{
  "changeTypes": [],
  "fundCiks": [
    "0001067983"
  ],
  "includeOptions": true,
  "maxItems": 200,
  "minPositionValueUsd": 0
}' |
apify call groundplanes/sec-13f-holdings-changes --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,groundplanes/sec-13f-holdings-changes"
        }
    }
}
```

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/gTHbC1CPfbvN1bPEJ/builds/bFO9atk6Igdt8QXZc/openapi.json
