Skip to content

Commit

Permalink
Added npv()
Browse files Browse the repository at this point in the history
  • Loading branch information
lmammino committed Jul 2, 2020
1 parent 3314056 commit 2203c3e
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ There's no `default` export in the ESM implementation, so you have to explicitel
- [X] `pv`
- [X] `rate`
- [X] `irr`
- [ ] `npv`
- [X] `npv`
- [ ] `mirr`


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "financial",
"description": "A Zero-dependency TypeScript/JavaScript port of numpy-financial",
"author": "Luciano Mammino <[email protected]> (https://loige.co)",
"version": "0.0.17",
"version": "0.0.18",
"repository": {
"type": "git",
"url": "https://github.com/lmammino/financial.git"
Expand Down
69 changes: 69 additions & 0 deletions src/financial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,75 @@ export function irr (values: number[], guess = 0.1, tol = 1e-6, maxIter = 100):
return resultRate
}

/**
* Returns the NPV (Net Present Value) of a cash flow series.
*
* @param rate - The discount rate
* @param values - The values of the time series of cash flows. The (fixed) time
* interval between cash flow "events" must be the same as that for
* which `rate` is given (i.e., if `rate` is per year, then precisely
* a year is understood to elapse between each cash flow event). By
* convention, investments or "deposits" are negative, income or
* "withdrawals" are positive; `values` must begin with the initial
* investment, thus `values[0]` will typically be negative.
* @returns The NPV of the input cash flow series `values` at the discount `rate`.
*
* ## Warnings
*
* `npv considers a series of cashflows starting in the present (t = 0).
* NPV can also be defined with a series of future cashflows, paid at the
* end, rather than the start, of each period. If future cashflows are used,
* the first cashflow `values[0]` must be zeroed and added to the net
* present value of the future cashflows. This is demonstrated in the
* examples.
*
* ## Notes
*
* Returns the result of:
*
* ```
* \\sum_{t=0}^{M-1}{\\frac{values_t}{(1+rate)^{t}}}
* ```
*
* ## Examples
*
* Consider a potential project with an initial investment of $40 000 and
* projected cashflows of $5 000, $8 000, $12 000 and $30 000 at the end of
* each period discounted at a rate of 8% per period. To find the project's
* net present value:
*
* ```javascript
* import {npv} from 'financial'
*
* const rate = 0.08
* const cashflows = [-40_000, 5000, 8000, 12000, 30000]
* npv(rate, cashflows) // 3065.2226681795255
* ```
*
* It may be preferable to split the projected cashflow into an initial
* investment and expected future cashflows. In this case, the value of
* the initial cashflow is zero and the initial investment is later added
* to the future cashflows net present value:
*
* ```javascript
* const initialCashflow = cashflows[0]
* cashflows[0] = 0
*
* npv(rate, cashflows) + initialCashflow // 3065.2226681795255
* ```
*
* ## References
*
* L. J. Gitman, "Principles of Managerial Finance, Brief,"
* 3rd ed., Addison-Wesley, 2003, pg. 346.
*/
export function npv (rate: number, values: number[]) : number {
return values.reduce(
(acc, curr, i) => acc + (curr / (1 + rate) ** i),
0
)
}

/**
* This function is here to simply have a different name for the 'fv'
* function to not interfere with the 'fv' keyword argument within the 'ipmt'
Expand Down
10 changes: 10 additions & 0 deletions test/examples.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,14 @@ describe('Source code docs examples', () => {
expect(f.irr([-100, 100, 0, 7])).toBeCloseTo(0.0620584, 6)
expect(f.irr([-5, 10.5, 1, -8, 1])).toBeCloseTo(0.088598, 6)
})

test('npv()', () => {
const rate = 0.08
const cashflows = [-40_000, 5000, 8000, 12000, 30000]
expect(f.npv(rate, cashflows)).toBeCloseTo(3065.22266817, 6)

const initialCashflow = cashflows[0]
cashflows[0] = 0
expect(f.npv(rate, cashflows) + initialCashflow).toBeCloseTo(3065.22266817, 6)
})
})
11 changes: 9 additions & 2 deletions test/financial.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fv, pmt, nper, ipmt, ppmt, pv, rate, irr, PaymentDueTime } from '../src/financial'
import { fv, pmt, nper, ipmt, ppmt, pv, rate, irr, npv, PaymentDueTime } from '../src/financial'

// Based on https://github.com/numpy/numpy-financial/blob/master/numpy_financial/tests/test_financial.py
// Mostly based on
// https://github.com/numpy/numpy-financial/blob/master/numpy_financial/tests/test_financial.py

describe('fv()', () => {
it('calculates float when is end', () => {
Expand Down Expand Up @@ -154,3 +155,9 @@ describe('irr()', () => {
expect(irr([-5, 10.5, 1, -8, 1], 0.1, 1e-10, 2)).toBeNaN()
})
})

describe('npv()', () => {
it('calculates float', () => {
expect(npv(0.05, [-15000, 1500, 2500, 3500, 4500, 6000])).toBeCloseTo(122.894855, 6)
})
})

0 comments on commit 2203c3e

Please sign in to comment.