Skip to content
Hero Background Light

How to Track Insider Buying: A Practical Guide

How to Track Insider Buying: A Practical Guide

Insider buying is one of the most watched signals in the market. When executives spend their own money to buy their company’s stock, it often signals confidence. Here’s how to track it systematically.

Why Track Insider Buying?

Insiders—CEOs, CFOs, directors, and major shareholders—have deep knowledge of their companies. They know about:

  • Upcoming product launches
  • Contract negotiations
  • Financial performance trends
  • Strategic initiatives

While they can’t trade on material non-public information, their transactions can still provide valuable signals.

The Asymmetry Principle

Insiders sell for many reasons:

  • Diversification
  • Tax obligations
  • Personal expenses
  • Pre-planned 10b5-1 plans

But they buy for one reason: They believe the stock will go up.

This asymmetry makes insider purchases far more informative than sales.

Setting Up Insider Tracking

First, install the FinBrain Python SDK:

Terminal window
pip install finbrain-python pandas

Basic Insider Data Retrieval

from finbrain import FinBrainClient
fb = FinBrainClient(api_key="YOUR_API_KEY")
# Get insider transactions for a ticker
df = fb.insider_transactions.ticker("S&P 500", "AAPL", as_dataframe=True)
print(df.head())
# insiderTradings relationship transaction shares cost USDValue
# date
# 2024-01-15 Tim Cook Chief Executive Officer Sale 50000 185.50 9275000
# Filter for purchases only
purchases = df[df["transaction"].str.contains("Buy", na=False)]
print(f"\nTotal purchases: {len(purchases)}")
print(purchases[["insiderTradings", "relationship", "USDValue"]])

Filtering for Meaningful Signals

Not all insider purchases are equal. Here’s how to filter for the most significant ones.

1. Filter by Transaction Size

Small purchases may be token gestures. Focus on significant positions:

def get_significant_purchases(df, min_value=100000):
"""Filter for purchases above minimum value"""
purchases = df[df["transaction"].str.contains("Buy", na=False)]
significant = purchases[purchases["USDValue"] >= min_value]
return significant.sort_values("USDValue", ascending=False)
# Get purchases over $100K
significant = get_significant_purchases(df, min_value=100000)
print(f"Significant purchases: {len(significant)}")

2. Focus on C-Suite Executives

CEOs, CFOs, and other top executives have the deepest insight:

C_SUITE = [
"chief executive", "ceo",
"chief financial", "cfo",
"chief operating", "coo",
"president", "chairman"
]
def get_c_suite_purchases(df):
"""Filter for C-suite executive purchases"""
purchases = df[df["transaction"].str.contains("Buy", na=False)]
pattern = "|".join(C_SUITE)
c_suite = purchases[
purchases["relationship"].str.lower().str.contains(pattern, na=False)
]
return c_suite
c_suite_buys = get_c_suite_purchases(df)
print(f"C-suite purchases: {len(c_suite_buys)}")

3. Detect Cluster Buying

Multiple insiders buying within a short period is a strong signal:

from datetime import timedelta
def detect_cluster_buying(df, window_days=14, min_buyers=2):
"""Find periods where multiple insiders bought"""
purchases = df[df["transaction"].str.contains("Buy", na=False)]
if purchases.empty:
return []
clusters = []
for date in purchases.index.unique():
window_end = date + timedelta(days=window_days)
window = purchases[(purchases.index >= date) & (purchases.index <= window_end)]
unique_buyers = window["insiderTradings"].nunique()
if unique_buyers >= min_buyers:
clusters.append({
"start_date": date,
"buyers": list(window["insiderTradings"].unique()),
"total_value": window["USDValue"].sum()
})
return clusters
clusters = detect_cluster_buying(df)
for c in clusters:
print(f"Cluster on {c['start_date'].strftime('%Y-%m-%d')}: {len(c['buyers'])} buyers, ${c['total_value']:,.0f}")

Building a Multi-Stock Scanner

Scan your watchlist for insider activity:

def scan_insider_activity(tickers, market="S&P 500", min_value=50000):
"""Scan multiple tickers for recent insider buying"""
fb = FinBrainClient(api_key="YOUR_API_KEY")
results = []
for ticker in tickers:
try:
df = fb.insider_transactions.ticker(market, ticker, as_dataframe=True)
if df.empty:
continue
# Filter for purchases
purchases = df[df["transaction"].str.contains("Buy", na=False)]
significant = purchases[purchases["USDValue"] >= min_value]
if not significant.empty:
results.append({
"ticker": ticker,
"purchase_count": len(significant),
"total_value": significant["USDValue"].sum(),
"unique_buyers": significant["insiderTradings"].nunique(),
"latest_date": significant.index.max()
})
except Exception as e:
continue
# Sort by total value
return sorted(results, key=lambda x: x["total_value"], reverse=True)
# Scan tech stocks
tickers = ["AAPL", "MSFT", "GOOGL", "AMZN", "NVDA", "META", "TSLA"]
results = scan_insider_activity(tickers)
print("=== Insider Buying Scanner ===\n")
for r in results:
print(f"{r['ticker']}: ${r['total_value']:,.0f} from {r['unique_buyers']} buyers")

Creating Alerts

Set up a simple alert system for notable insider activity:

def generate_alerts(results, value_threshold=500000, buyer_threshold=2):
"""Generate alerts for notable insider activity"""
alerts = []
for r in results:
# High value alert
if r["total_value"] >= value_threshold:
alerts.append({
"type": "HIGH_VALUE",
"ticker": r["ticker"],
"message": f"${r['total_value']:,.0f} in insider purchases"
})
# Multiple buyers alert
if r["unique_buyers"] >= buyer_threshold:
alerts.append({
"type": "CLUSTER",
"ticker": r["ticker"],
"message": f"{r['unique_buyers']} different insiders buying"
})
return alerts
alerts = generate_alerts(results)
for alert in alerts:
print(f"[{alert['type']}] {alert['ticker']}: {alert['message']}")

Complete Insider Tracking Script

Here’s a complete script you can run daily:

from finbrain import FinBrainClient
from datetime import datetime, timedelta
class InsiderTracker:
def __init__(self, api_key):
self.fb = FinBrainClient(api_key=api_key)
self.c_suite_keywords = [
"chief executive", "ceo", "chief financial", "cfo",
"chief operating", "coo", "president", "chairman", "director"
]
def is_c_suite(self, relationship):
rel_lower = str(relationship).lower()
return any(kw in rel_lower for kw in self.c_suite_keywords)
def analyze_ticker(self, market, ticker, days=30, min_value=50000):
"""Analyze insider activity for a single ticker"""
try:
df = self.fb.insider_transactions.ticker(market, ticker, as_dataframe=True)
except:
return None
if df.empty:
return None
# Filter recent
cutoff = datetime.now() - timedelta(days=days)
recent = df[df.index >= cutoff]
if recent.empty:
return None
# Purchases only
purchases = recent[recent["transaction"].str.contains("Buy", na=False)]
significant = purchases[purchases["USDValue"] >= min_value]
if significant.empty:
return None
# C-suite purchases
c_suite = significant[significant["relationship"].apply(self.is_c_suite)]
return {
"ticker": ticker,
"total_purchases": len(significant),
"total_value": significant["USDValue"].sum(),
"c_suite_purchases": len(c_suite),
"unique_buyers": significant["insiderTradings"].nunique(),
"top_buyer": significant.loc[significant["USDValue"].idxmax(), "insiderTradings"],
"top_value": significant["USDValue"].max()
}
def scan(self, tickers, market="S&P 500"):
"""Scan multiple tickers"""
results = []
for ticker in tickers:
result = self.analyze_ticker(market, ticker)
if result:
results.append(result)
return sorted(results, key=lambda x: x["total_value"], reverse=True)
# Run the tracker
tracker = InsiderTracker(api_key="YOUR_API_KEY")
watchlist = [
"AAPL", "MSFT", "GOOGL", "AMZN", "NVDA", "META", "TSLA",
"JPM", "BAC", "GS", "V", "MA",
"JNJ", "PFE", "UNH", "ABBV"
]
print(f"Scanning {len(watchlist)} stocks for insider buying...\n")
results = tracker.scan(watchlist)
print("=== INSIDER BUYING DETECTED ===\n")
for r in results:
print(f"{r['ticker']}")
print(f" Total: ${r['total_value']:,.0f} from {r['unique_buyers']} buyers")
print(f" C-Suite purchases: {r['c_suite_purchases']}")
print(f" Top buyer: {r['top_buyer']} (${r['top_value']:,.0f})")
print()

Key Takeaways

  1. Focus on purchases, not sales—the asymmetry principle
  2. Filter by transaction size ($100K+ is meaningful)
  3. Weight C-suite purchases more heavily
  4. Cluster buying (multiple insiders) is a strong signal
  5. Scan regularly and set up alerts for notable activity

Start tracking insider buying with the Insider Transactions Dataset and API Reference.