Skip to content

Trustee Tapes

Trustee tapes are periodic statement files from deal trustees containing loan-level portfolio data. They are the authoritative source of record for a CLO's portfolio composition and serve as the basis for reconciliation against the manager's internal books.


Upload Process

Supported Formats

Trustee tapes are uploaded as Excel files. The system:

  1. Validates the file format and structure
  2. Parses using trustee-specific normalization rules
  3. Extracts loan-level data (CUSIP, par, price, ratings, spread)
  4. Stores normalized data for reconciliation

File Requirements

Requirement Detail
Format Excel (.xlsx)
Max Size 100MB
Required Fields CUSIP or ISIN, par value
Statement Date Must be provided at upload

Trustee-Specific Parsing

Each trustee has distinct file layouts. The parser normalizes all formats into a common loan schema using the alias profile system.

US Bank

Standard CLO trustee report format with: - Loan identifier columns (CUSIP, LoanX ID) - Financial data (par, price, spread, rates) - Rating columns (Moody's, S&P, Fitch) - Borrower and industry classification

Deutsche Bank

European trustee format with: - ISIN-based identification - Spread and rate conventions - Industry and country mappings

Wilmington Trust

US trustee format similar to US Bank with: - Customized column naming - Additional reference fields

BNY Mellon

US trustee format with: - "Current Par" naming convention for par value - Abbreviated rating column headers ("Mdy", "S&P") - Borrower-centric naming

European Trustee Support

CalcBridge is expanding trustee support to include BNP Paribas and HSBC for European CLO coverage. See Regional Differences for details on European trustee format variations.


Loan Data Model

Each parsed loan includes:

Field Description
cusip CUSIP identifier
isin ISIN identifier (European CLOs)
loanx_id LoanX identifier
borrower_name Borrower name
par_value Par (face) value
price Current price
rating_moodys Moody's rating
rating_sp S&P rating
rating_fitch Fitch rating
spread Spread (basis points)
base_rate Base rate (e.g., SOFR)
all_in_rate Total interest rate
maturity_date Loan maturity date
industry Industry classification
country Country of domicile
days_past_due Days past due

Data Field Reference

This section provides a comprehensive reference for every field that appears in trustee tapes, grouped by the compliance tests they feed into. Use this reference when building parsers, configuring alias profiles, or debugging reconciliation discrepancies.

Loan Identification Fields

These fields uniquely identify a loan position within the portfolio.

Field Description Example Used In
CUSIP 9-character US identifier (issuer + issue + check digit) 12345ABC9 All tests -- primary key for US CLOs
ISIN 12-character international identifier (country + CUSIP/NSIN + check) US12345ABC90 All tests -- primary key for European CLOs
LoanX ID LoanX/Markit unique loan identifier LX123456 Cross-referencing with market data
Loan Name Obligor and facility description Acme Corp TL-B Concentration tests, reporting
Obligor Legal borrower entity name Acme Corporation Single obligor concentration test
Obligor ID Unique identifier for the borrower entity OBL-12345 Obligor deduplication across facilities
Industry Moody's 33-industry or S&P GICS code Banking & Finance Industry concentration test
Country Domicile of the obligor US or DE Geographic concentration test
Facility Type Type of loan facility TL-B Eligibility criteria, second lien test
Seniority Lien position (first lien, second lien) First Lien Second lien concentration test
Agent Bank Administrative agent for the loan JPMorgan Chase Reference data reconciliation

CUSIP vs ISIN

US CLOs use CUSIP as the primary identifier. European CLOs use ISIN. Some European tapes include both, but many include only ISIN. CalcBridge's loan matching must support either identifier, falling back from CUSIP to ISIN when CUSIP is not available.

# Loan matching priority
def match_loan(tape_loan, internal_loan):
    if tape_loan.cusip and internal_loan.cusip:
        return tape_loan.cusip == internal_loan.cusip
    elif tape_loan.isin and internal_loan.isin:
        return tape_loan.isin == internal_loan.isin
    elif tape_loan.loanx_id and internal_loan.loanx_id:
        return tape_loan.loanx_id == internal_loan.loanx_id
    else:
        # Fuzzy match on name + maturity as last resort
        return fuzzy_match(tape_loan, internal_loan)

Financial Fields (OC/IC Tests)

These fields feed directly into overcollateralisation and interest coverage calculations. They are the most reconciliation-sensitive fields -- even small discrepancies can affect compliance test results.

Field Description Example Used In
Par Value Face value of the position $5,000,000 OC numerator, concentration denominators
Current Balance Outstanding principal (may differ from par if amortising) $4,800,000 Amortisation tracking, OC adjustments
Purchase Price Price paid as percentage of par 98.5 Discount obligation tracking
Market Price Current secondary market trading price 95.25 CCC haircut calculation, mark-to-market
Spread Credit spread over base rate (in basis points) SOFR+350 WAS test, IC numerator
Coupon Total interest rate (base rate + spread) 8.85% IC test numerator
Accrued Interest Unpaid interest since last payment date $12,500 IC numerator component
Principal Payments Scheduled and unscheduled principal received $200,000 Cash flow tracking, amortisation
Interest Payments Interest received since last period $110,625 IC actual vs projected
Recovery Rate Estimated recovery for defaulted assets 50% Defaulted asset valuation in OC
Market Value Par value multiplied by market price $4,762,500 Mark-to-market reporting
Floor Interest rate floor on the loan 1.00% All-in-rate calculation
PIK Amount Payment-in-kind interest added to principal $25,000 OC tracking (PIK increases par)

OC Test Calculation

The OC test uses par value (not market value) in its standard formulation:

OC Ratio = Adjusted Collateral Balance / Tranche Outstanding Balance

Adjusted Collateral Balance =
    Sum of all loan par values
  - Defaulted asset haircuts
  - CCC excess haircuts (par above the CCC bucket limit, valued at market)
  - Discount obligations (if purchase price < threshold)
  + Principal cash

Discrepancies in par value directly affect the OC numerator. A $500K par value difference on a $500M portfolio is only 0.1%, but if the OC cushion is 0.5%, that discrepancy consumes 20% of the headroom.

Credit Fields (WARF/CCC Tests)

These fields determine the credit quality profile of the portfolio and feed into rating-dependent compliance tests.

Field Description Example Used In
Rating (Moody's) Moody's corporate family rating B1 WARF (US deals), CCC bucket
Rating (S&P) S&P issuer credit rating B+ WARF (EU deals), CCC bucket
Rating (Fitch) Fitch issuer default rating B+ WARF (EU deals), CCC bucket
Rating Date Date of most recent rating action 2024-03-15 Stale rating detection
Rating Watch Watchlist status (positive, negative, developing) Negative Early warning, potential WARF impact
Rating Outlook Medium-term rating outlook Stable Trend analysis
Default Status Whether the loan is in default N OC exclusion, recovery rate application
Default Date Date default was declared 2024-01-10 Time-in-default tracking
Composite Rating Derived rating using worst-of or average methodology B2 WARF input (deal-specific methodology)

Composite Rating Methodology Varies

Different indentures specify different composite rating methodologies:

  • Worst-of: Use the lowest rating from available agencies
  • Middle-of-three: If all three agencies rate, use the middle rating
  • Average: Average the numeric scores of available ratings
  • Moody's-only: Only use the Moody's rating (common in US)
  • S&P-primary: Use S&P, fall back to Fitch (common in EU)

CalcBridge must implement all methodologies and apply the correct one per deal. Using the wrong composite methodology produces incorrect WARF calculations.

# Composite rating calculation
def calculate_composite_rating(
    moodys: str | None,
    sp: str | None,
    fitch: str | None,
    methodology: str,
) -> str:
    ratings = [r for r in [moodys, sp, fitch] if r is not None]

    if methodology == "worst_of":
        return max(ratings, key=rating_to_numeric)
    elif methodology == "middle_of_three" and len(ratings) == 3:
        return sorted(ratings, key=rating_to_numeric)[1]
    elif methodology == "moodys_primary":
        return moodys or sp or fitch
    elif methodology == "sp_primary":
        return sp or fitch or moodys

Maturity Fields (WAL Test)

These fields determine the time profile of the portfolio and feed into the Weighted Average Life calculation.

Field Description Example Used In
Maturity Date Legal final maturity of the loan 2029-06-15 WAL calculation
Expected Life Expected repayment date (prepayment-adjusted) 2027-12-31 WAL (if prepay-adjusted methodology)
Amortisation Schedule Scheduled principal repayment pattern 1% quarterly Cash flow modelling, amortisation tracking
Call Protection Non-call period end date 2025-06-15 Refinancing risk assessment
Next Payment Date Date of next scheduled payment 2024-04-15 Cash flow projection
Payment Frequency How often payments are made Quarterly Cash flow modelling
Original Term Original term of the loan in months 84 Vintage analysis

WAL Calculation

The Weighted Average Life is calculated as:

WAL = Sum(Principal Payment(i) * Time to Payment(i)) / Total Principal

Where:
- Principal Payment(i) = expected principal received at time i
- Time to Payment(i) = years from measurement date to payment date

The WAL test has a maximum threshold (e.g., 5.5 years). Longer WAL means more duration risk. During amortisation, WAL typically decreases as near-term maturities roll off.

Concentration Fields

These fields are used to compute concentration metrics across obligors, industries, and geographies.

Field Description Example Used In
Obligor Group Parent entity grouping (for related borrowers) Acme Holdings Single obligor test (aggregated)
Industry Code Numeric or alphanumeric industry classification 3 or 40301020 Industry concentration test
Industry Description Human-readable industry name Banking, Finance, Insurance & Real Estate Reporting
Sub-Industry More granular industry classification Commercial Banking Detailed concentration analysis
Country Code ISO 3166-1 alpha-2 country code US, DE, GB Geographic concentration test
Region Geographic region grouping North America Regional concentration test
Currency Currency denomination of the loan USD, EUR Currency concentration (European CLOs)
Lien Position First lien, second lien, unsecured 1st Lien Second lien and unsecured limits
Covenant Status Covenant-lite or covenant-heavy Cov-Lite Covenant-lite concentration limit

Settlement and Trade Fields

These fields track the settlement status of positions and are important for reconciliation timing differences.

Field Description Example Used In
Trade Date Date the position was traded 2024-03-01 Trade reconciliation
Settlement Date Date the trade settles (T+7 typical for loans) 2024-03-08 Settlement reconciliation
Settlement Status Whether the trade has settled Settled Position reconciliation
Settle Amount Dollar amount exchanged at settlement $4,925,000 Cash reconciliation
Delayed Draw Amount Unfunded commitment on a delayed draw term loan $1,000,000 Unfunded exposure tracking
Revolver Commitment Total commitment on a revolving facility $2,000,000 Unfunded exposure tracking
Revolver Funded Funded portion of a revolving facility $500,000 OC, concentration (funded portion)

Settlement Timing Discrepancies

Loans settle on a T+7 to T+10 basis (compared to T+1 for bonds). This creates a window where the manager's internal books show a position that the trustee tape does not yet reflect, or vice versa. CalcBridge's reconciliation engine includes timing rules to detect and classify these as expected discrepancies rather than errors.


Trustee Format Variations

Field names vary significantly across trustees. This is the core reason CalcBridge's alias profile system exists. The following table maps common concepts to their actual column names in each trustee's file format.

Identifier Fields

Concept BNY Mellon US Bank Deutsche Bank Wilmington
CUSIP CUSIP CUSIP CUSIP CUSIP
ISIN ISIN -- ISIN --
Obligor name Borrower Obligor Name Issuer Borrower Name
LoanX ID Markit ID LoanX ID LX ID LoanX
Facility name Facility Facility Name Tranche Facility

Financial Fields

Concept BNY Mellon US Bank Deutsche Bank Wilmington
Par value Current Par Par Amount Outstanding Balance Par Value
Purchase price Purch Price Purchase Price Buy Price Cost
Market price Bid Price Market Price Mark Market Price
Spread Spread Current Spread Margin Spread (bps)
Base rate Index Base Rate Reference Rate Index Rate
Coupon Rate All-In Rate Coupon Current Rate
Floor Floor LIBOR Floor Floor Rate Floor

Rating Fields

Concept BNY Mellon US Bank Deutsche Bank Wilmington
Moody's rating Mdy Moody's Moody Rating Moodys
S&P rating S&P S&P Rating SP Rating S&P
Fitch rating Fitch Fitch Rating Fitch Rating Fitch

Classification Fields

Concept BNY Mellon US Bank Deutsche Bank Wilmington
Industry Industry Moody Industry Industry Code Industry
Country Country Country Domicile Country
Seniority Lien Seniority Ranking Lien Position
Facility type Type Loan Type Instrument Type Facility Type

Date Fields

Concept BNY Mellon US Bank Deutsche Bank Wilmington
Maturity date Maturity Maturity Date Final Maturity Maturity Date
Trade date Trade Dt Trade Date Trade Date Trade Date
Settlement date Settle Dt Settle Date Value Date Settlement Date
Next payment Next Pmt Next Payment Date Next Coupon Date Next Payment

Alias Profile Configuration

When adding support for a new trustee, create an alias profile JSON in calcbridge/config/clo_aliases/ that maps trustee-specific column names to CalcBridge's normalized schema. See Alias Profiles for the configuration format and examples.

{
  "profile_name": "bny_mellon_standard",
  "trustee": "bny_mellon",
  "mappings": {
    "Current Par": "par_value",
    "Borrower": "borrower_name",
    "Mdy": "rating_moodys",
    "S&P": "rating_sp",
    "Spread": "spread",
    "Maturity": "maturity_date"
  }
}

European Trustee Considerations

European trustee tapes have several characteristics that differ from US tapes and require specific parser handling.

ISIN as Primary Identifier

European tapes may not include a CUSIP at all. The ISIN is the primary identifier, and CalcBridge's matching logic must handle this.

Multi-Currency Positions

Some European CLOs hold GBP-denominated loans within a EUR-denominated deal. The trustee tape may include a currency column, and par values must be converted to the deal currency for compliance calculations.

Euribor Conventions

European tapes reference Euribor rather than SOFR. The base rate field may contain values like EURIBOR 3M or EUR3M, which must be normalised.

Different Date Formats

European tapes sometimes use DD/MM/YYYY rather than MM/DD/YYYY. The parser must detect and handle both conventions.

Date Format Ambiguity

A date like 01/03/2024 is January 3rd in US format but March 1st in European format. CalcBridge's parser uses heuristics (values > 12 in the first position indicate DD/MM) and trustee-specific configuration to resolve ambiguity. Always verify date parsing when onboarding a new European trustee.


Data Quality Indicators

Trustee tapes sometimes contain data quality issues that CalcBridge must handle gracefully.

Issue Detection CalcBridge Handling
Missing ratings Rating field is blank or "NR" Flag as unrated; apply worst-case rating factor for WARF
Stale prices Market price date is > 30 days old Flag in reconciliation; use last available price
Duplicate CUSIPs Same CUSIP appears multiple times Aggregate par values; may indicate multiple facilities
Negative par Par value is negative Flag as error; may indicate a short position or data issue
Zero spread Spread is 0 or blank May be a fixed-rate bond; check facility type
Missing maturity Maturity date is blank Flag as error; WAL cannot be calculated without maturity
Future trade date Trade date is after the statement date Flag as timing issue; position may not have settled

Parser Architecture

CalcBridge's trustee tape parser follows a pipeline architecture:

flowchart LR
    A[Raw Excel<br/>File] --> B[Trustee<br/>Detection]
    B --> C[Alias Profile<br/>Loading]
    C --> D[Column<br/>Mapping]
    D --> E[Type<br/>Conversion]
    E --> F[Validation<br/>Rules]
    F --> G[Normalized<br/>Loan Schema]

    style B fill:#DBEAFE,stroke:#3B82F6
    style D fill:#DBEAFE,stroke:#3B82F6
    style G fill:#DCFCE7,stroke:#22C55E
  1. Trustee Detection -- Identify the trustee from file structure or user selection
  2. Alias Profile Loading -- Load the appropriate alias profile for the detected trustee
  3. Column Mapping -- Map trustee-specific column names to normalized field names
  4. Type Conversion -- Convert string values to appropriate types (dates, decimals, ratings)
  5. Validation Rules -- Apply data quality checks and flag issues
  6. Normalized Output -- Produce a consistent loan schema for reconciliation
# Parser pipeline example
class TrusteeTapeParser:
    def parse(
        self,
        file_path: str,
        trustee: str,
        statement_date: date,
    ) -> ParseResult:
        # Load raw data
        df = pd.read_excel(file_path)

        # Load alias profile
        profile = self.alias_registry.get_profile(trustee)

        # Map columns
        df = df.rename(columns=profile.mappings)

        # Convert types
        df = self.type_converter.convert(df, profile.type_hints)

        # Validate
        issues = self.validator.validate(df, statement_date)

        # Build normalized loan objects
        loans = [NormalizedLoan(**row) for row in df.to_dict("records")]

        return ParseResult(loans=loans, issues=issues)