agentsclimarketplace

Run2 13f data analysis

Skill cxcscmu/SkillLearnBench/skills/b2-self-feedback-claude-opus-4-6/financial-analysis/run2_13f-data-analysis

Comprehensive guide for analyzing SEC 13-F quarterly filings data (TSV format) including fund lookup, AUM, holdings comparison, and stock investor analysis.From its SKILL.md

Install
npx -y skills add cxcscmu/SkillLearnBench --skill run2_13f-data-analysis

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

3.0 KB, 814 tokens by cl100k_base, as published. Nobody here has run it

SEC 13-F Data Analysis (Improved)

Data Files

Each quarter folder contains TSV files:

FilePurposeKey Columns
COVERPAGE.tsvFund manager metadataACCESSION_NUMBER, FILINGMANAGER_NAME
INFOTABLE.tsvIndividual stock holdings (~300MB)ACCESSION_NUMBER, NAMEOFISSUER, CUSIP, VALUE (x1000), SSHPRNAMT (shares)
SUMMARYPAGE.tsvAggregate stats per filingACCESSION_NUMBER, TABLEENTRYTOTAL, TABLEVALUETOTAL (x1000)

Important Notes

  • VALUE is in thousands of dollars — multiply by 1000 for actual dollar amounts
  • TABLEVALUETOTAL is also in thousands in SUMMARYPAGE
  • CUSIP casing: INFOTABLE may have mixed-case CUSIPs (e.g., 69608A108 vs 69608a108). Always normalize: df['CUSIP'] = df['CUSIP'].str.upper()
  • Multiple accession numbers: A single filer (e.g., Berkshire Hathaway) may have multiple filings. Use SUMMARYPAGE to identify the main one (largest TABLEVALUETOTAL).
  • Low memory: INFOTABLE is large. Use low_memory=False or specify dtype={'CUSIP': str}.

Workflow Patterns

1. Fuzzy Search for a Fund

from difflib import SequenceMatcher
cover = pd.read_csv('COVERPAGE.tsv', sep='\t', dtype=str)
cover['score'] = cover['FILINGMANAGER_NAME'].apply(
    lambda x: SequenceMatcher(None, search.lower(), str(x).lower()).ratio()
)
best = cover.sort_values('score', ascending=False).iloc[0]
accession = best['ACCESSION_NUMBER']

2. Get AUM (from SUMMARYPAGE)

summary = pd.read_csv('SUMMARYPAGE.tsv', sep='\t')
row = summary[summary['ACCESSION_NUMBER'] == accession]
aum_thousands = row['TABLEVALUETOTAL'].values[0]

3. Get Number of Holdings

Use TABLEENTRYTOTAL from SUMMARYPAGE or count unique CUSIPs from INFOTABLE (usually identical).

4. Compare Holdings Across Quarters

q2_h = info_q2[info_q2['ACCESSION_NUMBER']==acc_q2].groupby('CUSIP')['VALUE'].sum()
q3_h = info_q3[info_q3['ACCESSION_NUMBER']==acc_q3].groupby('CUSIP')['VALUE'].sum()
diff = q3_h.subtract(q2_h, fill_value=0).sort_values(ascending=False)
top5_increased = diff.head(5).index.tolist()  # CUSIPs

5. Find Top Investors for a Stock

# Find CUSIP by issuer name
matches = info[info['NAMEOFISSUER'].str.contains('NAME', case=False, na=False)]
cusip = matches['CUSIP'].str.upper().mode()[0]
# Aggregate by filing
holders = info[info['CUSIP'].str.upper()==cusip].groupby('ACCESSION_NUMBER')['VALUE'].sum()
top = holders.sort_values(ascending=False).head(3)
# Map to names via COVERPAGE

Disambiguation Tips

  • When multiple accession numbers match the same filer, the one with higher TABLEVALUETOTAL or more TABLEENTRYTOTAL is typically the main 13F-HR filing.
  • Some funds file separate confidential treatment requests — filter by ISCONFIDENTIALOMITTED='N' if needed.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.