Python Beginner

Insider Trade Scanner

Scan SEC Form 4 filings to find notable insider buys and sells across the market.

Note: The code examples in this tutorial have not yet been verified against the live API. If you encounter issues, please let us know.

What You'll Build

A command-line Python script that scans recent SEC Form 4 filings to find insider trades. Form 4 is the filing that corporate insiders (officers, directors, and large shareholders) must submit when they buy or sell company stock. Open market purchases by insiders are one of the most-watched signals in the market -- when a CEO spends their own money buying shares, it often means they believe the stock is undervalued.

The script will:

  • Fetch recent insider trades from the stockdata.dev API
  • Filter to open market buys (the most interesting signal)
  • Display a formatted table with date, ticker, insider name, title, shares, and total value
  • Support filtering by ticker or time range

Prerequisites

  • Python 3.7 or newer
  • The requests library (pip install requests)
  • A stockdata.dev API key (get one free)

The Code

Create a file called insider_scanner.py and paste the following:

Python
import argparse
import requests

API_KEY = "your_api_key_here"
BASE_URL = "https://api.stockdata.dev/v1"


def fetch_trades(ticker=None, days=7, action="buy"):
    """Fetch insider trades from the API."""
    headers = {"X-API-Key": API_KEY}

    if ticker:
        url = f"{BASE_URL}/insider-trades/{ticker}"
        params = {"days": days, "limit": 100}
    else:
        url = f"{BASE_URL}/insider-trades"
        params = {"days": days, "action": action, "limit": 100}

    resp = requests.get(url, headers=headers, params=params)
    resp.raise_for_status()
    return resp.json()["trades"]


def format_value(value):
    """Format a dollar value with commas."""
    if value >= 1_000_000:
        return f"${value / 1_000_000:.1f}M"
    return f"${value:,.0f}"


def print_trades(trades, title):
    """Print trades as a formatted table."""
    if not trades:
        print("No trades found.")
        return

    print(f"\n{title}")
    print("─" * 90)
    print(f"{'Date':12}{'Ticker':8}{'Insider':22}{'Title':18}{'Shares':>10}{'Value':>14}")
    print("─" * 90)

    for t in trades:
        name = t["owner_name"].title()  # Convert "SMITH JOHN" to "Smith John"
        title_str = t.get("owner_title", "")[:17]
        shares = f"{t['shares']:>,}"
        value = format_value(t["value"])

        print(f"{t['transaction_date']:12}{t['ticker']:8}{name[:21]:22}{title_str:18}{shares:>10}{value:>14}")

    print(f"\nTotal: {len(trades)} trades")


def main():
    parser = argparse.ArgumentParser(description="Scan SEC insider trades")
    parser.add_argument("--ticker", help="Filter to a specific company")
    parser.add_argument("--days", type=int, default=7, help="Look back N days (default: 7)")
    args = parser.parse_args()

    if args.ticker:
        trades = fetch_trades(ticker=args.ticker, days=args.days, action=None)
        title = f"Insider Trades for {args.ticker.upper()} (last {args.days} days)"
    else:
        trades = fetch_trades(days=args.days)
        title = f"Recent Insider Buys (last {args.days} days)"

    print_trades(trades, title)


if __name__ == "__main__":
    main()

Replace "your_api_key_here" with your actual API key. For production scripts, consider using an environment variable instead of hardcoding the key.

How It Works

When corporate insiders trade their company's stock, they must disclose it to the SEC via Form 4. Each trade includes a transaction code that tells you what kind of trade it was:

  • P (Purchase) -- Open market buy. The insider spent their own money to buy shares on the open market. This is the strongest bullish signal because it's entirely voluntary.
  • S (Sale) -- Open market sale. The insider sold shares. Sales can be for many reasons (diversification, taxes, personal expenses), so they're a weaker signal on their own.
  • M (Exercise) -- Option exercise. The insider exercised stock options. Often followed by a sale, this is usually part of a compensation plan and less informative.

The script filters to open market buys by default because they are the most actionable signal. When a CEO or CFO buys shares with their own money, it means they believe the stock is undervalued at the current price.

The API maps these codes to readable action values: "buy" for purchases, "sale" for sales. You can filter on either using the action query parameter.

Running It

Scan for recent insider buys across all companies:

Shell
python insider_scanner.py

Example output:

Output
Recent Insider Buys (last 7 days)
──────────────────────────────────────────────────────────────────────────────────────────
Date        Ticker  Insider               Title             Shares         Value
──────────────────────────────────────────────────────────────────────────────────────────
2026-02-14  XYZ     John Smith            CEO               10,000      $245,000
2026-02-13  ABC     Jane Doe              Director           5,000      $178,500
2026-02-12  DEF     Robert Chen           CFO                8,500      $312,750
2026-02-11  GHI     Maria Garcia          VP Operations      2,000       $67,400
2026-02-10  JKL     David Park            Director          15,000      $495,000

Total: 5 trades

Look up all insider trades for a specific company:

Shell
python insider_scanner.py --ticker AAPL --days 30

Example output:

Output
Insider Trades for AAPL (last 30 days)
──────────────────────────────────────────────────────────────────────────────────────────
Date        Ticker  Insider               Title             Shares         Value
──────────────────────────────────────────────────────────────────────────────────────────
2026-02-01  AAPL    Cook Timothy D        Chief Executive    50,000      $11.4M
2026-01-28  AAPL    Williams Jeffrey E    Chief Financial    20,000       $4.5M
2026-01-22  AAPL    O'Brien Deirdre       SVP Retail         10,000       $2.3M

Total: 3 trades

Filtering and Sorting

You can extend the script with a few small additions to find the most interesting trades.

Find the largest buys

Sort trades by value to find the biggest purchases:

Python
# Sort by total value, largest first
trades = fetch_trades(days=30)
trades.sort(key=lambda t: t["value"], reverse=True)
print_trades(trades[:10], "Top 10 Largest Insider Buys (last 30 days)")

Filter by insider title

Focus on C-suite executives or board directors:

Python
# Only show trades by CEOs, CFOs, and Directors
trades = fetch_trades(days=30)
key_titles = ["ceo", "cfo", "chief executive", "chief financial", "director"]
filtered = [
    t for t in trades
    if any(kw in t.get("owner_title", "").lower() for kw in key_titles)
]
print_trades(filtered, "C-Suite & Director Buys (last 30 days)")

Combine both

Find the largest C-suite purchases -- these are the strongest insider signals:

Python
trades = fetch_trades(days=30)
key_titles = ["ceo", "cfo", "chief executive", "chief financial"]
csuite = [t for t in trades if any(kw in t.get("owner_title", "").lower() for kw in key_titles)]
csuite.sort(key=lambda t: t["value"], reverse=True)
print_trades(csuite[:10], "Top C-Suite Buys (last 30 days)")

Enhancements

Here are some ways to extend the scanner:

  • Save to CSV -- Add --csv output.csv flag to export trades for further analysis in Excel or Google Sheets. Use Python's built-in csv module.
  • Track specific insiders -- Keep a list of notable insiders (e.g., well-known activist investors or successful CEO-buyers) and alert when they make new purchases.
  • Combine with company profile -- Use the /v1/company/{ticker} endpoint to add market cap and sector to each trade, helping you assess whether the buy is significant relative to the company's size.
  • Historical analysis -- Track insider buys over time and compare against subsequent stock performance. Use --days 90 to gather a larger dataset.
  • Email alerts -- Run the script on a schedule with a cron job and send an email when new large buys appear. See the SEC Filing Alert Email tutorial for an email notification pattern you can adapt.

Insider buying is just one data point. Always do your own research before making investment decisions. Combine insider activity with financial analysis (see the Financial Statement Analyzer tutorial) for a more complete picture.

Ready to build?

Get your free API key and start coding in minutes.

Get Free API Key