# SEC 13D/13G Activist Investor Tracking

> Shipped 2026-05-17. Migration 242.

## Overview

Comprehensive activist investor tracking system that monitors SEC 13D/13G filings to detect:
- Activist investors taking positions (>5% ownership)
- Intent signals (13D = activist intent, 13G = passive)
- Position changes (accumulating, reducing, closing)
- Active campaigns (proxy fights, board seats, etc.)

## Architecture

```
packages/be/src/activist/
├── types.ts          # TypeScript interfaces
├── repository.ts     # Database CRUD
├── sec-fetcher.ts    # SEC EDGAR RSS fetcher
├── service.ts        # Business logic
├── dsl-wrappers.ts   # DSL primitive implementations
└── index.ts          # Module exports
```

## Database Tables (Migration 242)

| Table | Purpose |
|-------|---------|
| `predict.activist_filers` | Investment managers (CIK, name, style, is_known_activist) |
| `predict.activist_filings` | Per-filing records (13D/13G, shares, ownership %) |
| `predict.activist_positions` | Current positions per filer per symbol |
| `predict.activist_campaigns` | Active campaigns (proxy fights, board seats) |
| `predict.activist_alerts` | Generated alerts for watchlist symbols |
| `predict.activist_sync_status` | Sync job tracking |

### Known Activists (Seeded)

The migration seeds 10 well-known activist investors:
- Carl Icahn (Icahn Enterprises)
- Bill Ackman (Pershing Square)
- Dan Loeb (Third Point)
- Nelson Peltz (Trian Partners)
- Jeffrey Smith (Starboard Value)
- Paul Singer (Elliott Management)
- Barry Rosenstein (JANA Partners)
- Jeff Ubben (ValueAct Capital)
- David Einhorn (Greenlight Capital)
- Seth Klarman (Baupost Group)

## SEC EDGAR Integration

### Filing Types

| Form | Description | Signal |
|------|-------------|--------|
| **13D** | Activist intent - plans to influence management | Strong |
| **13D/A** | Amendment to 13D | Position change |
| **13G** | Passive investor (>5% ownership, no control intent) | Weak |
| **13G/A** | Amendment to 13G | Position change |

### Data Sources

- **RSS Feed**: `https://www.sec.gov/cgi-bin/browse-edgar?action=getcurrent&type=13D&output=atom`
- **Filing Details**: Parsed from primary XML document
- **Rate Limiting**: 1 request/second (SEC fair use policy)

### CUSIP Resolution

SEC filings use CUSIP identifiers. Resolution order:
1. OpenFIGI API (free, 25 req/min)
2. Internal CUSIP→Symbol mapping table
3. Company name fallback

## DSL Primitives

7 primitives for AI Algorithm Builder:

| Primitive | Returns | Description |
|-----------|---------|-------------|
| `has_activist_position(symbol)` | boolean | Any activist with >5% position |
| `activist_ownership_pct(symbol)` | number | Total activist ownership % |
| `activist_count(symbol)` | number | Number of activist investors |
| `has_13d_activist(symbol)` | boolean | True if 13D filer (activist intent) |
| `is_activist_accumulating(symbol)` | boolean | Activists increasing positions |
| `largest_activist_position(symbol)` | number | Largest single activist stake % |
| `active_campaign_count(symbol)` | number | Active campaigns (proxy fights, etc.) |

### Example Algorithm DSL

```
entry:
  has_13d_activist('SYMBOL') AND
  is_activist_accumulating('SYMBOL') AND
  largest_activist_position('SYMBOL') > 5

exit:
  NOT has_activist_position('SYMBOL') OR
  activist_ownership_pct('SYMBOL') < 3
```

## API Endpoints

| Route | Method | Auth | Description |
|-------|--------|------|-------------|
| `/activist/[symbol]` | GET | Optional | Symbol activist summary |
| `/activist/[symbol]/alerts` | GET | Optional | Symbol alerts |
| `/activist/filers` | GET | Optional | Search filers |
| `/activist/filers/[cik]` | GET | Optional | Filer portfolio |
| `/activist/known` | GET | Optional | Known activists list |
| `/activist/activity` | GET | Optional | Recent activity |
| `/activist/campaigns` | GET | Optional | Active campaigns |
| `/admin/activist/sync` | POST | Admin | Trigger manual sync |
| `/admin/activist/sync` | GET | Admin | Sync status |

### Response Examples

**GET /activist/AAPL**
```json
{
  "symbol": "AAPL",
  "totalActivistOwnership": 2.3,
  "activistCount": 1,
  "has13dFiler": true,
  "activeCampaigns": 0,
  "positions": [
    {
      "filerName": "Example Activist",
      "ownershipPct": 2.3,
      "sharesOwned": 372000000,
      "formType": "13D",
      "filingDate": "2026-03-15"
    }
  ]
}
```

## Scheduler Jobs

| Job | Interval | Description |
|-----|----------|-------------|
| `sync-activist-filings` | 24h | Sync recent 13D/13G filings from SEC |
| `check-activist-alerts` | 6h | Generate alerts for watchlist symbols |

## Stock Hunter Integration

Activist data is automatically included in Stock Hunter research reports and analysis.

**Data Aggregator** (`packages/be/src/stock-hunter/data-aggregator.ts`):
- `aggregateActivist()` function fetches activist data for US securities
- Skipped for crypto/forex (13D/13G only covers US securities)
- Added to `StockDataBundle.activist` field
- `dataQuality.activistAvailable` flag indicates data availability

**Report Prompts** (`packages/be/src/stock-hunter/report-prompts.ts`):
- New "ACTIVIST INVESTORS (SEC 13D/13G)" section in reports
- Shows activist involvement, ownership %, known activists, campaigns
- Includes largest position and recent activity trend

```typescript
interface ActivistData {
  hasActivistInvolvement: boolean;
  activistCount: number;
  totalActivistOwnership: number;
  knownActivistsPresent: string[];
  has13dFiling: boolean;
  activeCampaigns: Array<{
    activistName: string;
    campaignType: string | null;
    demands: string | null;
  }>;
  recentActivity: 'accumulating' | 'reducing' | 'stable' | 'none';
  largestPosition: { filerName: string; ownershipPct: number } | null;
  dataAge: 'current' | 'stale' | 'unavailable';
}
```

## Caching

DSL primitives use 6-hour cache (TTL) since activist data changes slowly:
- Activists file within 10 days of crossing 5%
- Position changes require new filings
- Daily sync is sufficient for most use cases

## Cost & Performance

- **SEC EDGAR**: Free, no API key, ~1 req/sec rate limit
- **OpenFIGI**: Free tier 25 req/min (CUSIP resolution)
- **Storage**: ~1KB per filing, ~100 bytes per position
- **Query Performance**: Indexes on (symbol, filer_id, filing_date)

## Smoke Test Status (2026-05-18)

| Check | Status | Notes |
|-------|--------|-------|
| TypeScript Compilation | ✅ PASS | All packages compile |
| Migration Syntax | ✅ PASS | Migration 242 valid SQL |
| API Routes Created | ✅ PASS | 7 routes configured |
| Scheduler Jobs Registered | ✅ PASS | Daily sync + 6-hour alert check |
| DSL Primitives Wired | ✅ PASS | 7 primitives in evaluator + executor |
| Known Activists Seeded | ✅ PASS | 10 activists in migration |
| Stock Hunter Integration | ✅ PASS | ActivistData in StockDataBundle |

## Verification Checklist

1. **Migration**: `\dt predict.activist_*` to verify tables
2. **Known Activists**: `SELECT * FROM predict.activist_filers WHERE is_known_activist = true`
3. **API**: `GET /api/predict/v1/activist/AAPL`
4. **DSL**: Test algorithm with `has_13d_activist('AAPL')`
5. **Scheduler**: Check logs for `[Scheduler] Activist sync:`

## Comparison: 13F vs 13D/13G

| Feature | 13F (Institutional) | 13D/13G (Activist) |
|---------|---------------------|---------------------|
| Threshold | $100M AUM | 5% ownership |
| Filing Deadline | 45 days after quarter | 10 days after crossing |
| Intent Disclosure | No | Yes (13D only) |
| Update Frequency | Quarterly | Event-driven |
| Signal Strength | Weak (lagging) | Strong (timely) |

## Related Documentation

- `docs/75-institutional-holdings.md` - SEC 13F institutional tracking
- `docs/12-algorithm-builder.md` - DSL primitive integration
- `docs/24-api-routes.md` - Full API reference
