Skip to content

Releases: CommunityFIT/cfit

cfit v0.2.4 - Linear-Incentive Prepayment Model & Vectorized Engine

Choose a tag to compare

@colinlpaterson colinlpaterson released this 01 Jun 21:54

New Features

  • calculate_cash_flows(prepay_model = ...) - A new configuration option selects how the conditional prepayment rate (CPR) is derived for each loan:
    • "tier_static" (default) - Existing behavior, preserved exactly: applies tier-keyed CPR from cpr_vec. No market rate required.
    • "linear_incentive" - Derives a per-loan CPR from the borrower's rate incentive, so prepayment responds to the rate environment:
      CPR = clamp(base_cpr + beta × (coupon − current_market_rate), cpr_min, cpr_max)
      • base_cpr_vec, beta_vec, cpr_min_vec, cpr_max_vec are tier-keyed; current_market_rate is a scalar; coupon is the gross note rate.
      • beta is expressed per decimal of rate incentive (e.g. beta = 2.0 adds 0.02 to CPR per 100 bps of incentive).
      • Rate-responsive CPR is the prerequisite for an effective-duration measure (price sensitivity under re-projected cash flows), planned for a future release.

Performance

  • Vectorized cash flow engine - The per-loan engine no longer allocates a data frame for every projected month. Monthly results are accumulated in preallocated atomic vectors and assembled in a single tibble() call per loan.
    • The package's internal performance test dropped from roughly 79s to 7s, with output identical to v0.2.3 (verified to 1e-8).
    • The sequential balance roll-forward is unchanged; only the allocation pattern was rewritten.

Pipeline Integration

The prepayment model selection sits at the front of the existing analytical workflow:

calculate_prepay_speed()
→ calculate_cash_flows(prepay_model = "tier_static" | "linear_incentive")
├─> FinCal::yield.actual() (optional, to estimate portfolio yield/IRR)
├─> calculate_duration()
└─> calculate_wal()

"tier_static" keeps the established behavior for static-assumption analysis, while "linear_incentive" introduces rate-responsive prepayment for forward-looking interest-rate risk work.

Testing

  • Golden-master regression (new) - Freezes v0.2.3 output for the tier_static path (4 cases) and the linear_incentive output (1 case) at 1e-8 tolerance, guarding against behavioral drift through the engine refactor.
  • 5 unit tests for linear_incentive - Hand-computed CPR (including upper/lower clamps), tier fallback, required-parameter validation, and the negative-beta warning.
  • Full suite: 236 assertions passing, 0 failures, 0 warnings.
  • R CMD check: 0 errors, 0 warnings, 0 notes.

Compatibility

  • No breaking changes. prepay_model defaults to "tier_static"; existing calls produce identical results to v0.2.3.

Documentation

  • roxygen documentation updated for the new configuration parameters (prepay_model, current_market_rate, and the four tier-keyed vectors).
  • Inline guidance on beta units and the economic interpretation of the rate incentive.

Full Changelog: v0.2.3...v0.2.4

cfit v0.2.3 - Duration and WAL Calculations

Choose a tag to compare

@colinlpaterson colinlpaterson released this 05 Feb 22:05

New Features

  • calculate_duration() - Calculate Macaulay duration, modified duration, and optional analytical convexity for loan portfolios
    • Macaulay duration: PV-weighted average time (years) to receive cash flows (often interpreted as an “effective maturity” under the chosen discount rate).
      -Modified duration: interest-rate sensitivity; approximates % change in value for a 1% change in rates.
    • Analytical convexity (fixed cash flows): curvature of the price–yield relationship using held-constant cash flows (does not incorporate rate-dependent prepayment behavior).
    • Flexible discount rate selection: portfolio yield (IRR), loan coupon, or custom market/FTP rate
    • Supports both gross (total_payment) and net (investor_total) cash flows
  • calculate_wal() - Calculate weighted average life (WAL) for loan portfolios
    • WAL: Time-weighted average of principal repayments, expressed in years. Measures how quickly principal is returned, independent of interest rates.
    • Support for both total_principal and investor_principal
    • Complements duration analysis for comprehensive portfolio risk assessment

Pipeline Integration

These functions complete the cfit analytical workflow for community financial institutions:

calculate_prepay_speed()
→ calculate_cash_flows()
├─> FinCal::yield.actual() (optional, to estimate portfolio yield/IRR)
├─> calculate_duration()
└─> calculate_wal()

This pipeline enables treasury analysts to move from prepayment modeling through yield calculation to comprehensive duration and WAL risk metrics.

Testing

  • 76 comprehensive tests for calculate_duration() (63 assertions)
  • 48 comprehensive tests for calculate_wal() (48+ assertions)
  • All tests passed on local machine

Documentation

  • Detailed roxygen documentation with examples
  • Clear explanations of financial concepts
  • Guidance on when to use each function

cfit 0.2.2

Choose a tag to compare

@colinlpaterson colinlpaterson released this 29 Jan 20:05

Bug Fixes

  • Critical: Fixed credit loss calculation to cap at 100% of balance - prevents mathematical impossibility where credit losses could exceed loan balance
  • Fixed prepayment calculation to properly cap at available balance after credit losses are applied
  • Fixed date handling to use base R seq.Date() for more reliable month-end date arithmetic

Improvements

  • Simplified grouping column handling - now uses efficient lookup table join instead of complex parameter passing
  • Removed unnecessary date conversion messages for cleaner output
  • Monthly totals now automatically sorted by date and grouping variables for predictable output
  • Minor documentation fixes and clarifications

cfit 0.2.1

Choose a tag to compare

@colinlpaterson colinlpaterson released this 29 Jan 20:04

cfit 0.2.1

Bug Fixes and Improvements

Critical Fixes:

  • Fixed date conversion persistence - character dates are now properly converted and maintained throughout processing
  • Fixed prepayment calculation to cap at available balance after credit losses
  • Fixed months() namespace issue for better package reliability
  • Renamed monthly_reporting_fee to annual_reporting_fee for consistency with other annual rate parameters

New Features:

  • Added credit_loss_reduces_interest parameter (default: TRUE) - configurable accounting treatment for credit losses. By default, credit losses are applied against investor cash flows before distribution to investors. When set to FALSE, credit losses reduce principal balances only and do not directly reduce interest cash flows.
  • Added monthly_totals_group_vars parameter - allows grouping monthly totals by additional variables (e.g., tier, product type) beyond date
  • Split fee reporting for transparency: servicing_fee_amt, reporting_fee_amt, and total_fees columns

Enhanced Validation:

  • Enforced "default" tier requirement when tier column is not specified
  • Added explicit dplyr:: namespace calls for better compatibility
  • Improved error messages and validation checks

cfit 0.1.0 - First Stable Release

Choose a tag to compare

@colinlpaterson colinlpaterson released this 23 Dec 23:47

cfit 0.1.0 🎉

First release of cfit - open-source computational finance tools for community banks and credit unions!

Features

calculate_prepay_speed()

Calculate Single Monthly Mortality (SMM) and Conditional Prepayment Rate (CPR) for loan portfolios.

Accuracy

  • Industry-standard SMM calculation using pool available to prepay
  • Improved scheduled principal accuracy when loan ID provided
  • Automatic interest rate format detection and conversion

Validation

  • Optional loan ID validation prevents duplicate records
  • Smart rate format handling (7.29% or 0.0729)
  • Data quality checks and helpful error messages

Flexibility

  • Custom column mapping for any FI's data structure
  • Multiple interest calculation methods (360/365-day basis)
  • Configurable prepayment handling and filtering

Testing

  • 39 automated tests covering all functionality and edge cases

Installation

devtools::install_github("CommunityFIT/cfit@v0.1.0")

Documentation

See the README for examples and usage.

Contributing

Feedback and contributions welcome! Open an issue or discussion.


Part of the CommunityFIT initiative