A zero-dependency financial math library for TypeScript
If you've ever needed to do real financial math in JavaScript, you've probably noticed the ecosystem thins out fast. The basic time-value-of-money functions — PMT, FV, IRR — are everywhere. But the moment you reach for bond duration, convexity, XIRR over irregular dates, or a proper day-count convention, you're left choosing between a heavyweight Excel-formula port and writing it yourself.
So I built finlytic: a small, dependency-free, fully typed library for the financial calculations themselves.
npm install finlytic
The gap
Two things are genuinely hard to find in JS/TS finance libraries:
Bond analytics — price, yield to maturity, and especially interest-rate risk: Macaulay duration, modified duration, convexity. These are standard in a fixed-income context and almost absent from zero-dependency JS packages.
Dated cash flows — XNPV / XIRR, where the flows fall on arbitrary calendar dates rather than neat equal periods. Easy to get subtly wrong, especially around time zones and leap years.
finlytic covers both, alongside the usual TVM, loan amortization, depreciation, returns, perpetuities, and day-count conventions.
A few examples
Internal rate of return for cash flows on real dates:
ts import { xirr } from 'finlytic'; xirr([ { amount: -10000, date: new Date('2024-01-01') }, { amount: 6000, date: new Date('2024-06-15') }, { amount: 6000, date: new Date('2025-01-10') }, ]); // the annual rate that makes the dated NPV zero Price a bond and measure its interest-rate risk:
ts import { bondPrice, modifiedDuration, convexity } from 'finlytic'; const bond = { couponRate: 0.08, yearsToMaturity: 10 }; // face 100, semi-annual bondPrice(bond, 0.10); // ≈ 87.54 (priced to yield 10%) modifiedDuration(bond, 0.10); // ≈ 6.51 years convexity(bond, 0.10); // ≈ 56.49 A full loan amortization schedule that ends at exactly zero:
ts import { amortizationSchedule } from 'finlytic'; const schedule = amortizationSchedule({ principal: 10000, rate: 0.05 / 12, nper: 12 }); schedule[0]; // { period: 1, payment: 856.07, interest: 41.67, principal: 814.41, balance: 9185.59 } schedule.at(-1)!.balance; // 0 On correctness
For a finance library, "looks about right" isn't good enough — the output is money. So the test suite (116 tests) doesn't check results against the implementation itself. Each reference value is cross-checked against an independent method:
xirr roots verified by bisection
bond duration and convexity verified against finite differences of the price
growing-annuity formulas verified against brute-force summation
mirr, depreciation, and day-counts verified against spreadsheet results
That process actually caught a few wrong constants while I was writing it — including a reference IRR I'd misremembered — which is exactly the point.
Some other deliberate choices:
- Zero dependencies, ESM + CJS, tree-shakeable.
- Spreadsheet-compatible results, so numbers match what finance people expect.
- Time-zone-independent day counts — dates are read by their UTC calendar day, so the same inputs give the same answer regardless of where the code runs.
- Correct handling of the edge cases implementations tend to miss: zero-interest loans, annuity-due payments, balloon residuals, and the rate === growth limit.
Try it
npm: https://www.npmjs.com/package/finlytic
Source & docs: https://github.com/shilpidaswani/finkit
It's early (v0.2.0), so feedback, bug reports, and PRs are all welcome — especially from anyone who works with fixed income or financial modelling and can stress-test the numbers.


