スキル一覧に戻る
spinbris

bdc-xbrl-extraction

by spinbris

0🍴 0📅 2026年1月18日
GitHubで見るManusで実行

SKILL.md


name: bdc-xbrl-extraction description: Extract Schedule of Investments data from BDC 10-K/10-Q filings using XBRL taxonomy. Covers BOTH debt investments (senior secured loans, subordinated debt, etc.) AND equity investments (common stock, preferred, warrants, LLC units). Extracts from SEC Reg S-X Schedules 12-12 (unaffiliated) and 12-13 (affiliated). Use when extracting portfolio holdings, investment positions, fair values, loan data, or company-level data from Business Development Company SEC filings. Triggers on: BDC portfolio extraction, Schedule of Investments parsing, investment company holdings analysis, private credit portfolio data, loan book analysis.

BDC Schedule of Investments Extraction

Extract structured portfolio data from Business Development Company SEC filings.

Overview

BDCs file a Consolidated Schedule of Investments in 10-K/10-Q containing:

  • Debt Investments: Senior secured loans, subordinated debt, mezzanine, unitranche
  • Equity Investments: Common stock, preferred stock, warrants, LLC/LP units

Data comes from SEC Reg S-X Article 12:

  • Schedule 12-12: Investments in Securities of Unaffiliated Issuers
  • Schedule 12-13: Investments in and Advances to Affiliates

All use Inline XBRL (required since Aug 2022) with the US GAAP Investment Company Taxonomy.

Validated Results

Tested and validated on 4 major BDCs (Jan 2025):

BDCTickerDebtEquityTotal FVStatus
Ares CapitalARCC1,239427$35.6B
Main Street CapitalMAIN452204$5.4B
FS KKR CapitalFSK541153$19.9B
Hercules CapitalHTGC261258$7.3B
Total2,4931,042$68.2B

Critical Implementation Notes

1. Data is Split Across Multiple Statements

SOI data is NOT in one clean table. It's distributed across:

  • Schedule of Investments → Interest rates, spreads, maturity dates
  • Balance Sheet → Fair values
  • Balance Sheet Parenthetical → Cost basis

Must query all statements and join by investment ID.

2. Investment IDs are in Context Dimensions

Investment identifiers are NOT in fact values. They're in XBRL context dimensions:

# WRONG - won't find IDs
facts_df['investment_id']  # Doesn't exist as column

# CORRECT - access via contexts
context_ref = fact['context_ref']
dimensions = xbrl.contexts[context_ref].dimensions
investment_id = dimensions.get('InvestmentIdentifierAxis')

3. Namespace Prefixes Vary - Always Normalize

Different BDCs use different namespace prefixes:

  • us-gaap:InvestmentOwnedAtFairValue
  • InvestmentOwnedAtFairValue (no prefix)
  • arcc:CustomElement

Always strip namespace when matching:

def normalize_concept(concept: str) -> str:
    """Strip namespace prefix for consistent matching."""
    if not concept:
        return concept
    if ':' in concept:
        return concept.split(':', 1)[1]
    return concept

4. Classification Rate is 67-81%

Not all positions classify cleanly. Expect:

  • 67-81% classified as Debt or Equity
  • 19-33% unclassified (aggregate rollups, sector totals, etc.)

Unclassified positions are typically aggregate dimension members, not individual investments.

Output Structure

{TICKER}_10K_debt_investments.csv      # Loans with rate/maturity data
{TICKER}_10K_equity_investments.csv    # Equity with shares/ownership data  
{TICKER}_10K_affiliated_rollforward.csv # Affiliated investment activity
{TICKER}_10K_portfolio_summary.csv     # Totals by type, industry, affiliation

Quick Start

CLI Usage

python extract_soi.py ARCC --identity "Your Name your@email.com"
python extract_soi.py MAIN 10-Q --identity "Your Name your@email.com"
python extract_soi.py FSK 10-K 2023 --identity "Your Name your@email.com"

Python Usage

from edgar import Company, set_identity

set_identity("Your Name your@email.com")

company = Company("ARCC")
filing = company.get_filings(form="10-K").latest()
xbrl = filing.xbrl()

# Use the extraction functions from extract_soi.py
from extract_soi import extract_all_investments
debt_df, equity_df, affiliated_df, summary_df = extract_all_investments(xbrl)

Key XBRL Elements

Core Elements (Both Debt and Equity)

FieldElement (no namespace)Description
Fair ValueInvestmentOwnedAtFairValueCurrent fair value
CostInvestmentOwnedAtCostAmortized cost basis
% Net AssetsInvestmentOwnedPercentOfNetAssetsPosition size

Debt-Specific Elements

FieldElementDescription
PrincipalInvestmentOwnedBalancePrincipalAmountOutstanding principal
Interest RateInvestmentInterestRateStated rate
SpreadInvestmentBasisSpreadVariableRateSpread over base
FloorInvestmentInterestRateFloorRate floor
PIK RateInvestmentInterestRatePaidInKindPIK component
MaturityInvestmentMaturityDateDue date

Equity-Specific Elements

FieldElementDescription
SharesInvestmentOwnedBalanceSharesShares/units held

Extensible Enumerations

FieldElementNotes
Issuer NameInvestmentIssuerNameExtensibleEnumerationPortfolio company
Investment TypeInvestmentTypeExtensibleEnumerationLoan type, stock class
IndustryInvestmentIndustrySectorExtensibleEnumerationSector
AffiliationInvestmentIssuerAffiliationExtensibleEnumerationAffiliated/Unaffiliated
Rate TypeInvestmentVariableInterestRateTypeExtensibleEnumerationSOFR, Prime, etc.

Investment ID Format Examples

Investment IDs from context dimensions vary by BDC:

# ARCC format
"Actfy Buyer, Inc., First lien senior secured loan"
"ABC Company, Class A common stock"

# MAIN format  
"XYZ Holdings LLC - Senior Secured Term Loan"
"Portfolio Co Inc - Common Equity"

# FSK format
"Company Name | First Lien Term Loan | SOFR+500"

Entity resolution will require fuzzy matching or normalization.

Debt vs Equity Classification

The script classifies using multiple signals:

  1. Investment Type Keywords

    • Debt: loan, debt, note, bond, credit, mezzanine, senior, subordinated
    • Equity: stock, equity, share, warrant, unit, membership, preferred, common
  2. Field Presence

    • Has Principal + no Shares → Debt
    • Has Shares + no Principal → Equity
  3. Investment Type Axis (for totals)

    • DebtSecuritiesMember
    • EquitySecuritiesMember

Common Issues & Solutions

"No Schedule of Investments facts found"

Cause: Querying wrong concepts or not accessing contexts correctly

Solution:

  1. Query all facts, filter by normalized concept name
  2. Access investment IDs from xbrl.contexts[context_ref].dimensions

"Namespace prefix issues"

Cause: Concept has us-gaap: prefix in some filings, not others

Solution: Always use normalize_concept() to strip prefixes

"Low classification rate"

Cause: Aggregate dimension members (sector totals, rollups) aren't individual investments

Solution: This is expected. Focus on classified positions for analysis.

"Investment ID parsing"

Cause: ID formats vary widely across BDCs

Solution: For entity resolution/overlap analysis, will need:

  • Fuzzy matching
  • Company name normalization
  • Possibly LEI/CIK lookup

Data Quality Expectations

Based on testing across 4 BDCs:

MetricExpected Coverage
Fair Value100%
Cost Basis97-100%
Principal (debt)70-75%
Shares (equity)25-30%
Interest Rate65-70%
Classification Rate67-81%

See Also

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です