commit
message
[Financial.PV] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-10-04 01:34:21
stats
8 file(s) changed,
105 insertions(+),
8 deletions(-)
files
DOCS.md
TODO.md
dist/Formulas/AllFormulas.js
dist/Formulas/Financial.js
src/Formulas/AllFormulas.ts
src/Formulas/Financial.ts
tests/Formulas/FinancialTest.ts
tests/SheetFormulaTest.ts
1diff --git a/DOCS.md b/DOCS.md
2index 71d4089..44a9ed9 100644
3--- a/DOCS.md
4+++ b/DOCS.md
5@@ -602,6 +602,18 @@
6 @returns {number}
7 @constructor
8 ```
9+
10+### PV
11+
12+```
13+ Returns the present value of an investment resulting from a series of regular payments.
14+@param rate - The interest rate per period.
15+@param periods - The total number of payment periods
16+@param paymentPerPeriod - The regular payment made per period.
17+@param future - [OPTIONAL defaults to 0] The future value remaining after the final installment has been made
18+@param type - [OPTIONAL defaults to 0] Defines whether the payment is due at the beginning (1) or the end (0) of a period.
19+@constructor
20+```
21 ## Info
22
23
24diff --git a/TODO.md b/TODO.md
25index 90fa502..fe68aca 100644
26--- a/TODO.md
27+++ b/TODO.md
28@@ -88,7 +88,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
29 * PRICE
30 * PRICEDISC
31 * PRICEMAT
32-* PV
33 * RATE
34 * RECEIVED
35 * YIELD
36diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
37index 7d9fc23..fbb5f3d 100644
38--- a/dist/Formulas/AllFormulas.js
39+++ b/dist/Formulas/AllFormulas.js
40@@ -147,6 +147,7 @@ exports.IPMT = Financial_1.IPMT;
41 exports.FV = Financial_1.FV;
42 exports.PPMT = Financial_1.PPMT;
43 exports.FVSCHEDULE = Financial_1.FVSCHEDULE;
44+exports.PV = Financial_1.PV;
45 var Statistical_1 = require("./Statistical");
46 exports.AVERAGE = Statistical_1.AVERAGE;
47 exports.AVERAGEA = Statistical_1.AVERAGEA;
48diff --git a/dist/Formulas/Financial.js b/dist/Formulas/Financial.js
49index f859d6c..2018ab1 100644
50--- a/dist/Formulas/Financial.js
51+++ b/dist/Formulas/Financial.js
52@@ -5,6 +5,7 @@ var TypeConverter_1 = require("../Utilities/TypeConverter");
53 var Errors_1 = require("../Errors");
54 var Date_1 = require("./Date");
55 var Filter_1 = require("../Utilities/Filter");
56+var MoreUtils_1 = require("../Utilities/MoreUtils");
57 /**
58 * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
59 * @param cost - The initial cost of the asset.
60@@ -723,3 +724,31 @@ var FVSCHEDULE = function (principal, rateSchedule) {
61 return future;
62 };
63 exports.FVSCHEDULE = FVSCHEDULE;
64+/**
65+ * Returns the present value of an investment resulting from a series of regular payments.
66+ * @param rate - The interest rate per period.
67+ * @param periods - The total number of payment periods
68+ * @param paymentPerPeriod - The regular payment made per period.
69+ * @param future - [OPTIONAL defaults to 0] The future value remaining after the final installment has been made
70+ * @param type - [OPTIONAL defaults to 0] Defines whether the payment is due at the beginning (1) or the end (0) of a
71+ * period.
72+ * @constructor
73+ */
74+var PV = function (rate, periods, paymentPerPeriod, future, type) {
75+ ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "PV");
76+ rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
77+ if (rate < 0) {
78+ throw new Errors_1.NumError("Function PV parameter 21value is " + rate + ", but should be greater than or equal to 0.");
79+ }
80+ periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
81+ paymentPerPeriod = TypeConverter_1.TypeConverter.firstValueAsNumber(paymentPerPeriod);
82+ future = MoreUtils_1.isUndefined(future) ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(future);
83+ type = MoreUtils_1.isUndefined(type) ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
84+ if (rate === 0) {
85+ return -paymentPerPeriod * periods - future;
86+ }
87+ else {
88+ return (((1 - Math.pow(1 + rate, periods)) / rate) * paymentPerPeriod * (1 + rate * type) - future) / Math.pow(1 + rate, periods);
89+ }
90+};
91+exports.PV = PV;
92diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
93index b1f1e4f..d70f881 100644
94--- a/src/Formulas/AllFormulas.ts
95+++ b/src/Formulas/AllFormulas.ts
96@@ -151,7 +151,8 @@ import {
97 IPMT,
98 FV,
99 PPMT,
100- FVSCHEDULE
101+ FVSCHEDULE,
102+ PV
103 } from "./Financial";
104 import {
105 AVERAGE,
106@@ -519,5 +520,6 @@ export {
107 SERIESSUM,
108 ROMAN,
109 TEXT,
110- FVSCHEDULE
111+ FVSCHEDULE,
112+ PV
113 }
114\ No newline at end of file
115diff --git a/src/Formulas/Financial.ts b/src/Formulas/Financial.ts
116index 5a48078..457457f 100644
117--- a/src/Formulas/Financial.ts
118+++ b/src/Formulas/Financial.ts
119@@ -13,6 +13,7 @@ import {
120 YEARFRAC
121 } from "./Date";
122 import {Filter} from "../Utilities/Filter";
123+import {isUndefined} from "../Utilities/MoreUtils";
124
125
126 /**
127@@ -737,6 +738,34 @@ let FVSCHEDULE = function (principal, rateSchedule) {
128 };
129
130
131+/**
132+ * Returns the present value of an investment resulting from a series of regular payments.
133+ * @param rate - The interest rate per period.
134+ * @param periods - The total number of payment periods
135+ * @param paymentPerPeriod - The regular payment made per period.
136+ * @param future - [OPTIONAL defaults to 0] The future value remaining after the final installment has been made
137+ * @param type - [OPTIONAL defaults to 0] Defines whether the payment is due at the beginning (1) or the end (0) of a
138+ * period.
139+ * @constructor
140+ */
141+let PV = function (rate, periods, paymentPerPeriod, future?, type?) {
142+ ArgsChecker.checkLengthWithin(arguments, 3, 5, "PV");
143+ rate = TypeConverter.firstValueAsNumber(rate);
144+ if (rate < 0) {
145+ throw new NumError("Function PV parameter 21value is " + rate + ", but should be greater than or equal to 0.");
146+ }
147+ periods = TypeConverter.firstValueAsNumber(periods);
148+ paymentPerPeriod = TypeConverter.firstValueAsNumber(paymentPerPeriod);
149+ future = isUndefined(future) ? 0 : TypeConverter.firstValueAsNumber(future);
150+ type = isUndefined(type) ? 0 : TypeConverter.firstValueAsNumber(type);
151+ if (rate === 0) {
152+ return -paymentPerPeriod * periods - future;
153+ } else {
154+ return (((1 - Math.pow(1 + rate, periods)) / rate) * paymentPerPeriod * (1 + rate * type) - future) / Math.pow(1 + rate, periods);
155+ }
156+};
157+
158+
159 export {
160 ACCRINT,
161 CUMPRINC,
162@@ -758,5 +787,6 @@ export {
163 IPMT,
164 FV,
165 PPMT,
166- FVSCHEDULE
167+ FVSCHEDULE,
168+ PV
169 }
170\ No newline at end of file
171diff --git a/tests/Formulas/FinancialTest.ts b/tests/Formulas/FinancialTest.ts
172index a41a1af..cd5ba32 100644
173--- a/tests/Formulas/FinancialTest.ts
174+++ b/tests/Formulas/FinancialTest.ts
175@@ -19,7 +19,8 @@ import {
176 IPMT,
177 FV,
178 PPMT,
179- FVSCHEDULE
180+ FVSCHEDULE,
181+ PV
182 } from "../../src/Formulas/Financial";
183 import {
184 DATE
185@@ -478,4 +479,25 @@ test("FVSCHEDULE", function() {
186 catchAndAssertEquals(function() {
187 FVSCHEDULE.apply(this, [0.025]);
188 }, ERRORS.NA_ERROR);
189+});
190+
191+
192+test("PV", function() {
193+ assertEquals(PV(2, 12, 100), -49.99990591617884);
194+ assertEquals(PV(2, 12, 200), -99.99981183235768);
195+ assertEquals(PV(2, -1, 200), 200.00000000000003);
196+ assertEquals(PV(2, 1, 0), 0);
197+ assertEquals(PV(2, 1, 0, 100), -33.333333333333336);
198+ assertEquals(PV(2, 1, 0, 100), -33.333333333333336);
199+ assertEquals(PV(2, 3, 100, 100, 1), -148.14814814814815);
200+ assertEquals(PV(2, 3, 100, 100, 0), -51.851851851851855);
201+ catchAndAssertEquals(function() {
202+ PV(-1, 12, 100);
203+ }, ERRORS.NUM_ERROR);
204+ catchAndAssertEquals(function() {
205+ PV.apply(this, [0, 1]);
206+ }, ERRORS.NA_ERROR);
207+ catchAndAssertEquals(function() {
208+ PV.apply(this, [0, 1, 2, 3, 4, 5]);
209+ }, ERRORS.NA_ERROR);
210 });
211\ No newline at end of file
212diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
213index d40a6ae..4bbb5ef 100644
214--- a/tests/SheetFormulaTest.ts
215+++ b/tests/SheetFormulaTest.ts
216@@ -1021,10 +1021,14 @@ test("Sheet TEXT", function(){
217 assertFormulaEquals('=TEXT(12.3, "###.##")', "12.3");
218 });
219
220-test("Sheet TEXT", function(){
221+test("Sheet FVSCHEDULE", function(){
222 assertFormulaEquals('=FVSCHEDULE([0.025], [1, 2, 3, 4])', 3.0000000000000004);
223 });
224
225+test("Sheet PV", function(){
226+ assertFormulaEquals('=PV(2, 12, 100)', -49.99990591617884);
227+});
228+
229 test("Sheet parsing error", function(){
230 assertFormulaEqualsError('= 10e', PARSE_ERROR);
231 assertFormulaEqualsError('= SUM(', PARSE_ERROR);