Lightweight, dependency-free TypeScript financial math library providing pure calculation utilities.
npm i @pyverret/ratejsnpm run validate- GitHub Pages URL: https://pyverret.github.io/ratejs/
- Demo source:
demo/
Run locally:
cd demo
npm install
npm run devAll functions take a single options object (no positional args). Rates are decimals (e.g. 0.05 = 5%).
Cash-flow sign convention (Excel-style):
- Cash paid out is negative, cash received is positive.
- Loan example:
presentValue > 0andpayment < 0. - Investment withdrawal example:
presentValue < 0andpayment > 0.
pmt- ExcelPMT: payment per period for a loan/investment.pv- ExcelPV: present value from payment stream and future value.fv- ExcelFV: future value from present value and payment stream.nper- ExcelNPER: number of periods required.rate- ExcelRATE: implied rate per period. Supports optionalguess,maxIterations,lowerBound, andupperBound.npv- ExcelNPV: net present value of a cash flow series.
const payment = pmt({
ratePerPeriod: 0.06 / 12,
periods: 360,
presentValue: 250000,
futureValue: 0, // optional
timing: "end", // optional
});
const impliedRate = rate({
periods: 360,
payment,
presentValue: 250000,
futureValue: 0, // optional
timing: "end", // optional
guess: 0.1, // optional
maxIterations: 100, // optional
tolerance: 1e-10, // optional
lowerBound: -0.99, // optional
upperBound: 10, // optional
});Edge cases:
nperthrowsRangeErrorwhenratePerPeriod <= -1.ratethrowsRangeErrorwhen no root is found within search bounds.pmt,pv, andfvthrowRangeErrorwhenratePerPeriod <= -1.
compound- Final amount for a lump sum with compound interest.
compound({ principal: 1000, rate: 0.05, timesPerYear: 12, years: 10 });futureValue- Future value of a present lump sum.
futureValue({ presentValue: 2500, rate: 0.07, timesPerYear: 4, years: 3 });presentValue- Present value of a future lump sum.
presentValue({ futureValue: 5000, rate: 0.06, timesPerYear: 12, years: 5 });investmentGrowth- Future value with optional periodic contributions. Returns{ futureValue, totalContributions, totalInterest }.
investmentGrowth({
initial: 1000,
contributionPerPeriod: 100, // optional
rate: 0.06,
timesPerYear: 12,
years: 2,
contributionTiming: "end", // optional ("end" | "begin")
});effectiveAnnualRate- Convert nominal rate + compounding frequency to effective annual rate (EAR).
effectiveAnnualRate({ nominalRate: 0.06, timesPerYear: 12 });periodsToReachGoal— Number of compounding periods until future value reaches a target (lump sum or with contributions).
periodsToReachGoal({
principal: 1000,
targetFutureValue: 2000,
rate: 0.06,
timesPerYear: 12,
contributionPerPeriod: 0, // optional
contributionTiming: "end", // optional
maxPeriods: 100000, // optional
});Edge cases:
-
Returns
Infinitywhen the goal is unreachable. -
Throws
RangeErrorwhenrate / timesPerYear <= -1. -
Throws
RangeErrorwhenmaxPeriodsis exceeded for contribution-based iteration. -
Throws
RangeErrorwhencontributionTimingis not"end"or"begin". -
rateToReachGoal- Rate per period required to reach a target future value in a given number of periods.
rateToReachGoal({
principal: 1000,
targetFutureValue: 1500,
periods: 24,
contributionPerPeriod: 0, // optional
contributionTiming: "end", // optional
maxIterations: 100, // optional
tolerance: 1e-10, // optional
lowerBound: -0.99, // optional
upperBound: 10, // optional
});Edge cases:
-
Throws
RangeErrorwhen no root is found within search bounds. -
Throws
RangeErrorwhencontributionTimingis not"end"or"begin". -
ruleOf72- Approximate years to double a lump sum at a given annual rate. Optionalconstant: 69for rule of 69.
ruleOf72({ rate: 0.07 }); // ~10.3 years
ruleOf72({ rate: 0.07, constant: 69 });cagr- Compound annual growth rate between a start and end value over years.
cagr({ startValue: 1000, endValue: 2000, years: 10 });irr- Internal rate of return: discount rate that makes NPV of cash flows zero.cashFlows[0]is typically the initial outlay (negative). Supports optionalguess,maxIterations,lowerBound, andupperBound.
irr({
cashFlows: [-1000, 300, 400, 500],
guess: 0.1, // optional
maxIterations: 100, // optional
lowerBound: -0.99, // optional
upperBound: 10, // optional
});Edge cases:
- Throws
RangeErrorwhencashFlowsis empty. - Throws
RangeErrorwhencashFlowsdoes not contain at least one positive and one negative value. - Throws
RangeErrorwhen no root is found within search bounds.
realReturn- Real (inflation-adjusted) return from nominal return and inflation rate.
realReturn({ nominalReturn: 0.07, inflationRate: 0.02 });inflationAdjustedAmount- Purchasing power across time.toPast: value years ago with same purchasing power;toFuture: nominal amount in the future with same purchasing power.
inflationAdjustedAmount({
amount: 100,
annualInflationRate: 0.03,
years: 10,
direction: "toPast",
});
inflationAdjustedAmount({
amount: 100,
annualInflationRate: 0.03,
years: 10,
direction: "toFuture",
});presentValueOfAnnuity- Present value of a series of equal payments.timing:"end"(ordinary) or"begin"(annuity due).
presentValueOfAnnuity({
paymentPerPeriod: 100,
ratePerPeriod: 0.01,
periods: 36,
timing: "end", // optional
});paymentFromPresentValue- Periodic payment to pay off a present value (e.g. loan) over a number of periods.
paymentFromPresentValue({
presentValue: 100000,
ratePerPeriod: 0.005,
periods: 360,
timing: "end", // optional
});loanPayment- Fixed periodic payment for an amortizing loan (nominal annual rate, payments per year, years).
loanPayment({
principal: 200000,
annualRate: 0.06,
paymentsPerYear: 12,
years: 30,
});Edge cases:
-
Throws
RangeErrorwhenannualRate / paymentsPerYear <= -1. -
amortizationSchedule- Full schedule:{ paymentPerPeriod, schedule, totalPaid, totalInterest }. OptionalextraPaymentPerPeriod.
amortizationSchedule({
principal: 200000,
annualRate: 0.06,
paymentsPerYear: 12,
years: 30,
extraPaymentPerPeriod: 50, // optional
});remainingBalance- Balance remaining after a given number of payments (1-basedafterPeriodNumber).
remainingBalance({
principal: 200000,
annualRate: 0.06,
paymentsPerYear: 12,
years: 30,
afterPeriodNumber: 12,
});payoffPeriodWithExtra— Number of periods until the loan is paid off with base payment + extra payment.
payoffPeriodWithExtra({
principal: 100000,
annualRate: 0.06,
paymentsPerYear: 12,
basePaymentPerPeriod: 599.55,
extraPaymentPerPeriod: 100,
});Edge cases:
- Returns
Infinitywhen payment is zero or does not cover per-period interest.
roundToCurrency- Round to decimal places (default 2).mode:"half-up"or"half-even"(banker's rounding).
roundToCurrency({ value: 2.125 }); // 2.13
roundToCurrency({ value: 2.125, decimals: 2, mode: "half-even" }); // decimals/mode optional- Pure functions only
- No runtime dependencies
- Object-parameter inputs (no positional args)
- Deterministic outputs
- Tree-shakeable (import only what you use)