Releases: CommunityFIT/cfit
Release list
cfit v0.2.4 - Linear-Incentive Prepayment Model & Vectorized Engine
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 fromcpr_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_vecare tier-keyed;current_market_rateis a scalar;couponis the gross note rate.betais expressed per decimal of rate incentive (e.g.beta = 2.0adds 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.
- The package's internal performance test dropped from roughly 79s to 7s, with output identical to v0.2.3 (verified to
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_staticpath (4 cases) and thelinear_incentiveoutput (1 case) at1e-8tolerance, 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-betawarning. - Full suite: 236 assertions passing, 0 failures, 0 warnings.
R CMD check: 0 errors, 0 warnings, 0 notes.
Compatibility
- No breaking changes.
prepay_modeldefaults 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
betaunits and the economic interpretation of the rate incentive.
Full Changelog: v0.2.3...v0.2.4
cfit v0.2.3 - Duration and WAL Calculations
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
- Macaulay duration: PV-weighted average time (years) to receive cash flows (often interpreted as an “effective maturity” under the chosen discount rate).
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_principalandinvestor_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
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
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_feetoannual_reporting_feefor consistency with other annual rate parameters
New Features:
- Added
credit_loss_reduces_interestparameter (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_varsparameter - 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, andtotal_feescolumns
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
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