A reference-grade financial calculation engine for TypeScript.
Explicit assumptions. Reproducible results. Verifiable answers.
finprecise is not another collection of financial helper functions. It is a calculation foundation where every assumption — rate convention, day count, rounding rule, solver behavior — is visible in the API and reproducible across Node.js, Bun, Deno, and browsers.
Existing TypeScript/JavaScript financial libraries have gaps:
- financial covers numpy-financial basics but explicitly excludes arbitrary-precision decimals
- financejs and xirr are aging implementations (2017, 2020) with no day-count or rounding controls
- None expose solver diagnostics ("did it converge?", "why did it fail?")
finprecise fills these gaps:
- Decimal-first: All calculations use
decimal.js— no floating-point surprises - Assumptions are explicit: Day count convention, compounding frequency, payment timing, and rounding mode are API parameters — sensible defaults exist where industry convention is clear, but nothing is hidden
- Solver transparency: IRR/XIRR/rate return
SolveResult— convergence status, iteration count, and failure reasons - Verification-ready: Ships with fixtures cross-referenced against numpy-financial and Excel
| Package | Description |
|---|---|
@finprecise/core | Decimal, Rate, DayCount, Rounding, Solver |
@finprecise/cashflow | PV, FV, PMT, NPER, RATE, NPV, XNPV, IRR, XIRR, MIRR |
@finprecise/loans | Amortization schedules: level-payment, level-principal, interest-only, bullet, variable-rate, prepayment |
@finprecise/depreciation | SLN, DB, DDB, SYD (Excel-compatible) |
@finprecise/bonds | Bond pricing, YTM, Macaulay/modified duration, convexity |
@finprecise/format | Display formatting via Intl.NumberFormat (separated from calculation) |
@finprecise/fixtures | Verification data for numpy-financial and Excel compatibility |
npm install @finprecise/core @finprecise/cashflowimport{periodicRate}from"@finprecise/core";import{pv,pmt,irr,xirr}from"@finprecise/cashflow";// Monthly payment on a $200,000 mortgage at 6% annual for 30 yearsconstmonthlyRate=periodicRate("0.06","monthly");// → 0.005constpayment=pmt(monthlyRate,"360","200000");// → -1199.10 (you pay $1,199.10/month)// Present value of $1,000/year for 10 years at 5%constpresentValue=pv("0.05","10","-1000");// → 7721.73// IRR with solver diagnosticsconstresult=irr(["-100000","30000","35000","40000","25000"]);if(result.ok){console.log(`IRR: ${result.value.toFixed(4)}, converged in ${result.iterations} iterations`);}else{console.log(`Failed: ${result.reason} — ${result.detail}`);}import{xirr}from"@finprecise/cashflow";constresult=xirr({cashflows: [{amount: "-100000",date: "2025-01-10"},{amount: "25000",date: "2025-06-30"},{amount: "90000",date: "2026-03-01"},],dayCount: "act/365-fixed",solver: {method: "hybrid",guess: "0.10",maxIterations: 128,tolerance: "1e-12",},});import{loanSchedule}from"@finprecise/loans";constschedule=loanSchedule({principal: "350000",periods: 360,repayment: {kind: "level-payment"},rateSteps: [{from: 1,annualRate: "0.0475"},{from: 37,annualRate: "0.0610"},],accrual: {dayCount: "30e/360",compounding: "monthly"},rounding: {interest: "half-up",payment: "half-up",balance: "half-up",scale: 2,},});// Every row shows: period, beginBalance, payment, principal, interest, endBalance, annualRatefor(constrowofschedule.rows.slice(0,3)){console.log(`#${row.period} | Balance: ${row.beginBalance} | Payment: ${row.payment} | `+`Principal: ${row.principal} | Interest: ${row.interest} | End: ${row.endBalance}`);}console.log(`Total interest: ${schedule.summary.totalInterest}`);import{sln,ddb,syd}from"@finprecise/depreciation";// Straight-line: $30,000 asset, $7,500 salvage, 10 yearssln("30000","7500","10");// → 2250// Double-declining balanceddb("1000000","100000","6","1");// → 333333.33// Sum-of-years-digitssyd("30000","7500","10","1");// → 4090.91import{effectiveAnnualRate,nominalAnnualRate}from"@finprecise/core";// 12% nominal with monthly compounding → 12.68% effectiveeffectiveAnnualRate("0.12","monthly");// → 0.126825...// Convert backnominalAnnualRate("0.126825","monthly");// → 0.12...Every function that depends on conventions exposes them as API parameters. Sensible defaults are provided where industry convention is clear, but all can be overridden explicitly:
PaymentTiming:"begin"or"end"(default"end"— ordinary annuity, matching Excel/numpy-financial)DayCountConvention:"act/365-fixed","30/360","act/act-isda", etc. (default"act/365-fixed"for XIRR/XNPV)CompoundingFrequency:"monthly","quarterly","continuous", etc.RoundingMode:"half-up","half-even","down", etc.SolverConfig: method, guess, maxIterations, tolerance (default: hybrid, 0.10, 128, 1e-12)
IRR, XIRR, and RATE return a discriminated union:
typeSolveResult=|{ok: true;value: Decimal;iterations: number}|{ok: false;reason: "no-bracket"|"no-convergence";detail?: string}- All calculations use
decimal.jsfor arbitrary precision - Inputs accept
string | number | Decimal(strings recommended) - Display formatting is in a separate
@finprecise/formatpackage usingIntl.NumberFormat - Computation and display are strictly separated
The @finprecise/fixtures package provides cross-referenced expected values from numpy-financial and Excel, so users can verify results against authoritative sources.
| Function | numpy-financial | Excel | Notes |
|---|---|---|---|
pv | npf.pv | PV | Identical sign convention |
fv | npf.fv | FV | Identical sign convention |
pmt | npf.pmt | PMT | Identical sign convention |
nper | npf.nper | NPER | |
rate | npf.rate | RATE | Returns SolveResult |
ipmt | npf.ipmt | IPMT | |
ppmt | npf.ppmt | PPMT | |
npv | npf.npv | — | First cashflow discounted (numpy convention) |
xnpv | — | XNPV | Configurable day count |
irr | npf.irr | IRR | Returns SolveResult |
xirr | — | XIRR | Returns SolveResult, configurable day count |
mirr | npf.mirr | MIRR | |
yearFrac | — | YEARFRAC | All 6 basis types |
sln | — | SLN | |
ddb | — | DDB | |
syd | — | SYD |
packages/
core/ — Decimal, Rate, DayCount, Rounding, Solver
cashflow/ — TVM functions, NPV, IRR, XIRR, MIRR
loans/ — Amortization schedule engine
depreciation/ — SLN, DB, DDB, SYD
bonds/ — Bond pricing, YTM, duration, convexity
format/ — Display formatting (Intl.NumberFormat)
fixtures/ — Verification data
pnpm install
pnpm build
pnpm testTests include:
- Unit tests against numpy-financial and Excel expected values
- Property-based tests with fast-check (TVM round-trips, IRR→NPV=0)
- Day count convention tests for all 6 basis types
- Solver convergence tests
- Fork the repository
- Create a feature branch
- Add tests (including fixtures for new functions)
- Ensure
pnpm testpasses - Submit a pull request