@michitson/cre-irr
v0.1.0
Published
IRR and tornado sensitivity analysis for commercial-real-estate deals. Pure, zero-dependency, validated against a golden fixture.
Maintainers
Readme
@michitson/cre-irr
IRR and tornado sensitivity analysis for commercial-real-estate (CRE) deals. Pure, zero-dependency TypeScript, validated against a golden fixture.
Status: pre-publish (
0.1.0). Extracted from the CRE deal-analyst project as a standalone, reusable library — the one piece of authored domain logic that survives every architecture change around it.
Install
npm install @michitson/cre-irrUsage
import { calculateIrr, runSensitivity } from '@michitson/cre-irr';
const deal = {
purchasePrice: 5_000_000,
netOperatingIncome: 400_000, // year 1 NOI
noiGrowthRate: 3, // percent, e.g. 3 = 3%/yr
holdPeriod: 10, // years
exitCapRate: 6.5, // percent
};
const irr = calculateIrr(deal);
console.log(irr.irrPercentage); // e.g. 12.544692996050152
const tornado = runSensitivity(deal);
// variables ranked by IRR spread (max − min) across the sweep
console.log(tornado.variables.map((v) => [v.name, v.spreadPp]));What it does
calculateIrr(inputs)— projects annual cash flows (year-1 NOI grown atnoiGrowthRate), capitalises forward NOI atexitCapRatefor the exit value, and solves IRR by bisection (100 iterations, |NPV| < 1e-6). Returns the IRR, total return, year-1 cash flow, exit value, and the full cash-flow array.runSensitivity(inputs)— a tornado sweep that moves each variable and ranks them by IRR spread. Mixed-mode by variable type: rate variables (noiGrowthRate,exitCapRate) move in basis points (±50/±100 bp); dollar/period variables (purchasePrice,netOperatingIncome,holdPeriod) move multiplicatively (±10%/±20%) — the way CRE practitioners actually think about each.
Determinism and correctness
The IRR is computed by code, not estimated — and it's locked to a golden
fixture (test/fixtures/irr_reference_values.json) extracted from a reference
Python implementation. Parity is asserted to 4 decimal places. The exported
irrPercentage for the standard case is 12.544692996050152; that value is
the cross-implementation contract.
Develop
npm test # vitest — golden-fixture parity + economic sanity
npm run build # emit dist/ (ESM + .d.ts)License
MIT © Andrew Michitson
