live

Regulatory Lens

A unified regulatory intelligence engine: from raw SEC Form ADV and 13F bulk data ingestion, to a SQLite relational store, a local FastMCP tool server, and fine-tuned LLM models.

UPDATED
6/3/2026
STATUS
LIVE
STACK
Astro, Python, FastMCP, SQLite, PostgreSQL, FastAPI, QLoRA / TinyLlama, SEC regulatory data

Investment adviser intelligence lives in separate SEC data universes that never talk to each other. This project brings them together—building a unified ingestion pipeline, a SQLite relational store, a FastMCP tool server, and local AI models trained directly on the dataset.


The Core Fragmentation of SEC Filings

For allocators, compliance teams, and analysts, researching an investment adviser means navigating a fragmented regulatory landscape. The SEC publishes three distinct datasets, each running on separate schedules and in separate formats:

  1. Form ADV Part 1: Structured registration data (Item 5 assets/clients, Item 9 custody flags, and Item 11 disciplinary yes/no flags).
  2. Form ADV Part 2A (Brochures): Plain-English narrative PDFs covering fees, conflicts of interest, and detailed disciplinary disclosures (Item 9).
  3. Form 13F: Quarterly tab-separated (TSV) filings disclosing long US equity holdings for managers managing over $100 million.

Stitching these together manually takes substantial time. Furthermore, none of this data is structured for AI agents (like Claude or Cursor) to query directly. We resolved this by building a unified data engine and local AI Studio.


1. Methodology: Relational Entity Resolution

At the core of the system is a unified relational model built on SQLite (for local-first speed) and Postgres (for production). The primary link between these filings is the Central Registration Depository (CRD) number.

┌────────────────────────────────────────────────────────┐
│                        Firms                           │
├────────────────────────────────────────────────────────┤
│ crd_number (PK)        │ legal_name                    │
│ sec_number             │ business_name                 │
│ total_aum              │ office_state                  │
│ client_types (JSON)    │ advisory_activities (JSON)    │
└────────────────────────┬───────────────────────────────┘

        ┌────────────────┼────────────────┐
        ▼                ▼                ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Disclosures  │ │Private Funds │ │  Firm CIKs   │
├──────────────┤ ├──────────────┤ ├──────────────┤
│ crd_number FK│ │crd_number FK │ │crd_number PK │
│ question_item│ │fund_name     │ │cik           │
│ answer (bool)│ │gross_assets  │ └──────┬───────┘
└──────────────┘ └──────────────┘        │

                             ┌──────────────────────┐
                             │   13F Submissions    │
                             ├──────────────────────┤
                             │ accession_number (PK)│
                             │ cik (FK)             │
                             │ crd_number (FK)      │
                             └──────────┬───────────┘


                             ┌──────────────────────┐
                             │     13F Holdings     │
                             ├──────────────────────┤
                             │ accession_number (FK)│
                             │ issuer_name          │
                             │ value_usd            │
                             └──────────────────────┘

Resolving Entity Identifiers

  • FilingID to CRD Mapping: Every ADV filing contains a unique FilingID mapping to a firm’s crd_number. Across 788,478 historical filings, we determine the latest (maximum) FilingID for each of the 49,574 distinct advisers and load only conformed latest records to prevent historical duplication.
  • CRD-to-CIK Cross-Walk: CIKs (Central Index Keys) are required for 13F filings, while CRDs are used for ADV. By extracting FilingID -> CRD from base filings and FilingID -> CIK from specialized CIK files (IA_1D3_CIK and ERA_1D3_CIK), we map 5,554 adviser CRDs to their conformed CIKs.

2. Data Collection & Ingestion Pipeline

To ingest the SEC’s bulk data sets politely and robustly, we implemented a custom Python pipeline:

  • Rate-Limiting & Compliance: All network crawlers declare a structured User-Agent header (declaring organization name and contact email) to comply with the SEC fair-use policy, and enforce rate limits.
  • WAL-Mode Streaming: A single quarter of Form 13F holdings contains over 3.4 million records. To load these under low-memory constraints, the parser streams TSV datasets in 10,000-row chunks using SQLite’s Write-Ahead Logging (WAL) and transactional batch inserts.
  • Header Normalization: The SEC’s Form ADV column headers drift slightly between yearly versions (e.g. 5F(2)(c) vs. 5F2c). The parser implements a fuzzy match alias dictionary in pipeline/column_map.py to resolve headers dynamically.
DatasetSource FormatLocal RecordsRaw Size
Form ADV Part 1Bulk CSV (Monthly Zip)49,574 firms1.15 GB
ADV Part 2ANarrative PDFs (ZIP)12,000+ files563 MB
Form 13FTSV (DERA Dataset)6.75M holdings700 MB

3. Building Local AI Training & Multi-Adapter Routing

To automate the review of narrative disciplinary disclosures, we trained a specialized model and integrated it into the workspace:

Instruction-Tuning Dataset

We compiled a dataset of 250 high-quality instruction-tuning pairs by extracting narrative text from firm_brochures.item_9 (covering SEC, state, and civil court disciplinary events) and generating structured summary targets covering:

  1. What the case/event is.
  2. Who or what entities were mentioned.
  3. What penalties were imposed.

QLoRA Fine-Tuning

Using PEFT (Parameter-Efficient Fine-Tuning) and BitsAndBytes, we loaded a base TinyLlama-1.1B chat model in 4-bit NF4 quantization to minimize memory overhead. The specialized adapter was trained locally on our GPU across 3 epochs, outputting LoRA weights to models/tinyllama-adv-drp-qlora/ with a VRAM footprint of just 4.3 GB.

Dynamic PEFT Multi-Adapter Router

To avoid loading multiple large models into GPU memory, we implemented a dynamic router in the FastAPI backend (dashboard/app.py). Using PEFT’s adapter switching capability, we host two specialized adapters on top of a single quantized base model instance:

  • adv_lora: General Form ADV regulatory questions.
  • drp_lora: Specialized brochure disciplinary summaries (Item 9 DRPs).

During inference, requests are routed to the target adapter on-the-fly, allowing instant model toggling with zero switching latency and zero additional VRAM cost.


4. Interactive Features & Workspaces

We built two high-fidelity workspaces that connect directly to your local FastAPI backend server:

A. The Search & Portfolio Dashboard (app.html)

A glassmorphic, visual interface that displays:

  • Advanced Filters: Filter by registration status (SEC Registered IA or Exempt Reporting Adviser), office state, and sort by AUM.
  • Firm Profile Cards: Show CCO details, employee count, website, and conformed CIK.
  • AUM Breakdown: Interactive progress bar separating discretionary and non-discretionary assets.
  • 13F Portfolio Breakdown: A Chart.js doughnut chart visualizing portfolio concentration, paired with a sortable holdings table showing security names, CUSIPs, share counts, and dollar values.
  • ADV-AI Disclosures Panel: A summarization widget that runs the locally hosted QLoRA drp_lora adapter model to summarize narrative disciplinary information.

B. The AI Studio Telemetry Dashboard (training.html)

An operational control center that displays:

  • System Telemetry: Real-time monitoring of CPU load, RAM, GPU temperature, and VRAM occupancy.
  • Loss Curve: Interactive Chart.js line plot tracking QLoRA training steps and loss.
  • Process Controller: Buttons to start, pause, or resume training in the background safely.
  • Model Playground: Interactive chat interface to run prompt tests, with sliders for max tokens, temperature, and top-p.

5. Relational Model Context Protocol (MCP) Server

To make this dataset available to external AI clients (like Cursor, Claude Desktop, or custom scripts), the engine exposes the database through FastMCP:

  • search_advisers: Full-text and filter searches across 56K+ registered investment advisers.
  • get_adviser: Fetches full adviser details including client types and advisory activities.
  • get_disclosures: Lists all positive Item 11 disclosures.
  • get_brochure: Retrieves narrative Item 4 through 15 sections from conformed brochures.
  • get_13f_holdings: Returns a list of equity holdings for a specific quarter.
  • query_sql: A read-only SQL escape hatch for ad-hoc custom queries.

Interactive Workspaces

1. Adviser & Portfolio Lookup

Use the live panel below to search adviser profiles, inspect client type breakdowns, view active advisory activities, and browse their latest Form 13F stock portfolios:

2. AI Studio: Model Training Telemetry

If your local backend server is running (ml_env\Scripts\python.exe dashboard/app.py --port 8000), the panel below will stream GPU/VRAM telemetry, render Chart.js loss curves, display the standard output training log stream, and let you test the QLoRA adapter models in the Playground: