Build an insider buying screener with Form 4 data
Screen open market insider purchases (Form 4 code P) across the whole market with SecFeed's bulk insider data, then drill into one company.
Open market purchases by officers and directors (transaction code P on Form 4) are a widely studied data point because insiders buy with their own money. This tutorial screens every purchase filed over two months, finds companies where several insiders bought, then looks at one company's full history.
Step 1: load two months of insider transactions
For market wide screens, the bulk dataset is the efficient path: one call returns every parsed Form 3, 4 and 5 row filed in a month as gzipped JSON Lines.
import gzip
import json
import os
import requests
BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}
# Parsed Form 3/4/5 rows, one gzipped JSON Lines file per filing month
rows = []
for month in ["2026-09", "2026-10"]:
r = requests.get(f"{BASE}/v1/bulk/download", params={"dataset": "insider-transactions", "month": month},
headers=HEADERS, timeout=300)
r.raise_for_status()
rows += [json.loads(line) for line in gzip.decompress(r.content).splitlines()]
print(len(rows), "rows filed in September and October 2026")
def role(owner):
if owner.get("isOfficer"):
return owner.get("officerTitle") or "Officer"
if owner.get("isDirector"):
return "Director"
if owner.get("isTenPercentOwner"):
return "10% owner"
return owner.get("otherText") or "Other"
buys = [x for x in rows if x["code"] == "P" and x["kind"] == "transaction" and x["shares"] and x["price"]]
for x in buys:
x["usd"] = x["shares"] * x["price"]
buys = [x for x in buys if x["usd"] >= 100_000 and x["price"] < 5000] # a price above $5,000 is almost always a filer typo
print(len(buys), "open market purchases of $100,000 or more")
# cluster: issuers where two or more different insiders bought
by_issuer = {}
for x in buys:
by_issuer.setdefault((x["ticker"], x["issuer_name"]), set()).add(x["owners"][0]["name"])
clusters = {k: v for k, v in by_issuer.items() if len(v) >= 2}
print(len(clusters), "issuers with purchases by 2+ insiders")
print()
for (ticker, name), insiders in sorted(clusters.items(), key=lambda kv: -len(kv[1]))[:5]:
print(f"{ticker or '-':6} {name[:30]:30} {len(insiders)} insiders")
print()
for x in sorted(buys, key=lambda x: -x["usd"])[:8]:
o = x["owners"][0]
print(f"{x['tx_date']} {(x['ticker'] or '-'):6} {x['issuer_name'][:28]:28} {o['name'][:24]:24} {role(o)[:22]:22} ${x['usd']:>13,.0f}")
Output:
34121 rows filed in September and October 2026
778 open market purchases of $100,000 or more
55 issuers with purchases by 2+ insiders
BBD BANK BRADESCO 22 insiders
SBLK Star Bulk Carriers Corp. 6 insiders
NONE Blackstone Multi-Strategy Hedg 5 insiders
ADRX ADARx Pharmaceuticals, Inc. 5 insiders
GME GameStop Corp. 4 insiders
2026-09-15 TYRA Tyra Biosciences, Inc. Shah Rajeev M. Director $ 199,999,994
2026-09-01 PBLSX AMG Pantheon Infrastructure Pantheon Infrastructure 10% owner $ 99,379,127
2026-09-18 LEN, LEN.B LENNAR CORP /NEW/ BERKSHIRE HATHAWAY INC 10% owner $ 93,075,791
2026-09-04 RSG REPUBLIC SERVICES, INC. GATES WILLIAM H III 10% owner $ 59,791,602
2026-09-03 RSG REPUBLIC SERVICES, INC. GATES WILLIAM H III 10% owner $ 56,956,600
2026-09-08 RSG REPUBLIC SERVICES, INC. GATES WILLIAM H III 10% owner $ 55,425,276
2026-09-30 LEN LENNAR CORP /NEW/ BUFFETT WARREN E 10% owner $ 52,120,753
2026-09-09 RSG REPUBLIC SERVICES, INC. GATES WILLIAM H III 10% owner $ 47,227,619
What the screen does
- Keeps rows where
kindistransactionandcodeisP(open market purchase). Holdings rows and other codes, such as grants (A), option exercises (M) and tax withholding (F), are dropped. - Computes the dollar amount as shares times price, keeps $100,000 and up, and drops prices above $5,000 per share, which are almost always data entry errors by the filer.
- Groups by issuer and counts distinct insiders to find cluster purchases.
The owners field carries the reporting person's name and relationship flags (isDirector, isOfficer with officerTitle, isTenPercentOwner), which is how the role column is built.
Step 2: drill into one company
For one issuer, call /v1/insider-trading with a ticker:
import os
import requests
BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}
r = requests.get(f"{BASE}/v1/insider-trading", params={"ticker": "NVDA", "size": 50}, headers=HEADERS, timeout=120)
r.raise_for_status()
data = r.json()
print(data["total"], "NVDA rows")
for t in data["transactions"]:
if t["kind"] != "transaction":
continue
print(t["tx_date"], t["code"], t["codeDescription"], t["owners"][0]["name"], t["shares"], t["price"], "10b5-1" if t["aff10b5one"] else "")
Output:
6965 NVDA rows
2026-10-07 G Bona fide gift COXE TENCH 500000.0 0.0 10b5-1
2026-09-21 S Open market or private sale Teter Timothy S. 13478.0 223.05 10b5-1
2026-09-21 S Open market or private sale Teter Timothy S. 12483.0 222.19 10b5-1
2026-09-21 S Open market or private sale Teter Timothy S. 4499.0 223.75 10b5-1
2026-09-18 S Open market or private sale STEVENS MARK A 1356000.0 219.72
2026-09-18 S Open market or private sale STEVENS MARK A 10000.0 220.42
2026-09-16 F Payment of exercise price or tax by delivering securities HUANG JEN HSUN 45728.0 212.17
2026-09-16 F Payment of exercise price or tax by delivering securities Kress Colette 40747.0 212.17 10b5-1
2026-09-16 F Payment of exercise price or tax by delivering securities Teter Timothy S. 35738.0 212.17
2026-09-16 F Payment of exercise price or tax by delivering securities Shoquist Debora 35008.0 212.17
2026-09-17 S Open market or private sale Kress Colette 20369.0 219.02 10b5-1
2026-09-17 S Open market or private sale Kress Colette 9868.0 219.59 10b5-1
2026-09-17 S Open market or private sale Kress Colette 4681.0 218.01 10b5-1
2026-09-16 F Payment of exercise price or tax by delivering securities GAWEL SCOTT 2932.0 212.17
2026-09-17 G Bona fide gift HUANG JEN HSUN 438000.0 0.0
2026-09-09 A Grant or award Parker Nicholas P. 172507.0 0.0
2026-09-04 S Open market or private sale STEVENS MARK A 237820.0 231.17
2026-09-03 S Open market or private sale STEVENS MARK A 200000.0 229.87
2026-09-04 S Open market or private sale STEVENS MARK A 197180.0 230.4
2026-09-03 S Open market or private sale STEVENS MARK A 198707.0 227.7
2026-09-04 S Open market or private sale STEVENS MARK A 182628.0 233.46
2026-09-04 S Open market or private sale STEVENS MARK A 4611.0 234.0
2026-09-03 S Open market or private sale STEVENS MARK A 1293.0 228.27
2026-09-02 G Bona fide gift COXE TENCH 500000.0 0.0 10b5-1
Each row includes codeDescription, so you do not need a lookup table, and aff10b5one tells you whether the filer checked the Rule 10b5-1 trading plan box.
Notes
- Purchases by 10% owners are often funds or corporate holders, not executives. Filter on
isOfficerorisDirectorif you only want management. - This is research data, not a recommendation to trade.
Next steps
- Insider Trading API and Bulk Datasets
- Form 144 proposed sales
- Datasets: Form 4, Form 3, Form 5