commit
message
[Financial] adding PMT formula and tests
author
Ben Vogt <[email protected]>
date
2017-05-13 21:32:09
stats
3 file(s) changed,
60 insertions(+),
13 deletions(-)
files
src/Formulas/Financial.ts
src/Utilities/ArgsChecker.ts
tests/Formulas/FinancialTest.ts
1diff --git a/src/Formulas/Financial.ts b/src/Formulas/Financial.ts
2index 1c2f28c..c78b892 100644
3--- a/src/Formulas/Financial.ts
4+++ b/src/Formulas/Financial.ts
5@@ -219,21 +219,39 @@ var EFFECT = function (...values) : number {
6 return Math.pow(1 + rate / periods, periods) - 1;
7 };
8
9-// TODO: Convert to real formula PMT.
10-function pmt(rate, periods, present, future, type) {
11+
12+/**
13+ * Calculates the periodic payment for an annuity investment based on constant-amount periodic payments and a constant
14+ * interest rate.
15+ * @param rate - The interest rate.
16+ * @param periods - The number of payments to be made.
17+ * @param presentValue - The current value of the annuity.
18+ * @param futureValue [ OPTIONAL ] - The future value remaining after the final payment has been made.
19+ * @param endOrBeginning [ OPTIONAL - 0 by default ] - Whether payments are due at the end (0) or beginning (1) of each
20+ * period.
21+ * @returns {number}
22+ * @constructor
23+ */
24+var PMT = function (rate, periods, presentValue, futureValue?, endOrBeginning?) : number {
25+ ArgsChecker.checkLengthWithin(arguments, 3, 5, "PMT");
26+ rate = TypeConverter.firstValueAsNumber(rate);
27+ periods = TypeConverter.firstValueAsNumber(periods);
28+ presentValue = TypeConverter.firstValueAsNumber(presentValue);
29+ futureValue = futureValue ? TypeConverter.firstValueAsNumber(futureValue) : 0;
30+ endOrBeginning = endOrBeginning ? TypeConverter.firstValueAsNumber(endOrBeginning) : 0;
31 var result;
32 if (rate === 0) {
33- result = (present + future) / periods;
34+ result = (presentValue + futureValue) / periods;
35 } else {
36 var term = Math.pow(1 + rate, periods);
37- if (type) {
38- result = (future * rate / (term - 1) + present * rate / (1 - 1 / term)) / (1 + rate);
39+ if (endOrBeginning) {
40+ result = (futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term)) / (1 + rate);
41 } else {
42- result = future * rate / (term - 1) + present * rate / (1 - 1 / term);
43+ result = futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term);
44 }
45 }
46 return -result;
47-}
48+};
49
50 // TODO: Convert to real formula FV
51 function fv(rate, periods, payment, value, type) {
52@@ -283,7 +301,7 @@ var CUMPRINC = function (...values) : number {
53 }
54 var type = TypeConverter.firstValueAsBoolean(values[5]);
55
56- var payment = pmt(rate, periods, value, 0, type);
57+ var payment = PMT(rate, periods, value, 0, type);
58 var principal = 0;
59 if (start === 1) {
60 if (type) {
61@@ -335,7 +353,7 @@ var CUMIPMT = function (...values) : number {
62 }
63 var type = TypeConverter.firstValueAsBoolean(values[5]);
64
65- var payment = pmt(rate, periods, value, 0, type);
66+ var payment = PMT(rate, periods, value, 0, type);
67 var interest = 0;
68 if (start === 1) {
69 if (!type) {
70@@ -422,5 +440,6 @@ export {
71 DOLLAR,
72 DOLLARDE,
73 DOLLARFR,
74- EFFECT
75+ EFFECT,
76+ PMT
77 }
78\ No newline at end of file
79diff --git a/src/Utilities/ArgsChecker.ts b/src/Utilities/ArgsChecker.ts
80index cc85633..5c40cb3 100644
81--- a/src/Utilities/ArgsChecker.ts
82+++ b/src/Utilities/ArgsChecker.ts
83@@ -44,8 +44,8 @@ class ArgsChecker {
84 static checkLengthWithin(args: any, low: number, high: number, caller?: string) {
85 if (args.length > high || args.length < low) {
86 var functionName = caller !== undefined ? " to " + caller : "";
87- throw new NAError("Wrong number of arguments" + functionName + ". Expected between" + low
88- + "and " + high + " arguments, but got " + args.length + " arguments.");
89+ throw new NAError("Wrong number of arguments" + functionName + ". Expected between " + low
90+ + " and " + high + " arguments, but got " + args.length + " arguments.");
91 }
92 }
93 }
94diff --git a/tests/Formulas/FinancialTest.ts b/tests/Formulas/FinancialTest.ts
95index e9b6e41..06ca457 100644
96--- a/tests/Formulas/FinancialTest.ts
97+++ b/tests/Formulas/FinancialTest.ts
98@@ -7,7 +7,8 @@ import {
99 DOLLAR,
100 DOLLARDE,
101 DOLLARFR,
102- EFFECT
103+ EFFECT,
104+ PMT
105 } from "../../src/Formulas/Financial";
106 import {
107 DATE
108@@ -244,3 +245,27 @@ test("EFFECT", function(){
109 EFFECT(0.99, []);
110 }, ERRORS.REF_ERROR);
111 });
112+
113+
114+test("PMT", function() {
115+ assertEquals(PMT(0.05/12, 30*12, 100000), -536.8216230121382);
116+ assertEquals(PMT(0.05/12, 30*12, 100000, 10000), -548.8371186466853);
117+ assertEquals(PMT(0.05/12, 30*12, 100000, 10000, 0), -548.8371186466853);
118+ assertEquals(PMT(0.05/12, 30*12, 100000, 10000, false), -548.8371186466853);
119+ assertEquals(PMT(0.05/12, 30*12, 100000, 10000, 1), -546.559786204168);
120+ assertEquals(PMT(0.05/12, 30*12, 100000, 10000, 100), -546.559786204168);
121+ assertEquals(PMT([0.05/12, []], [30*12], ["100000"]), -536.8216230121382);
122+ assertEquals(PMT(-0.0001, 30*12, 100000, 10000, 1), -301.1033887993179);
123+ assertEquals(PMT(-0.0001, 1, 100000, 10000, 1), -110001.000100094);
124+ assertEquals(PMT(-0.0001, 1, 0, 10000, 1), -10001.0001000111);
125+ assertEquals(PMT(-0.0001, 1, 0, 0, 1), 0);
126+ catchAndAssertEquals(function() {
127+ PMT.apply(this, [[[0.05/12]], [], ["100000"]]);
128+ }, ERRORS.REF_ERROR);
129+ catchAndAssertEquals(function() {
130+ PMT.apply(this);
131+ }, ERRORS.NA_ERROR);
132+ catchAndAssertEquals(function() {
133+ PMT.apply(this, [0.05/12, 30*12, 100000, 10000, 1, "nope"]);
134+ }, ERRORS.NA_ERROR);
135+});
136\ No newline at end of file