# SEC Form 4 Insider Cluster-Buy Monitor (`titan_coder/sec-form4-cluster-buy-monitor`) Actor

Watches Form 4 filings for companies you pick and tells you when several DIFFERENT officers, directors or 10%-owners buy stock in the open market within a short window — a far stronger signal than any single insider trade.

- **URL**: https://apify.com/titan\_coder/sec-form4-cluster-buy-monitor.md
- **Developed by:** [Radu Furtuna](https://apify.com/titan_coder) (community)
- **Categories:** Lead generation, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$50.00 / 1,000 insider cluster buy detecteds

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?

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

## SEC Form 4 Insider Cluster-Buy Monitor

One insider buying is a data point. **Several different officers, directors or 10%-owners of the
same company buying in the open market within a few days of each other is a signal** — and there is
no existing Apify Actor that watches for it. Everything else in the SEC Form 4 space is a one-shot
list or a single-trade tracker.

This Actor watches the companies you pick and tells you exactly when that cluster forms.

### How it works

1. For each company (`cik`), fetch the official **SEC EDGAR Submissions API** — no scraping, no key,
   just a descriptive `User-Agent` (SEC's fair-use policy).
2. Find new **Form 4** filings since the last check, fetch and parse each one from EDGAR Archives.
3. Keep only filings that are: a **single reporting owner** (not a joint/institutional group filing —
   see "Honest limits"), who is an **officer, director, or 10%-owner**, with at least one **open-market
   purchase** (`transactionCode = P`, `acquiredDisposedCode = A` — not an award, option exercise, gift,
   or sale).
4. Keep a rolling window of these purchases per company. When **N distinct insiders** (default 2) have
   bought within **W days** of each other (by transaction date, default 5), that is a cluster — you get
   one row with every purchase behind it.

### Input

```json
{
  "monitorId": "my-watchlist",
  "userAgentContact": "you@example.com",
  "watches": [{"watchId": "acme", "cik": "320193"}],
  "clusterWindowDays": 5,
  "minDistinctInsiders": 2
}
```

### Output row

| Field | Meaning |
|---|---|
| `distinctInsiders` | how many different people bought |
| `windowStart`, `windowEnd` | transaction-date span of the cluster |
| `totalShares`, `totalValueUsd` | summed across the cluster (null components are omitted, not zeroed) |
| `purchases` | each purchase: insider name, title, transaction date, shares, price |

A cluster that later **grows** (a new insider joins) is delivered again as a new, larger event — that
is a materially stronger signal, not a duplicate. The exact same set of purchases is never billed twice.

### Pricing

Pay per event:

- **`insider-cluster-detected`** — charged once per newly-formed or newly-grown cluster, after the row
  is written to the dataset. No charge for runs that find nothing.

**What happens if a run is interrupted.** This Actor keeps a durable four-state delivery ledger
(intent → written → charge started → billed) in its own per-monitor key-value store. The honest
guarantee, stated precisely rather than rounded up: delivery to the dataset is **at-least-once** — a
crash between a confirmed write and the transport acknowledging it can produce a duplicate row on
retry, which we accept because a duplicate row costs you nothing. Charging is **at-most-once, with a
tracked uncertain window**: a row is never billed before it is confirmed written, never billed twice
for the same content, and the one case the ledger cannot resolve on its own — a crash inside the
charge call itself — is never re-charged automatically; it is counted in the run's coverage record
(`chargeUncertainRows`) for manual reconciliation instead of being guessed at.

### Honest limits

- **Group/institutional filings are excluded.** Some Form 4s are filed jointly by several related
  entities under one accession number (measured live: a single filing by Goldman Sachs group entities
  covering 8+ affiliated filers). The raw filing gives no reliable way to attribute individual
  transactions to individual filers in that case, and most such filings are funds, not people with
  Section 16 insider status anyway. This Actor only processes single-owner filings.
- **`P` (open-market purchase) only.** Grants, awards, option exercises, gifts and sales are not
  purchase signals and are excluded, even though they appear in the same filings.
- **Calendar days, not trading days**, for the cluster window — simpler, and the difference does not
  matter at the window sizes this product uses.
- **New watches see a live window, not history.** The window is pruned to the last `clusterWindowDays`
  on every run, so a brand-new watch cannot retroactively "discover" an old cluster from months ago —
  only purchases whose transaction date is genuinely recent ever count.

### Coverage record

Every run writes a `coverage` record: per-watch status and reason, new Form 4 filings seen, fetch
errors (filings that failed to parse are retried next run, never silently dropped), current window
size, clusters delivered and billed. If part of the run failed, the record says which part and why.

Author: OmniCoder (https://t.me/OmniCoder)

# Actor input Schema

## `monitorId` (type: `string`):

Your own identifier for this monitor instance, lowercase letters/digits/hyphens. Keep it stable across runs — it scopes this monitor's durable state.

## `userAgentContact` (type: `string`):

SEC requires a descriptive, identifiable User-Agent on every request to EDGAR (fair-use policy). Give your email or a contact link (e.g. https:// or t.me/...). Not a secret, just required identification.

## `watches` (type: `array`):

List of {watchId, cik} objects. cik is the company's SEC Central Index Key (1-10 digits, leading zeros optional).

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

How many days apart insider purchases can be and still count as one cluster, measured by transaction date (not filing date). Default 5.

## `minDistinctInsiders` (type: `integer`):

How many different officers/directors/10%-owners must buy within the window to count as a cluster. Minimum 2 — one insider is not a cluster by definition.

## `webhookUrl` (type: `string`):

Optional. Receives a JSON summary of the run. HTTPS only.

## Actor input object example

```json
{
  "monitorId": "example-monitor",
  "userAgentContact": "you@example.com",
  "watches": [
    {
      "watchId": "example-co",
      "cik": "320193"
    }
  ],
  "clusterWindowDays": 5,
  "minDistinctInsiders": 2
}
```

# Actor output Schema

## `clusters` (type: `string`):

One row per detected cluster: distinct insiders, total shares/value, window dates, and the individual purchases (insider name, title, date, shares, price) behind it.

## `coverage` (type: `string`):

Per-watch status and reason, new Form 4 filings seen, fetch errors, current window size, clusters delivered/billed. Enough to reconcile every charge against every row.

# 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 = {
    "monitorId": "example-monitor",
    "userAgentContact": "you@example.com",
    "watches": [
        {
            "watchId": "example-co",
            "cik": "320193"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("titan_coder/sec-form4-cluster-buy-monitor").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 = {
    "monitorId": "example-monitor",
    "userAgentContact": "you@example.com",
    "watches": [{
            "watchId": "example-co",
            "cik": "320193",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("titan_coder/sec-form4-cluster-buy-monitor").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 '{
  "monitorId": "example-monitor",
  "userAgentContact": "you@example.com",
  "watches": [
    {
      "watchId": "example-co",
      "cik": "320193"
    }
  ]
}' |
apify call titan_coder/sec-form4-cluster-buy-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,titan_coder/sec-form4-cluster-buy-monitor"
        }
    }
}
```

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/y2oNJDrYHgR8NOfR8/builds/kR4FRq1hYl8qxbxYA/openapi.json
