SEC 13-F Data Format and Structure
SkillDev toolsUnderstanding SEC 13-F filing data structure, TSV format, and key tables for hedge fund analysis
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the SEC 13-F Data Format and Structure skill
What this skill tells your AI
The instructions your AI receives, as published by cxcscmu/skilllearnbench in skills/b1-one-shot-claude-haiku-4-5/financial-analysis/sec13f-data-format/SKILL.md and read by ahel’s review.
Overview
SEC 13-F filings provide quarterly snapshots of large institutional investment holdings. The data is distributed as tab-separated value (TSV) files organized by reporting quarters.
Key Data Files
COVERPAGE.tsv
Purpose: Fund/Manager information and filing metadata Key Columns:
ACCESSION_NUMBER: Unique identifier for the filing (use to link with holdings)FILINGMANAGER_NAME: Name of the fund or investment managerREPORTCALENDARORQUARTER: Reporting date (e.g., "30-JUN-2025")DATEREPORTED: When the filing was reportedREPORTTYPE: Type of 13-F report
Usage Example:
import pandas as pd
# Load fund information
coverpage = pd.read_csv('/root/2025-q3/COVERPAGE.tsv', sep='\t')
# Find a specific fund by name
fund_info = coverpage[coverpage['FILINGMANAGER_NAME'].str.contains('Renaissance', case=False, na=False)]
accession_number = fund_info['ACCESSION_NUMBER'].values[0]
INFOTABLE.tsv
Purpose: Detailed holdings data for all funds Key Columns:
ACCESSION_NUMBER: Links to the fund (from COVERPAGE)NAMEOFISSUER: Company name of the stockCUSIP: Committee on Uniform Security Identification Procedures code (unique stock identifier)VALUE: Market value of holdings in thousands (USD)SSHPRNAMT: Number of shares held (integer)SSHPRNAMTTYPE: Share amount type (usually "SH" for shares)
Usage Example:
# Load all holdings
holdings = pd.read_csv('/root/2025-q3/INFOTABLE.tsv', sep='\t')
# Get holdings for a specific fund
fund_holdings = holdings[holdings['ACCESSION_NUMBER'] == 'specific_accession_number']
# Get count of stocks held
stock_count = len(fund_holdings)
# Find a specific stock
palantir = holdings[holdings['NAMEOFISSUER'].str.contains('PALANTIR', case=False, na=False)]
SUMMARYPAGE.tsv
Purpose: Summary-level information per fund Key Columns:
ACCESSION_NUMBER: Fund identifierTABLE_OF_CONTENTS: Summary metadata- Other aggregate information
Data Characteristics
Value Representation
- All monetary values in INFOTABLE are in thousands of USD
- To get actual dollar value:
actual_value = VALUE_FROM_TSV * 1000 - Share counts are exact integers
Date Formats
- Dates typically in format "DD-MMM-YYYY" (e.g., "30-JUN-2025")
- Convert using:
pd.to_datetime(df['date_column'], format='%d-%b-%Y')
Data Types
# Common data type conversions
df['VALUE'] = pd.to_numeric(df['VALUE'], errors='coerce')
df['SSHPRNAMT'] = pd.to_numeric(df['SSHPRNAMT'], errors='coerce')
df['CUSIP'] = df['CUSIP'].astype(str)
Loading and Initial Data Exploration
import pandas as pd
def load_13f_data(quarter_path):
"""Load all 13-F data for a quarter"""
return {
'coverpage': pd.read_csv(f'{quarter_path}/COVERPAGE.tsv', sep='\t'),
'infotable': pd.read_csv(f'{quarter_path}/INFOTABLE.tsv', sep='\t'),
'summarypage': pd.read_csv(f'{quarter_path}/SUMMARYPAGE.tsv', sep='\t')
}
# Usage
q2_data = load_13f_data('/root/2025-q2')
q3_data = load_13f_data('/root/2025-q3')
# Find number of unique funds
num_funds = q3_data['coverpage']['ACCESSION_NUMBER'].nunique()
print(f"Number of unique funds in Q3: {num_funds}")
Common Analysis Patterns
Get Fund AUM (Assets Under Management)
AUM is typically found in SUMMARYPAGE.tsv:
summarypage = q3_data['summarypage']
# Look for AUM-related fields (may vary by filing)
Get Fund Holdings Count
fund_accession = 'specific_accession_number'
fund_holdings = q3_data['infotable'][q3_data['infotable']['ACCESSION_NUMBER'] == fund_accession]
num_holdings = len(fund_holdings)
Cross-Quarter Comparison
# Get same fund's holdings from two quarters
q2_holdings = q2_data['infotable'][q2_data['infotable']['ACCESSION_NUMBER'] == accession]
q3_holdings = q3_data['infotable'][q3_data['infotable']['ACCESSION_NUMBER'] == accession]
# Merge and compare
comparison = pd.merge(
q2_holdings[['CUSIP', 'VALUE', 'SSHPRNAMT', 'NAMEOFISSUER']],
q3_holdings[['CUSIP', 'VALUE', 'SSHPRNAMT']],
on='CUSIP',
suffixes=('_q2', '_q3'),
how='outer'
).fillna(0)
# Calculate changes
comparison['value_change'] = comparison['VALUE_q3'] - comparison['VALUE_q2']
comparison = comparison.sort_values('value_change', ascending=False)
Notes
- ACCESSION_NUMBER is the critical linking key between all tables
- CUSIP is the universal stock identifier
- Multiple funds can have the same stock in their portfolios
- Data is case-sensitive in some fields, use
.str.lower()orstr.contains(..., case=False)for case-insensitive matching
Signals
- GitHub stars
- 83
- Forks
- 5
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
sec13f-data-format- Source
- github.com/cxcscmu/skilllearnbench