1.4.1 — 2026-07-05
Fixed
- The solver now converges for long-maturity, low-rate flows — for example the
ytmof a deep-discount 28-year bond, or a 30-year monthly amortizationrate. Previously a Newton step could overflow on such flows and abort the whole solve instead of falling through to bisection, and the bisection bracket itself overflowed for long-dated flows. Now a Newton overflow falls through to bisection, the bracket floor adapts to the longest flow, and the bracketing sign check compares signs instead of multiplying (which could overflow).
1.4.0 — 2026-07-04
Added
Finance.Returnsreturn metrics:cagr/4(compound annual growth rate),payback_period/2anddiscounted_payback_period/3(with fractional-period interpolation),profitability_index/3(reusingCashFlow.npv), andtwr/2(time-weighted return, with an optional:periods_per_yearto annualise) — each with a!variant.
1.3.0 — 2026-07-04
Added
Finance.TVM.ipmt/6andppmt/6— the interest and principal portions of a given period's payment; together they add up topmt/5.Finance.TVM.amortization_schedule/3,4— the full repayment schedule as a list of%{period, payment, interest, principal, balance}rows, with the final row absorbing rounding so the balance ends at exactly0. Computed in integer minor units (10^:precision), so every row is exact to the requested precision; returnsDecimalrows when givenDecimalinputs, floats otherwise.Finance.Rates—effective_annual_rate/2,nominal_rate/2, andcontinuous_to_periodic/2for converting between rate quotations.Finance.Bonds— fixed income:price/5,ytm/5(reuses theFinance.Solverseam, mirroringTVM.rate),duration/4(Macaulay),modified_duration/4, andconvexity/4, each with a!variant. Maturity is given in years with a configurable coupon frequency (freq, default2); settlement is assumed to fall on a coupon date (clean price, no accrued interest).
1.2.0 — 2026-07-04
Reorganised the flat Finance module into domain modules. No behaviour
change — every function keeps its signature and result.
Added
- Domain modules:
Finance.CashFlow(npv/xnpv/irr/xirr/mirr),Finance.TVM(pv/fv/pmt/nper/rate),Finance.Depreciation(sln/syd/ddb/db), andFinance.Returns(volatility). Finance.Solverbehaviour with the defaultFinance.Solver.Newton. The solver is swappable per call with the:solveroption or globally withconfig :finance, solver: MySolver— a seam for a future Nx/GPU solver.
Deprecated
- The flat
Finance.foofunctions (e.g.Finance.xirr/1) now delegate to their domain module and are deprecated. They still work in the 1.x line and will be removed in 2.0.
1.1.0 — 2026-07-04
Added
volatility/2andvolatility!/2— annualised volatility of a price series, the standard deviation of its period returns scaled by√periods_per_year. Supports simple or log returns and a configurable period count. Resolves the long-standing volatility request (issue #7), with the submitted snippet's crashes on short input and zero prices fixed.
1.0.0 — 2026-07-04
A complete rewrite of the library. Breaking changes — some return values differ from 0.x because intermediate rounding was removed and the solver was replaced, and errors are now atoms rather than strings.
Rate of return
xirr/1,2,3andxirr!— internal rate of return for dated cash flows, given as{date, amount}pairs or two parallel lists. Dates may beDatestructs or{year, month, day}tuples.irr/1,2andirr!— internal rate of return for periodic (equally spaced) flows.mirr/3,4andmirr!— modified internal rate of return.- Newton-Raphson solver with an analytic derivative, a bracketing bisection fallback, and a hard iteration cap.
Present / future value
xnpv/2,3andxnpv!— net present value of dated cash flows.npv/2,3andnpv!— net present value of periodic flows. The first amount sits at period 0 (sonpv(irr(a), a) ≈ 0), which differs from spreadsheetNPV(first amount at period 1).
Time value of money
fv/5,pv/5,pmt/5,nper/5,rate/6and their!variants — solve the annuity equation for one unknown, with annuity-due (type: 1) support.
Depreciation
sln/3,syd/4,ddb/5,db/5and their!variants — straight-line, sum-of-years'-digits, double-declining and fixed-declining depreciation.
Amounts and options
- Amounts may be integers, floats, or
Decimalvalues (via the optionaldecimaldependency); results are always floats. - Options (
:guess,:tolerance,:max_iterations,:precision) are validated withnimble_options; unknown keys and out-of-type values raise.
Removed
- The
timexruntime dependency (now uses the standard-libraryDate). - The
spawn_link-per-cash-flow "parallel" mapping, which was slower and unsafe.
Tooling
- Requires Elixir
~> 1.18; tested on Elixir 1.18/OTP 27 and 1.20/OTP 29. - Travis CI replaced with GitHub Actions.