spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
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);