@travishorn/financejs 1.0.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -48
- package/package.json +5 -4
- package/src/cumipmt.js +58 -0
- package/src/cumprinc.js +62 -0
- package/src/db.js +60 -0
- package/src/ddb.js +49 -0
- package/src/effect.js +41 -0
- package/src/fv.js +32 -9
- package/src/index.js +16 -5
- package/src/ipmt.js +31 -10
- package/src/irr.js +45 -8
- package/src/mirr.js +59 -0
- package/src/nominal.js +36 -0
- package/src/normalizeZero.js +22 -0
- package/src/nper.js +23 -9
- package/src/npv.js +45 -9
- package/src/pmt.js +30 -9
- package/src/ppmt.js +27 -8
- package/src/pv.js +47 -10
- package/src/rate.js +62 -18
- package/src/sln.js +16 -0
- package/src/syd.js +22 -0
- package/src/xirr.js +137 -0
- package/src/xnpv.js +72 -0
package/src/ipmt.js
CHANGED
|
@@ -1,19 +1,40 @@
|
|
|
1
|
-
import { fv } from "./fv.js";
|
|
1
|
+
import { fv as calculateFv } from "./fv.js";
|
|
2
2
|
import { pmt } from "./pmt.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Returns the interest payment for a given period for an investment based on
|
|
6
|
+
* periodic, constant payments and a constant interest rate.
|
|
7
|
+
*
|
|
8
|
+
* Remarks:
|
|
9
|
+
* - Make sure that you are consistent about the units you use for specifying
|
|
10
|
+
* `rate` and `nper`. If you make monthly payments on a four-year loan at 12
|
|
11
|
+
* percent annual interest, use `.12/12` for `rate` and `4*12` for `nper`. If
|
|
12
|
+
* you make annual payments on the same loan, use `.12` for `rate` and `4` for
|
|
13
|
+
* `nper`.
|
|
14
|
+
* - For all the arguments, cash you pay out, such as deposits to savings, is
|
|
15
|
+
* represented by negative numbers. Cash you receive, such as dividend checks,
|
|
16
|
+
* is represented by positive numbers.
|
|
6
17
|
*
|
|
7
18
|
* @param {number} rate - The interest rate per period.
|
|
8
|
-
* @param {number} per - The
|
|
9
|
-
*
|
|
10
|
-
* @param {number}
|
|
11
|
-
* @param {number}
|
|
12
|
-
*
|
|
19
|
+
* @param {number} per - The period for which you want to find the interest and
|
|
20
|
+
* must be in the range `1` to `nper`.
|
|
21
|
+
* @param {number} nper - The total number of payment periods in an annuity.
|
|
22
|
+
* @param {number} pv - The present value, or the lump-sum amount that a series
|
|
23
|
+
* of future payments is worth right now.
|
|
24
|
+
* @param {number} [fv=0] - The future value, or a cash balance you
|
|
25
|
+
* want to attain after the last payment is made. If `fv` is omitted, it is
|
|
26
|
+
* assumed to be `0` (the future value of a loan, for example, is `0`).
|
|
27
|
+
* @param {0|1} [type=0] - The number `0` or `1` and indicates when payments are
|
|
28
|
+
* due. If type is omitted, it is assumed to be `0`. Set `type` equal to `0` if
|
|
29
|
+
* payments are due at the end of the period. Set `type` equal to `1` if
|
|
30
|
+
* payments are due at the beginning of the period.
|
|
13
31
|
* @returns {number} The interest payment for the specified period.
|
|
14
32
|
* @throws {RangeError} When `per` is outside the valid range.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ipmt(0.1 / 12, 1, 3, 8000); // -66.67
|
|
15
36
|
*/
|
|
16
|
-
export function ipmt(rate, per, nper, pv,
|
|
37
|
+
export function ipmt(rate, per, nper, pv, fv = 0, type = 0) {
|
|
17
38
|
if (per <= 0 || per >= nper + 1) {
|
|
18
39
|
throw new RangeError("Invalid period.");
|
|
19
40
|
}
|
|
@@ -23,9 +44,9 @@ export function ipmt(rate, per, nper, pv, futureValue = 0, type = 0) {
|
|
|
23
44
|
}
|
|
24
45
|
|
|
25
46
|
const periodOffset = type !== 0 ? 2 : 1;
|
|
26
|
-
const periodicPayment = pmt(rate, nper, pv,
|
|
47
|
+
const periodicPayment = pmt(rate, nper, pv, fv, type);
|
|
27
48
|
const adjustedPresentValue = type !== 0 ? pv + periodicPayment : pv;
|
|
28
|
-
const periodFutureValue =
|
|
49
|
+
const periodFutureValue = calculateFv(
|
|
29
50
|
rate,
|
|
30
51
|
per - periodOffset,
|
|
31
52
|
periodicPayment,
|
package/src/irr.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Computes the net present value (NPV) of a series of cash flows at a given
|
|
3
|
+
* discount rate.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Used internally by the IRR algorithm to evaluate the present value of cash
|
|
6
|
+
* flows for a specific rate guess. Skips leading zero cash flows for
|
|
7
|
+
* efficiency. Cash flows are discounted in reverse order, from last to first
|
|
8
|
+
* nonzero value.
|
|
9
|
+
*
|
|
10
|
+
* @param {number[]} values - Array of cash flows, where each entry represents a
|
|
11
|
+
* payment (negative) or income (positive) at a regular interval.
|
|
12
|
+
* @param {number} [guess=0.1] - Discount rate guess (as a decimal, e.g., 0.1
|
|
13
|
+
* for 10%).
|
|
14
|
+
* @returns {number} The net present value of the cash flows at the supplied
|
|
15
|
+
* discount rate.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* internalPv([-1000, 300, 400, 500], 0.1); // -21.036814425244188
|
|
7
19
|
*/
|
|
8
20
|
function internalPv(values, guess = 0.1) {
|
|
9
21
|
let lowerBound = 0;
|
|
@@ -24,12 +36,37 @@ function internalPv(values, guess = 0.1) {
|
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
/**
|
|
27
|
-
* Calculates the internal rate of return for a series of cash flows
|
|
39
|
+
* Calculates the internal rate of return for a series of cash flows represented
|
|
40
|
+
* by the numbers in `values`. These cash flows do not have to be even, as they
|
|
41
|
+
* would be for an annuity. However, the cash flows must occur at regular
|
|
42
|
+
* intervals, such as monthly or annually. The internal rate of return is the
|
|
43
|
+
* interest rate received for an investment consisting of payments (negative
|
|
44
|
+
* values) and income (positive values) that occur at regular periods.
|
|
45
|
+
*
|
|
46
|
+
* Remarks:
|
|
47
|
+
* - Uses an iterative technique for calculating IRR. Starting with guess, this
|
|
48
|
+
* function cycles through the calculation until the result is accurate within
|
|
49
|
+
* a small absolute threshold. If this function can't find a result that works
|
|
50
|
+
* after 39 tries, a RangeError is thrown.
|
|
51
|
+
* - `irr()` is closely related to `npv()`, the net present value function. The
|
|
52
|
+
* rate of return calculated by this function is the interest rate
|
|
53
|
+
* corresponding to a 0 (zero) net present value.
|
|
28
54
|
*
|
|
29
|
-
* @param {number[]} values -
|
|
30
|
-
*
|
|
55
|
+
* @param {number[]} values - An array that contains numbers for which you want
|
|
56
|
+
* to calculate the internal rate of return. Values must contain at least one
|
|
57
|
+
* positive value and one negative value to calculate the internal rate of
|
|
58
|
+
* return. This function uses the order of values to interpret the order of cash
|
|
59
|
+
* flows. Be sure to enter your payment and income values in the sequence you
|
|
60
|
+
* want.
|
|
61
|
+
* @param {number} [guess=0.1] - A number that you guess is close to the result
|
|
62
|
+
* of this function. In most cases you do not need to provide guess for this
|
|
63
|
+
* calculation. If a RangeError is thrown, or if the result is not close to what
|
|
64
|
+
* you expected, try again with a different value for `guess`.
|
|
31
65
|
* @returns {number} The internal rate of return.
|
|
32
|
-
* @throws {RangeError} When inputs are invalid or the algorithm cannot
|
|
66
|
+
* @throws {RangeError} When inputs are invalid or the algorithm cannot
|
|
67
|
+
* converge.
|
|
68
|
+
* @example
|
|
69
|
+
* irr([-70000,12000,15000,18000,21000]); // -0.021244848272975403
|
|
33
70
|
*/
|
|
34
71
|
export function irr(values, guess = 0.1) {
|
|
35
72
|
if (guess <= -1) {
|
package/src/mirr.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the modified internal rate of return for a series of periodic cash
|
|
3
|
+
* flows. Considers both the cost of the investment and the interest received on
|
|
4
|
+
* reinvestment of cash.
|
|
5
|
+
*
|
|
6
|
+
* Remarks:
|
|
7
|
+
* - Uses the order of values to interpret the order of cash flows. Be sure to
|
|
8
|
+
* enter your payment and income values in the sequence you want and with the
|
|
9
|
+
* correct signs (positive values for cash received, negative values for cash
|
|
10
|
+
* paid).
|
|
11
|
+
* - If `n` is the number of cash flows in values, `frate` is the `financeRate`,
|
|
12
|
+
* and `rrate` is the `reinvestRate`, then the equation is: `((-NPV(rrate,
|
|
13
|
+
* values[positive]) * (1 + rrate)) / (NPV(frate, values[negative]) * (1 +
|
|
14
|
+
* frate)))^(1 / (n - 1)) - 1`
|
|
15
|
+
*
|
|
16
|
+
* @param {number[]} values - An array that contains numbers. These numbers
|
|
17
|
+
* represent a series of payments (negative values) and income (positive values)
|
|
18
|
+
* occurring at regular periods. Values must contain at least one positive value
|
|
19
|
+
* and one negative value to calculate the modified internal rate of return.
|
|
20
|
+
* Otherwise, an error is thrown (divide by zero).
|
|
21
|
+
* @param {number} [financeRate] - The interest rate you pay on the money used in the cash flows.
|
|
22
|
+
* @param {number} [reinvestRate] - The interest rate you receive on the cash flows as you reinvest them.
|
|
23
|
+
* @returns {number} the modified internal rate of return
|
|
24
|
+
* @throws {RangeError} If `values` is not an array of at least two elements, or if there are not both positive and negative cash flows.
|
|
25
|
+
* @throws {TypeError} If `financeRate` or `reinvestRate` is not a number.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* mirr([-120000, 39000, 30000, 21000, 37000, 46000], 0.1, 0.12); // 0.12609413
|
|
29
|
+
*/
|
|
30
|
+
export function mirr(values, financeRate, reinvestRate) {
|
|
31
|
+
if (!Array.isArray(values) || values.length < 2) {
|
|
32
|
+
throw new RangeError("values must be an array with at least two elements");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (typeof financeRate !== "number" || typeof reinvestRate !== "number") {
|
|
36
|
+
throw new TypeError("financeRate and reinvestRate must be numbers");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const n = values.length;
|
|
40
|
+
let fvPos = 0;
|
|
41
|
+
let pvNeg = 0;
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < n; i++) {
|
|
44
|
+
const v = values[i];
|
|
45
|
+
if (v > 0) {
|
|
46
|
+
fvPos += v * Math.pow(1 + reinvestRate, n - 1 - i);
|
|
47
|
+
} else if (v < 0) {
|
|
48
|
+
pvNeg += v * Math.pow(1 + financeRate, i);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (fvPos === 0 || pvNeg === 0) {
|
|
53
|
+
throw new RangeError(
|
|
54
|
+
"At least one negative and one positive cash flow required",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return Math.pow(fvPos / -pvNeg, 1 / (n - 1)) - 1;
|
|
59
|
+
}
|
package/src/nominal.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates the nominal annual interest rate, given the effective rate and the
|
|
3
|
+
* number of compounding periods per year.
|
|
4
|
+
*
|
|
5
|
+
* Remarks:
|
|
6
|
+
* - `npery` is truncated to an integer.
|
|
7
|
+
* - If either argument is nonnumeric, an error is thrown.
|
|
8
|
+
* - If `effectRate` <= `0` or if `npery` < `1`, an error is thrown.
|
|
9
|
+
* - `nominal()` is related to `effect()` through `effectiveRate = (1 +
|
|
10
|
+
* (nominalRate / npery)) * npery - 1`.
|
|
11
|
+
*
|
|
12
|
+
* @param {number} effectRate - The effective interest rate.
|
|
13
|
+
* @param {number} npery - The number of compounding periods per year.
|
|
14
|
+
* @returns {number} the nominal annual interest rate
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* nominal(0.053543, 4); // 0.05250032
|
|
18
|
+
*/
|
|
19
|
+
export function nominal(effectRate, npery) {
|
|
20
|
+
if (
|
|
21
|
+
typeof effectRate !== "number" ||
|
|
22
|
+
typeof npery !== "number" ||
|
|
23
|
+
isNaN(effectRate) ||
|
|
24
|
+
isNaN(npery)
|
|
25
|
+
) {
|
|
26
|
+
throw new TypeError("Both arguments must be numbers");
|
|
27
|
+
}
|
|
28
|
+
if (effectRate <= 0) {
|
|
29
|
+
throw new RangeError("effectRate must be > 0");
|
|
30
|
+
}
|
|
31
|
+
npery = Math.trunc(npery);
|
|
32
|
+
if (npery < 1) {
|
|
33
|
+
throw new RangeError("npery must be >= 1");
|
|
34
|
+
}
|
|
35
|
+
return npery * (Math.pow(1 + effectRate, 1 / npery) - 1);
|
|
36
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes zero values to ensure consistent handling of positive and negative
|
|
3
|
+
* zero in calculations.
|
|
4
|
+
*
|
|
5
|
+
* In JavaScript, +0 and -0 are distinct values that can yield different results
|
|
6
|
+
* in equality checks (e.g., Object.is(+0, -0) is false), sign checks
|
|
7
|
+
* (Math.sign), and division (1/0 vs 1/-0). This function coerces any zero input
|
|
8
|
+
* (either +0 or -0) to positive zero (+0), providing a consistent
|
|
9
|
+
* representation for downstream calculations, comparisons, and serialization.
|
|
10
|
+
*
|
|
11
|
+
* @param {number} value - The numeric value to normalize. If the value is +0 or
|
|
12
|
+
* -0, returns +0; otherwise, returns the original value.
|
|
13
|
+
* @returns {number} The normalized value, with all zeroes represented as +0.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* normalizeZero(-0); // 0
|
|
17
|
+
* normalizeZero(+0); // 0
|
|
18
|
+
* normalizeZero(5); // 5
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeZero(value) {
|
|
21
|
+
return value === 0 ? 0 : value;
|
|
22
|
+
}
|
package/src/nper.js
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
|
+
import { normalizeZero } from "./normalizeZero.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Calculates the number of periods for an investment
|
|
4
|
+
* Calculates the number of periods for an investment based on periodic,
|
|
5
|
+
* constant payments and a constant interest rate.
|
|
3
6
|
*
|
|
4
|
-
* @param {number} rate -
|
|
5
|
-
* @param {number} pmt -
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
7
|
+
* @param {number} rate - The interest rate per period.
|
|
8
|
+
* @param {number} pmt - The payment made each period; it cannot change over the
|
|
9
|
+
* life of the annuity. Typically, `pmt` contains principal and interest but no
|
|
10
|
+
* other fees or taxes.
|
|
11
|
+
* @param {number} pv - The present value, or the lump-sum amount that a series
|
|
12
|
+
* of future payments is worth right now.
|
|
13
|
+
* @param {number} [fv=0] - The future value, or a cash balance you want to
|
|
14
|
+
* attain after the last payment is made. If `fv` is omitted, it is assumed to
|
|
15
|
+
* be `0` (the future value of a loan, for example, is 0).
|
|
16
|
+
* @param {0|1} [type=0] - The number 0 or 1 and indicates when payments are
|
|
17
|
+
* due. Set `type` equal to `0` or omitted if payments are due at the end of the
|
|
18
|
+
* period. Set `type` equal to `1` if payments are due at the beginning of the
|
|
19
|
+
* period.
|
|
9
20
|
* @returns {number} Number of periods.
|
|
10
21
|
* @throws {RangeError} When calculation is impossible with the provided inputs.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* nper(0.12 / 12, -100, -1000, 10000, 1); // 59.67386567
|
|
11
25
|
*/
|
|
12
26
|
export function nper(rate, pmt, pv, fv = 0, type = 0) {
|
|
13
27
|
if (rate === 0) {
|
|
@@ -15,7 +29,7 @@ export function nper(rate, pmt, pv, fv = 0, type = 0) {
|
|
|
15
29
|
throw new RangeError("Payment cannot be 0 when rate is 0.");
|
|
16
30
|
}
|
|
17
31
|
|
|
18
|
-
return -(pv + fv) / pmt;
|
|
32
|
+
return normalizeZero(-(pv + fv) / pmt);
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
const paymentAdjustment = type !== 0 ? pmt * (1 + rate) : pmt;
|
|
@@ -34,8 +48,8 @@ export function nper(rate, pmt, pv, fv = 0, type = 0) {
|
|
|
34
48
|
|
|
35
49
|
const growthFactor = 1 + rate;
|
|
36
50
|
|
|
37
|
-
return (
|
|
51
|
+
return normalizeZero(
|
|
38
52
|
(Math.log(futureValueTerm) - Math.log(presentValueTerm)) /
|
|
39
|
-
|
|
53
|
+
Math.log(growthFactor),
|
|
40
54
|
);
|
|
41
55
|
}
|
package/src/npv.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Calculates the net present value (NPV) of a subset of cash flows at a
|
|
3
|
+
* specified discount rate.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Used internally by the `npv()` function to evaluate the present value of cash
|
|
6
|
+
* flows between given indices. Each cash flow is discounted to its present
|
|
7
|
+
* value using the supplied rate, starting from lowerBound to upperBound
|
|
8
|
+
* (inclusive).
|
|
9
|
+
*
|
|
10
|
+
* @param {number} rate - Discount rate per period (as a decimal, e.g., `0.1`
|
|
11
|
+
* for 10%).
|
|
12
|
+
* @param {number[]} values - Array of cash flows, where each entry represents a
|
|
13
|
+
* payment (negative) or income (positive) at a regular interval.
|
|
14
|
+
* @param {number} [lowerBound=0] - Start index (inclusive) for the range of
|
|
15
|
+
* values to evaluate.
|
|
16
|
+
* @param {number} [upperBound=values.length - 1] - End index (inclusive) for
|
|
17
|
+
* the range of values to evaluate.
|
|
18
|
+
* @returns {number} The net present value of the specified range of cash flows
|
|
19
|
+
* at the given discount rate.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* evalNpv(0.1, [-1000, 300, 400, 500], 0, 2); // -360.6311044327573
|
|
9
23
|
*/
|
|
10
24
|
function evalNpv(rate, values, lowerBound = 0, upperBound = values.length - 1) {
|
|
11
25
|
let discountFactor = 1;
|
|
@@ -21,12 +35,34 @@ function evalNpv(rate, values, lowerBound = 0, upperBound = values.length - 1) {
|
|
|
21
35
|
}
|
|
22
36
|
|
|
23
37
|
/**
|
|
24
|
-
* Calculates the net present value of
|
|
38
|
+
* Calculates the net present value of an investment by using a discount rate
|
|
39
|
+
* and a series of future payments (negative values) and income (positive
|
|
40
|
+
* values).
|
|
25
41
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
42
|
+
* Remarks:
|
|
43
|
+
* - The NPV investment begins one period before the date of the first value in
|
|
44
|
+
* the cash flow and ends with the last value in the cash flow. The NPV
|
|
45
|
+
* calculation is based on future cash flows. If your first cash flow occurs
|
|
46
|
+
* at the beginning of the first period, the first value must be added to the
|
|
47
|
+
* NPV result, not included in the values arguments.
|
|
48
|
+
* - `npv()` is similar to the `pv()` function (present value). The primary
|
|
49
|
+
* difference between `pv()` and `npv()` is that `pv()` allows cash flows to
|
|
50
|
+
* begin either at the end or at the beginning of the period. Unlike the
|
|
51
|
+
* variable NPV cash flow values, PV cash flows must be constant throughout
|
|
52
|
+
* the investment.
|
|
53
|
+
* - `npv()` is also related to the `irr()` function (internal rate of return).
|
|
54
|
+
* IRR is the rate for which NPV equals zero: `npv(irr(...), ...) = 0`.
|
|
55
|
+
*
|
|
56
|
+
* @param {number} rate - The rate of discount over the length of one period.
|
|
57
|
+
* @param {...number} values - At least one value is required. Values must be
|
|
58
|
+
* equally spaced in time and occur at the end of each period. This function
|
|
59
|
+
* uses the order of the values to interpret the order of cash flows. Be sure to
|
|
60
|
+
* enter your payment and income values in the correct sequence.
|
|
28
61
|
* @returns {number} The net present value.
|
|
29
62
|
* @throws {RangeError} When there are no cash flow values or rate is invalid.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* npv(0.1, -10000, 3000, 4200, 6800); // 1188.44
|
|
30
66
|
*/
|
|
31
67
|
export function npv(rate, ...values) {
|
|
32
68
|
if (values.length < 1) {
|
package/src/pmt.js
CHANGED
|
@@ -1,25 +1,46 @@
|
|
|
1
|
+
import { normalizeZero } from "./normalizeZero.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Calculates the
|
|
4
|
+
* Calculates the payment for a loan based on constant payments and a constant
|
|
5
|
+
* interest rate.
|
|
6
|
+
*
|
|
7
|
+
* Remarks:
|
|
8
|
+
* - The payment returned by this function includes principal and interest but
|
|
9
|
+
* no taxes, reserve payments, or fees sometimes associated with loans.
|
|
10
|
+
* - Make sure that you are consistent about the units you use for specifying
|
|
11
|
+
* `rate` and `nper`. If you make monthly payments on a four-year loan at an
|
|
12
|
+
* annual interest rate of 12 percent, use `0.12 / 12` for `rate` and `4 * 12`
|
|
13
|
+
* for `nper`. If you make annual payments on the same loan, use `0.12` for
|
|
14
|
+
* `rate` and `4` for `nper`.
|
|
3
15
|
*
|
|
4
|
-
* @param {number} rate - The interest rate
|
|
5
|
-
* @param {number} nper - The total number of
|
|
6
|
-
* @param {number} pv - The present value
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
16
|
+
* @param {number} rate - The interest rate for the loan.
|
|
17
|
+
* @param {number} nper - The total number of payments for the loan.
|
|
18
|
+
* @param {number} pv - The present value, or the total amount that a series of
|
|
19
|
+
* future payments is worth now; also known as the principal.
|
|
20
|
+
* @param {number} [fv=0] - The future value, or a cash balance you want to
|
|
21
|
+
* attain after the last payment is made. If `fv `is omitted, it is assumed to
|
|
22
|
+
* be `0 `(zero), that is, the future value of a loan is 0.
|
|
23
|
+
* @param {0|1} [type=0] - The number `0` (zero) or `1` and indicates when
|
|
24
|
+
* payments are due. Set `type` equal to `0` or omitted if payments are due at
|
|
25
|
+
* the end of the period. Set `type` equal to `1` if payments are due at the
|
|
26
|
+
* beginning of the period.
|
|
9
27
|
* @returns {number} The periodic payment amount.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* pmt(0.08 / 12, 10, 10000); // -1037.03
|
|
10
31
|
*/
|
|
11
32
|
export function pmt(rate, nper, pv, fv = 0, type = 0) {
|
|
12
33
|
if (rate === 0) {
|
|
13
|
-
return (-fv - pv) / nper;
|
|
34
|
+
return normalizeZero((-fv - pv) / nper);
|
|
14
35
|
} else {
|
|
15
36
|
const paymentTimingFactor = type !== 0 ? 1 + rate : 1;
|
|
16
37
|
const interestFactor = 1 + rate;
|
|
17
38
|
const compoundFactor = Math.pow(interestFactor, nper);
|
|
18
39
|
|
|
19
|
-
return (
|
|
40
|
+
return normalizeZero(
|
|
20
41
|
((-fv - pv * compoundFactor) /
|
|
21
42
|
(paymentTimingFactor * (compoundFactor - 1))) *
|
|
22
|
-
|
|
43
|
+
rate,
|
|
23
44
|
);
|
|
24
45
|
}
|
|
25
46
|
}
|
package/src/ppmt.js
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
import { ipmt } from "./ipmt.js";
|
|
2
|
+
import { normalizeZero } from "./normalizeZero.js";
|
|
2
3
|
import { pmt } from "./pmt.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
* Calculates the
|
|
6
|
+
* Calculates the payment on the principal for a given period for an investment
|
|
7
|
+
* based on periodic, constant payments and a constant interest rate.
|
|
8
|
+
*
|
|
9
|
+
* Remarks:
|
|
10
|
+
* - Make sure that you are consistent about the units you use for specifying
|
|
11
|
+
* `rate` and `nper`. If you make monthly payments on a four-year loan at 12
|
|
12
|
+
* percent annual interest, use `0.12 / 12` for `rate` and `4 * 12` for
|
|
13
|
+
* `nper`. If you make annual payments on the same loan, use `0.12` for `rate`
|
|
14
|
+
* and `4` for `nper`.
|
|
6
15
|
*
|
|
7
16
|
* @param {number} rate - The interest rate per period.
|
|
8
|
-
* @param {number} per -
|
|
9
|
-
*
|
|
10
|
-
* @param {number}
|
|
11
|
-
* @param {number}
|
|
12
|
-
*
|
|
13
|
-
* @
|
|
17
|
+
* @param {number} per - Specifies the period and must be in the range `1` to
|
|
18
|
+
* `nper`.
|
|
19
|
+
* @param {number} nper - The total number of payment periods in an annuity.
|
|
20
|
+
* @param {number} pv - The present value — the total amount that a series of
|
|
21
|
+
* future payments is worth now.
|
|
22
|
+
* @param {number} [futureValue=0] - The future value, or a cash balance you
|
|
23
|
+
* want to attain after the last payment is made. If `fv` is omitted, it is
|
|
24
|
+
* assumed to be `0` (zero), that is, the future value of a loan is 0.
|
|
25
|
+
* @param {0|1} [type=0] - The number `0` (zero) or `1` and indicates when
|
|
26
|
+
* payments are due. Set `type` equal to `0` or omitted if payments are due at
|
|
27
|
+
* the end of the period. Set `type` equal to `1` if payments are due at the
|
|
28
|
+
* beginning of the period.
|
|
29
|
+
* @returns {number} The payment on the principal for the specified period.
|
|
14
30
|
* @throws {RangeError} When `per` is outside the valid range.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ppmt(0.1 / 12, 1, 2 * 12, 2000); // -75.62
|
|
15
34
|
*/
|
|
16
35
|
export function ppmt(rate, per, nper, pv, futureValue = 0, type = 0) {
|
|
17
36
|
if (per <= 0 || per >= nper + 1) {
|
|
@@ -21,5 +40,5 @@ export function ppmt(rate, per, nper, pv, futureValue = 0, type = 0) {
|
|
|
21
40
|
const periodicPayment = pmt(rate, nper, pv, futureValue, type);
|
|
22
41
|
const interestPayment = ipmt(rate, per, nper, pv, futureValue, type);
|
|
23
42
|
|
|
24
|
-
return periodicPayment - interestPayment;
|
|
43
|
+
return normalizeZero(periodicPayment - interestPayment);
|
|
25
44
|
}
|
package/src/pv.js
CHANGED
|
@@ -1,24 +1,61 @@
|
|
|
1
|
+
import { normalizeZero } from "./normalizeZero.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Calculates the present value of an investment based on a
|
|
4
|
+
* Calculates the present value of a loan or an investment, based on a constant
|
|
5
|
+
* interest rate. You can use PV with either periodic, constant payments (such
|
|
6
|
+
* as a mortgage or other loan), or a future value that's your investment goal.
|
|
7
|
+
*
|
|
8
|
+
* Remarks:
|
|
9
|
+
* - Make sure that you are consistent about the units you use for specifying
|
|
10
|
+
* `rate` and `nper`. If you make monthly payments on a four-year loan at 12
|
|
11
|
+
* percent annual interest, use 12%/12 for `rate` and 4*12 for `nper`. If you
|
|
12
|
+
* make annual payments on the same loan, use 12% for `rate` and 4 for `nper`.
|
|
13
|
+
* - An annuity is a series of constant cash payments made over a continuous
|
|
14
|
+
* period. For example, a car loan or a mortgage is an annuity.
|
|
15
|
+
* - In annuity functions, cash you pay out, such as a deposit to savings, is
|
|
16
|
+
* represented by a negative number. Cash you receive, such as a dividend
|
|
17
|
+
* check, is represented by a positive number. For example, a $1,000 deposit
|
|
18
|
+
* to the bank would be represented by the argument -1000 if you are the
|
|
19
|
+
* depositor and by the argument 1000 if you are the bank.
|
|
3
20
|
*
|
|
4
|
-
* @param {number} rate - The interest rate per period.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
21
|
+
* @param {number} rate - The interest rate per period. For example, if you
|
|
22
|
+
* obtain an automobile loan at a 10 percent annual interest rate and make
|
|
23
|
+
* monthly payments, your interest rate per month is 10%/12, or 0.83%. You would
|
|
24
|
+
* enter 10%/12, or 0.83%, or 0.0083, into the formula as the rate.
|
|
25
|
+
* @param {number} nper - The total number of payment periods in an annuity. For
|
|
26
|
+
* example, if you get a four-year car loan and make monthly payments, your loan
|
|
27
|
+
* has 4*12 (or 48) periods. You would enter 48 into the formula for nper.
|
|
28
|
+
* @param {number} [pmt=0] - The payment made each period and cannot change over
|
|
29
|
+
* the life of the annuity. Typically, pmt includes principal and interest but
|
|
30
|
+
* no other fees or taxes. For example, the monthly payments on a $10,000,
|
|
31
|
+
* four-year car loan at 12 percent are $263.33. You would enter -263.33 into
|
|
32
|
+
* the formula as the pmt. If pmt is omitted, you must include the fv argument.
|
|
33
|
+
* @param {number} [fv=0] - The future value or a cash balance you want to
|
|
34
|
+
* attain after the last payment is made. If fv is omitted, it is assumed to be
|
|
35
|
+
* 0 (the future value of a loan, for example, is 0). For example, if you want
|
|
36
|
+
* to save $50,000 to pay for a special project in 18 years, then $50,000 is the
|
|
37
|
+
* future value. You could then make a conservative guess at an interest rate
|
|
38
|
+
* and determine how much you must save each month. If fv is omitted, you must
|
|
39
|
+
* include the pmt argument.
|
|
40
|
+
* @param {0|1} [type=0] - The number 0 or 1 and indicates when payments are
|
|
41
|
+
* due. Set `type` equal to `0` or omitted if payments are due at the end of the
|
|
42
|
+
* period. Set `type` equal to `1` if payments are due at the end of the period.
|
|
9
43
|
* @returns {number} The present value of the investment.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* pv(0.08 / 12, 20 * 12, 500); // -59777.15
|
|
10
47
|
*/
|
|
11
|
-
export function pv(rate, nper, pmt, fv = 0, type = 0) {
|
|
48
|
+
export function pv(rate, nper, pmt = 0, fv = 0, type = 0) {
|
|
12
49
|
if (rate === 0) {
|
|
13
|
-
return -pmt * nper - fv;
|
|
50
|
+
return normalizeZero(-pmt * nper - fv);
|
|
14
51
|
} else {
|
|
15
52
|
const paymentTimingFactor = type !== 0 ? 1 + rate : 1;
|
|
16
53
|
const interestFactor = 1 + rate;
|
|
17
54
|
const compoundFactor = Math.pow(interestFactor, nper);
|
|
18
55
|
|
|
19
|
-
return (
|
|
56
|
+
return normalizeZero(
|
|
20
57
|
-(fv + pmt * paymentTimingFactor * ((compoundFactor - 1) / rate)) /
|
|
21
|
-
|
|
58
|
+
compoundFactor,
|
|
22
59
|
);
|
|
23
60
|
}
|
|
24
61
|
}
|
package/src/rate.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
import { normalizeZero } from "./normalizeZero.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Evaluates the
|
|
4
|
+
* Evaluates the annuity equation for a candidate interest rate.
|
|
5
|
+
*
|
|
6
|
+
* Used internally by the `rate()` function to compute the result of the annuity
|
|
7
|
+
* equation for a given rate guess. This function supports both ordinary
|
|
8
|
+
* annuities (payments at end of period) and annuities due (payments at
|
|
9
|
+
* beginning of period), and accounts for present value, future value, and
|
|
10
|
+
* periodic payments.
|
|
11
|
+
*
|
|
12
|
+
* @param {number} rate - Candidate interest rate per period (as a decimal,
|
|
13
|
+
* e.g., `0.1` for 10%).
|
|
14
|
+
* @param {number} nper - Total number of payment periods.
|
|
15
|
+
* @param {number} pmt - Payment made each period (negative for outflows,
|
|
16
|
+
* positive for inflows).
|
|
17
|
+
* @param {number} pv - Present value (the lump sum amount at the start).
|
|
18
|
+
* @param {number} [fv=0] - Future value (the desired balance after the last
|
|
19
|
+
* payment; defaults to `0`).
|
|
20
|
+
* @param {0|1} [type=0] - Payment timing: `0` = end of period (ordinary annuity),
|
|
21
|
+
* `1` = beginning of period (annuity due).
|
|
22
|
+
* @returns {number} The result of the annuity equation for the supplied rate
|
|
23
|
+
* and parameters. A value close to zero indicates a solution for the interest
|
|
24
|
+
* rate.
|
|
3
25
|
*
|
|
4
|
-
* @
|
|
5
|
-
*
|
|
6
|
-
* @param {number} pmt - Periodic payment.
|
|
7
|
-
* @param {number} pv - Present value.
|
|
8
|
-
* @param {number} [fv=0] - Future value.
|
|
9
|
-
* @param {0|1} [type=0] - Payment timing: 0 = end of period, 1 = beginning.
|
|
10
|
-
* @returns {number} Equation result for the supplied rate.
|
|
26
|
+
* @example
|
|
27
|
+
* evalRate(0.05, 12, -100, 1000, 0, 0); // 204.1436739778701
|
|
11
28
|
*/
|
|
12
29
|
function evalRate(rate, nper, pmt, pv, fv = 0, type = 0) {
|
|
13
30
|
if (rate === 0) {
|
|
@@ -26,16 +43,43 @@ function evalRate(rate, nper, pmt, pv, fv = 0, type = 0) {
|
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
/**
|
|
29
|
-
* Calculates the interest rate per period
|
|
46
|
+
* Calculates the interest rate per period of an annuity. The rate is calculated
|
|
47
|
+
* by iteration and can have zero or more solutions. If the successive results
|
|
48
|
+
* of this function do not converge to within 0.0000001 after 128 iterations, a
|
|
49
|
+
* RangeError is thrown.
|
|
50
|
+
*
|
|
51
|
+
* Remarks:
|
|
52
|
+
* - Make sure that you are consistent about the units you use for specifying
|
|
53
|
+
* `rate` and `nper`. If you make monthly payments on a four-year loan at 12
|
|
54
|
+
* percent annual interest, use `0.12 / 12` for `rate` and `4 * 12` for
|
|
55
|
+
* `nper`. If you make annual payments on the same loan, use `0.12` for `rate`
|
|
56
|
+
* and `4` for `nper`.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} nper - The total number of payment periods in an annuity.
|
|
59
|
+
* @param {number} pmt - The payment made each period and cannot change over the
|
|
60
|
+
* life of the annuity. Typically, `pmt` includes principal and interest but no
|
|
61
|
+
* other fees or taxes. If `pmt` is omitted, you must include the `fv` argument
|
|
62
|
+
* for a meaningful equation.
|
|
63
|
+
* @param {number} pv - The present value — the total amount that a series of
|
|
64
|
+
* future payments is worth now.
|
|
65
|
+
* @param {number} [fv=0] - The future value, or a cash balance you want to
|
|
66
|
+
* attain after the last payment is made. If `fv` is omitted, it is assumed to
|
|
67
|
+
* be `0` (the future value of a loan, for example, is 0). If `fv` is omitted,
|
|
68
|
+
* you must include the `pmt` argument.
|
|
69
|
+
* @param {0|1} [type=0] - The number `0` (zero) or `1` and indicates when
|
|
70
|
+
* payments are due. Set `type` equal to `0` or omitted if payments are due at
|
|
71
|
+
* the end of the period. Set `type` equal to `1` if payments are due at the
|
|
72
|
+
* beginning of the period.
|
|
73
|
+
* @param {number} [guess=0.1] - Your guess for what the rate will be. If you
|
|
74
|
+
* omit `guess`, it is assumed to be `0.1` (10 percent). If the calculation does
|
|
75
|
+
* not converge, try different values for `guess`. The calculation usually
|
|
76
|
+
* converges if guess is between `0` and `1`.
|
|
77
|
+
* @returns {number} The calculated interest rate per period of an annuity.
|
|
78
|
+
* @throws {RangeError} When inputs are invalid or the algorithm cannot
|
|
79
|
+
* converge.
|
|
30
80
|
*
|
|
31
|
-
* @
|
|
32
|
-
*
|
|
33
|
-
* @param {number} pv - Present value.
|
|
34
|
-
* @param {number} [fv=0] - Future value.
|
|
35
|
-
* @param {0|1} [type=0] - Payment timing: 0 = end of period, 1 = beginning.
|
|
36
|
-
* @param {number} [guess=0.1] - Initial guess for rate.
|
|
37
|
-
* @returns {number} The calculated rate per period.
|
|
38
|
-
* @throws {RangeError} When inputs are invalid or the algorithm cannot converge.
|
|
81
|
+
* @example
|
|
82
|
+
* rate(4 * 12, -200, 8000); // 0.007701472488210098
|
|
39
83
|
*/
|
|
40
84
|
export function rate(nper, pmt, pv, fv = 0, type = 0, guess = 0.1) {
|
|
41
85
|
if (nper <= 0) {
|
|
@@ -66,7 +110,7 @@ export function rate(nper, pmt, pv, fv = 0, type = 0, guess = 0.1) {
|
|
|
66
110
|
y0 = evalRate(rate0, nper, pmt, pv, fv, type);
|
|
67
111
|
|
|
68
112
|
if (Math.abs(y0) < epsilonMax) {
|
|
69
|
-
return rate0;
|
|
113
|
+
return normalizeZero(rate0);
|
|
70
114
|
}
|
|
71
115
|
|
|
72
116
|
const nextY = y0;
|