spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
name: dist/Formulas/Financial.js
-rw-r--r--
39655
  1"use strict";
  2exports.__esModule = true;
  3var ArgsChecker_1 = require("../Utilities/ArgsChecker");
  4var TypeConverter_1 = require("../Utilities/TypeConverter");
  5var Errors_1 = require("../Errors");
  6var Date_1 = require("./Date");
  7var Filter_1 = require("../Utilities/Filter");
  8var MoreUtils_1 = require("../Utilities/MoreUtils");
  9/**
 10 * Calculates the depreciation of an asset for a specified period using the double-declining balance method.
 11 * @param cost - The initial cost of the asset.
 12 * @param salvage - The value of the asset at the end of depreciation.
 13 * @param life - The number of periods over which the asset is depreciated.
 14 * @param period - The single period within life for which to calculate depreciation.
 15 * @param factor - [ OPTIONAL - 2 by default ] - The factor by which depreciation decreases.
 16 * @returns {number} depreciation of an asset for a specified period
 17 * @constructor
 18 */
 19var DDB = function (cost, salvage, life, period, factor) {
 20    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 5, "DDB");
 21    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
 22    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
 23    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
 24    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
 25    factor = factor === undefined ? 2 : TypeConverter_1.TypeConverter.firstValueAsNumber(factor);
 26    if (cost < 0) {
 27        throw new Errors_1.NumError("Function DDB parameter 1 value is "
 28            + cost + ". It should be greater than or equal to 0.");
 29    }
 30    if (salvage < 0) {
 31        throw new Errors_1.NumError("Function DDB parameter 2 value is "
 32            + salvage + ". It should be greater than or equal to 0.");
 33    }
 34    if (life < 0) {
 35        throw new Errors_1.NumError("Function DDB parameter 3 value is "
 36            + life + ". It should be greater than or equal to 0.");
 37    }
 38    if (period < 0) {
 39        throw new Errors_1.NumError("Function DDB parameter 4 value is "
 40            + period + ". It should be greater than or equal to 0.");
 41    }
 42    if (period > life) {
 43        throw new Errors_1.NumError("Function DDB parameter 4 value is "
 44            + life + ". It should be less than or equal to value of Function DB parameter 3 with " + period + ".");
 45    }
 46    if (salvage >= cost) {
 47        return 0;
 48    }
 49    var total = 0;
 50    var current = 0;
 51    for (var i = 1; i <= period; i++) {
 52        current = Math.min((cost - total) * (factor / TypeConverter_1.checkForDevideByZero(life)), (cost - salvage - total));
 53        total += current;
 54    }
 55    return current;
 56};
 57exports.DDB = DDB;
 58/**
 59 * Calculates the depreciation of an asset for a specified period using the arithmetic declining balance method.
 60 * @param cost - The initial cost of the asset.
 61 * @param salvage - The value of the asset at the end of depreciation.
 62 * @param life - The number of periods over which the asset is depreciated.
 63 * @param period - The single period within life for which to calculate depreciation.
 64 * @param month - [ OPTIONAL - 12 by default ] - The number of months in the first year of depreciation.
 65 * @returns {number} depreciated value
 66 * @constructor
 67 */
 68var DB = function (cost, salvage, life, period, month) {
 69    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 5, "DB");
 70    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
 71    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
 72    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
 73    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
 74    month = month !== undefined ? Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(month)) : 12;
 75    if (cost < 0) {
 76        throw new Errors_1.NumError("Function DB parameter 1 value is "
 77            + cost + ". It should be greater than or equal to 0.");
 78    }
 79    if (salvage < 0) {
 80        throw new Errors_1.NumError("Function DB parameter 2 value is "
 81            + salvage + ". It should be greater than or equal to 0.");
 82    }
 83    if (life < 0) {
 84        throw new Errors_1.NumError("Function DB parameter 3 value is "
 85            + life + ". It should be greater than or equal to 0.");
 86    }
 87    if (period < 0) {
 88        throw new Errors_1.NumError("Function DB parameter 4 value is "
 89            + period + ". It should be greater than or equal to 0.");
 90    }
 91    if (month > 12 || month < 1) {
 92        throw new Errors_1.NumError("Function DB parameter 5 value is "
 93            + month + ". Valid values are between 1 and 12 inclusive.");
 94    }
 95    if (period > life) {
 96        throw new Errors_1.NumError("Function DB parameter 4 value is "
 97            + life + ". It should be less than or equal to value of Function DB parameter 3 with " + period + ".");
 98    }
 99    if (salvage >= cost) {
100        return 0;
101    }
102    if (cost === 0 && salvage !== 0) {
103        throw new Errors_1.DivZeroError("Evaluation of function DB cause a divide by zero error.");
104    }
105    var rate = (1 - Math.pow(salvage / cost, 1 / life));
106    var initial = cost * rate * month / 12;
107    var total = initial;
108    var current = 0;
109    var ceiling = (period === life) ? life - 1 : period;
110    for (var i = 2; i <= ceiling; i++) {
111        current = (cost - total) * rate;
112        total += current;
113    }
114    if (period === 1) {
115        return initial;
116    }
117    else if (period === life) {
118        return (cost - total) * rate;
119    }
120    else {
121        return current;
122    }
123};
124exports.DB = DB;
125/**
126 * Formats a number into the locale-specific currency format. WARNING: Currently the equivalent of TRUNC, since this
127 * returns numbers
128 * @param number - The value to be formatted.
129 * @param places - [ OPTIONAL - 2 by default ] - The number of decimal places to display.
130 * @returns {number} dollars
131 * @constructor
132 */
133var DOLLAR = function (number, places) {
134    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "DOLLAR");
135    var v = TypeConverter_1.TypeConverter.firstValueAsNumber(number);
136    places = places !== undefined ? TypeConverter_1.TypeConverter.firstValueAsNumber(places) : 2;
137    var sign = (v > 0) ? 1 : -1;
138    var divisor = sign * (Math.floor(Math.abs(v) * Math.pow(10, places)));
139    var pow = Math.pow(10, places);
140    if (pow === 0 && divisor !== 0) {
141        throw new Errors_1.DivZeroError("Evaluation of function DOLLAR cause a divide by zero error.");
142    }
143    return divisor / pow;
144};
145exports.DOLLAR = DOLLAR;
146/**
147 * Converts a price quotation given as a decimal fraction into a decimal value.
148 * @param fractionalPrice - The price quotation given using fractional decimal conventions.
149 * @param unit - The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.
150 * @returns {number} decimal value.
151 * @constructor
152 */
153var DOLLARDE = function (fractionalPrice, unit) {
154    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "DOLLARDE");
155    var dollar = TypeConverter_1.TypeConverter.firstValueAsNumber(fractionalPrice);
156    var fraction = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(unit));
157    if (fraction === 0) {
158        throw new Errors_1.DivZeroError("Function DOLLARDE parameter 2 cannot be zero.");
159    }
160    var result = parseInt(dollar.toString(), 10);
161    result += (dollar % 1) * Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN10)) / fraction;
162    var power = Math.pow(10, Math.ceil(Math.log(fraction) / Math.LN2) + 1);
163    if (power === 0) {
164        throw new Errors_1.DivZeroError("Evaluation of function DOLLARDE cause a divide by zero error.");
165    }
166    result = Math.round(result * power) / power;
167    return result;
168};
169exports.DOLLARDE = DOLLARDE;
170/**
171 * Converts a price quotation given as a decimal value into a decimal fraction.
172 * @param decimalPrice - The price quotation given as a decimal value.
173 * @param unit - The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds
174 * @returns {number} price quotation as decimal fraction.
175 * @constructor
176 */
177var DOLLARFR = function (decimalPrice, unit) {
178    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "DOLLARFR");
179    decimalPrice = TypeConverter_1.TypeConverter.firstValueAsNumber(decimalPrice);
180    unit = Math.floor(TypeConverter_1.TypeConverter.firstValueAsNumber(unit));
181    if (unit === 0) {
182        throw new Errors_1.DivZeroError("Function DOLLARFR parameter 2 cannot be zero.");
183    }
184    var result = parseInt(decimalPrice.toString(), 10);
185    result += (decimalPrice % 1) * Math.pow(10, -Math.ceil(Math.log(unit) / Math.LN10)) * unit;
186    return result;
187};
188exports.DOLLARFR = DOLLARFR;
189/**
190 * Calculates the annual effective interest rate given the nominal rate and number of compounding periods per year.
191 * @param nominalRate - The nominal interest rate per year.
192 * @param periodsPerYear - The number of compounding periods per year.
193 * @returns {number} annual effective interest rate
194 * @constructor
195 */
196var EFFECT = function (nominalRate, periodsPerYear) {
197    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "EFFECT");
198    var rate = TypeConverter_1.TypeConverter.firstValueAsNumber(nominalRate);
199    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periodsPerYear);
200    if (rate <= 0) {
201        throw new Errors_1.NumError("Function EFFECT parameter 1 value is " + rate + ". It should be greater than to 0");
202    }
203    if (periods < 1) {
204        throw new Errors_1.NumError("Function EFFECT parameter 2 value is " + periods + ". It should be greater than or equal to 1");
205    }
206    periods = Math.floor(periods);
207    return Math.pow(1 + rate / periods, periods) - 1;
208};
209exports.EFFECT = EFFECT;
210/**
211 * Calculates the periodic payment for an annuity investment based on constant-amount periodic payments and a constant
212 * interest rate.
213 * @param rate - The interest rate.
214 * @param periods - The number of payments to be made.
215 * @param presentValue - The current value of the annuity.
216 * @param futureValue [ OPTIONAL ] - The future value remaining after the final payment has been made.
217 * @param endOrBeginning [ OPTIONAL - 0 by default ] - Whether payments are due at the end (0) or beginning (1) of each
218 * period.
219 * @returns {number}
220 * @constructor
221 */
222var PMT = function (rate, periods, presentValue, futureValue, endOrBeginning) {
223    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "PMT");
224    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
225    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
226    presentValue = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
227    futureValue = futureValue ? TypeConverter_1.TypeConverter.firstValueAsNumber(futureValue) : 0;
228    endOrBeginning = endOrBeginning ? TypeConverter_1.TypeConverter.firstValueAsNumber(endOrBeginning) : 0;
229    var result;
230    if (rate === 0) {
231        result = (presentValue + futureValue) / periods;
232    }
233    else {
234        var term = Math.pow(1 + rate, periods);
235        if (endOrBeginning) {
236            result = (futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term)) / (1 + rate);
237        }
238        else {
239            result = futureValue * rate / (term - 1) + presentValue * rate / (1 - 1 / term);
240        }
241    }
242    return -result;
243};
244exports.PMT = PMT;
245/**
246 * Returns the future value of an investment based on periodic, constant payments and a constant interest rate.
247 * @param rate - The rate of periodic interest.
248 * @param periods - The total number of periods.
249 * @param payment - The annuity paid regularly per period
250 * @param value - [OPTIONAL] - The present cash value of an investment.
251 * @param type - [OPTIONAL] - Defines whether the payment is due at the beginning (1) or the end (0) of a period.
252 * @returns {number}
253 * @constructor
254 */
255var FV = function (rate, periods, payment, value, type) {
256    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "FV");
257    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
258    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
259    payment = TypeConverter_1.TypeConverter.firstValueAsNumber(payment);
260    value = (typeof value === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(value);
261    type = (typeof type === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
262    var result;
263    if (rate === 0) {
264        result = value + payment * periods;
265    }
266    else {
267        var term = Math.pow(1 + rate, periods);
268        if (type === 0) {
269            result = value * term + payment * (term - 1) / rate;
270        }
271        else {
272            result = value * term + payment * (1 + rate) * (term - 1.0) / rate;
273        }
274    }
275    return -result;
276};
277exports.FV = FV;
278/**
279 * Calculates the cumulative principal paid over a range of payment periods for an investment based on constant-amount
280 * periodic payments and a constant interest rate.
281 * @param rate - The interest rate.
282 * @param numberOfPeriods - The number of payments to be made.
283 * @param presentValue - The current value of the annuity.
284 * @param firstPeriod - The number of the payment period to begin the cumulative calculation. must be greater
285 * than or equal to 1.
286 * @param lastPeriod - The number of the payment period to end the cumulative calculation, must be greater
287 * than first_period.
288 * @param endOrBeginning - Whether payments are due at the end (0) or beginning (1) of each period
289 * @returns {number} cumulative principal
290 * @constructor
291 */
292var CUMPRINC = function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning) {
293    ArgsChecker_1.ArgsChecker.checkLength(arguments, 6, "CUMPRINC");
294    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
295    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfPeriods);
296    var value = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
297    var start = TypeConverter_1.TypeConverter.firstValueAsNumber(firstPeriod);
298    if (start < 1) {
299        throw new Errors_1.NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
300    }
301    var end = TypeConverter_1.TypeConverter.firstValueAsNumber(lastPeriod);
302    if (end < 1) {
303        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
304    }
305    if (end < start) {
306        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
307    }
308    var type = TypeConverter_1.TypeConverter.firstValueAsBoolean(endOrBeginning);
309    var payment = PMT(rate, periods, value, 0, type);
310    var principal = 0;
311    if (start === 1) {
312        if (type) {
313            principal = payment;
314        }
315        else {
316            principal = payment + value * rate;
317        }
318        start++;
319    }
320    for (var i = start; i <= end; i++) {
321        if (type) {
322            principal += payment - (FV(rate, i - 2, payment, value, 1) - payment) * rate;
323        }
324        else {
325            principal += payment - FV(rate, i - 1, payment, value, 0) * rate;
326        }
327    }
328    return principal;
329};
330exports.CUMPRINC = CUMPRINC;
331/**
332 * Calculates the cumulative interest over a range of payment periods for an investment based on constant-amount
333 * periodic payments and a constant interest rate.
334 * @param rate - The interest rate.
335 * @param numberOfPeriods - The number of payments to be made.
336 * @param presentValue - The current value of the annuity.
337 * @param firstPeriod - The number of the payment period to begin the cumulative calculation, must be greater
338 * than or equal to 1.
339 * @param lastPeriod - The number of the payment period to end the cumulative calculation, must be greater
340 * than first_period.
341 * @param endOrBeginning - Whether payments are due at the end (0) or beginning (1) of each period.
342 * @returns {number} cumulative interest
343 * @constructor
344 */
345var CUMIPMT = function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning) {
346    ArgsChecker_1.ArgsChecker.checkLength(arguments, 6, "CUMIPMT");
347    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
348    var periods = TypeConverter_1.TypeConverter.firstValueAsNumber(numberOfPeriods);
349    var value = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
350    var start = TypeConverter_1.TypeConverter.firstValueAsNumber(firstPeriod);
351    if (start < 1) {
352        throw new Errors_1.NumError("Function CUMPRINC parameter 4 value is " + start + ". It should be greater than or equal to 1.");
353    }
354    var end = TypeConverter_1.TypeConverter.firstValueAsNumber(lastPeriod);
355    if (end < 1) {
356        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to 1.");
357    }
358    if (end < start) {
359        throw new Errors_1.NumError("Function CUMPRINC parameter 5 value is " + end + ". It should be greater than or equal to " + start + ".");
360    }
361    var type = TypeConverter_1.TypeConverter.firstValueAsBoolean(endOrBeginning);
362    var payment = PMT(rate, periods, value, 0, type);
363    var interest = 0;
364    if (start === 1) {
365        if (!type) {
366            interest = -value;
367            start++;
368        }
369        else {
370            start++;
371        }
372    }
373    for (var i = start; i <= end; i++) {
374        if (type) {
375            interest += FV(rate, i - 2, payment, value, 1) - payment;
376        }
377        else {
378            interest += FV(rate, i - 1, payment, value, 0);
379        }
380    }
381    interest *= rate;
382    return interest;
383};
384exports.CUMIPMT = CUMIPMT;
385/**
386 * Calculates the accrued interest of a security that has periodic payments.
387 * WARNING: This function has been implemented to specifications as outlined in Google Spreadsheets, LibreOffice, and
388 * OpenOffice. It functions much the same as MSExcel's ACCRINT, but there are several key differences. Below are links
389 * to illustrate the differences. Please see the source code for more information on differences. Links: https://quant.stackexchange.com/questions/7040/whats-the-algorithm-behind-excels-accrint, https://support.office.com/en-us/article/ACCRINT-function-fe45d089-6722-4fb3-9379-e1f911d8dc74, https://quant.stackexchange.com/questions/7040/whats-the-algorithm-behind-excels-accrint, https://support.google.com/docs/answer/3093200 .
390 * @param issue - The date the security was initially issued.
391 * @param firstPayment - The first date interest will be paid.
392 * @param settlement - The settlement date of the security, the date after issuance when the security is
393 * delivered to the buyer. Is the maturity date of the security if it is held until maturity rather than sold.
394 * @param rate - The annualized rate of interest.
395 * @param redemption - The redemption amount per 100 face value, or par.
396 * @param frequency - The number of coupon payments per year. For annual payments, frequency = 1; for
397 * semiannual, frequency = 2; for quarterly, frequency = 4.
398 * @param dayCountConvention - [ OPTIONAL - 0 by default ] - An indicator of what day count method to use.
399 * 0 or omitted = US (NASD) 30/360, 1 = Actual/actual, 2 = Actual/360, 3 = Actual/365, 4 = European 30/360.
400 * @returns {number}
401 * @constructor
402 * TODO: This function is based off of the open-source versions I was able to dig up online. We should implement a
403 * TODO:     second version that is closer to what MSExcel does and is named something like `ACCRINT.MS`.
404 */
405var ACCRINT = function (issue, firstPayment, settlement, rate, redemption, frequency, dayCountConvention) {
406    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 6, 7, "ACCRINT");
407    issue = TypeConverter_1.TypeConverter.firstValueAsDateNumber(issue);
408    // "firstPayment" param is only here to check for errors for GS implementation.
409    // In MSE, there is a 7th (zero-indexed-6th) param that indicates the calculation-method to use, which indicates
410    // weather the total accrued interest starting at the first_intrest date, instead of the issue date.
411    firstPayment = TypeConverter_1.TypeConverter.firstValueAsDateNumber(firstPayment);
412    if (firstPayment < 0) {
413        throw new Errors_1.NumError("Function ACCRINT parameter 2 value is " + firstPayment
414            + ". It should be greater than 0.");
415    }
416    settlement = TypeConverter_1.TypeConverter.firstValueAsDateNumber(settlement);
417    if (issue > settlement) {
418        throw new Errors_1.NumError("Function ACCRINT parameter 1 (" + issue.toString()
419            + ") should be on or before Function ACCRINT parameter 3 (" + settlement.toString() + ").");
420    }
421    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
422    // redemption, aka "par"
423    redemption = TypeConverter_1.TypeConverter.firstValueAsNumber(redemption);
424    // The frequency parameter also does not affect the resulting value of the formula in the GS implementation.
425    // In MSE, frequency is used to calculate a more accurate value, by breaking apart the year, and computing interest
426    // on an on-going basis. In this implementation, we use YEARFRAC to get a numerical value that encompasses the
427    // functionality of "frequency".
428    frequency = TypeConverter_1.TypeConverter.firstValueAsNumber(frequency);
429    // dayCountConvention, aka "basis"
430    dayCountConvention = dayCountConvention !== undefined ? TypeConverter_1.TypeConverter.firstValueAsNumber(dayCountConvention) : 1;
431    var factor = Date_1.YEARFRAC(issue, settlement, dayCountConvention);
432    return redemption * rate * factor;
433};
434exports.ACCRINT = ACCRINT;
435/**
436 * Returns the arithmetic-declining depreciation rate. Use this function to calculate the depreciation amount for one
437 * period of the total depreciation span of an object. Arithmetic declining depreciation reduces the depreciation amount
438 * from period to period by a fixed sum.
439 * @param cost - The initial cost of an asset.
440 * @param salvage - the value of an asset after depreciation.
441 * @param life - The period fixing the time span over which an asset is depreciated.
442 * @param period - The period for which the depreciation is to be calculated.
443 * @returns {number}
444 * @constructor
445 */
446var SYD = function (cost, salvage, life, period) {
447    ArgsChecker_1.ArgsChecker.checkLength(arguments, 4, "SYD");
448    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
449    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
450    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
451    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
452    // Return error if period is lower than 1 or greater than life
453    if (period > life) {
454        throw new Errors_1.NumError("Function SYD parameter 4 value is " + period +
455            ". It should be less than or equal to value of Function SYD parameter 3 with " + life + ".");
456    }
457    if (period < 1) {
458        throw new Errors_1.NumError("Function SYD parameter 4 value is " + period + ". It should be greater than 0.");
459    }
460    period = Math.floor(period);
461    return (cost - salvage) * (life - period + 1) * 2 / (life * (life + 1));
462};
463exports.SYD = SYD;
464/**
465 * Returns the straight-line depreciation of an asset for one period. The amount of the depreciation is constant during
466 * the depreciation period.
467 * @param cost - The initial cost of the asset.
468 * @param salvage - The value of an asset at the end of the depreciation.
469 * @param life - The depreciation period determining the number of periods in the deprecation of the asset.
470 * @returns {number}
471 * @constructor
472 */
473var SLN = function (cost, salvage, life) {
474    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "SYD");
475    cost = TypeConverter_1.TypeConverter.firstValueAsNumber(cost);
476    salvage = TypeConverter_1.TypeConverter.firstValueAsNumber(salvage);
477    life = TypeConverter_1.TypeConverter.firstValueAsNumber(life);
478    if (life === 0) {
479        throw new Errors_1.DivZeroError("Function SLN parameter 3 cannot be zero.");
480    }
481    return (cost - salvage) / life;
482};
483exports.SLN = SLN;
484/**
485 * Returns the net present value of an investment based on a series of periodic cash flows and a discount rate.
486 * @param rate - The discount rate for a period.
487 * @param values - The values representing deposits or withdrawals.
488 * @returns {number}
489 * @constructor
490 * TODO: This function can return results that are prone to floating point precision errors.
491 */
492var NPV = function (rate) {
493    var values = [];
494    for (var _i = 1; _i < arguments.length; _i++) {
495        values[_i - 1] = arguments[_i];
496    }
497    ArgsChecker_1.ArgsChecker.checkAtLeastLength(arguments, 2, "NPV");
498    var range = Filter_1.Filter.flattenAndThrow(values).map(function (value) {
499        try {
500            return TypeConverter_1.TypeConverter.valueToNumber(value);
501        }
502        catch (e) {
503            throw new Errors_1.ValueError("Function NPV expects number values. But '" + value + "' is " + (typeof value)
504                + " and cannot be coerced to a number.");
505        }
506    });
507    var value = 0;
508    for (var i = 0; i < range.length; i++) {
509        value += range[i] / Math.pow(1 + rate, i);
510    }
511    return value;
512};
513exports.NPV = NPV;
514/**
515 * Returns the number of payment for an investment. Number is based on constant-amount payments made periodically and a
516 * constant interest rate.
517 * @param rate - The interest rate.
518 * @param payment - The amount of each payment.
519 * @param present - THe current value.
520 * @param future - [OPTIONAL] - The future value remaining after the final payment has been made.
521 * @param type [OPTIONAL 0 by default] - 1 indicates payments are due at the beginning of each period. 0 indicates
522 * payments are due at the end of each period.
523 * @returns {number}
524 * @constructor
525 */
526var NPER = function (rate, payment, present, future, type) {
527    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "NPER");
528    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
529    payment = TypeConverter_1.TypeConverter.firstValueAsNumber(payment);
530    present = TypeConverter_1.TypeConverter.firstValueAsNumber(present);
531    type = (typeof type === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
532    future = (typeof future === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(future);
533    var num = payment * (1 + rate * type) - future * rate;
534    var den = (present * rate + payment * (1 + rate * type));
535    if (den === 0) {
536        throw new Errors_1.DivZeroError("Evaluation of function NPER cause a divide by zero error.");
537    }
538    var div = Math.log(1 + rate);
539    var logNumDen = Math.log(num / den);
540    if (isNaN(logNumDen)) {
541        throw new Errors_1.NumError("Parameters given function NPER are not possible.");
542    }
543    return logNumDen / div;
544};
545exports.NPER = NPER;
546/**
547 * Calculates the yearly nominal interest rate, given the effective rate and the number of compounding periods per year.
548 * @param rate - The effective interest rate.
549 * @param periods - The number of periodic interest payments per year.
550 * @returns {number}
551 * @constructor
552 */
553var NOMINAL = function (rate, periods) {
554    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "NOMINAL");
555    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
556    periods = Math.round(TypeConverter_1.TypeConverter.firstValueAsNumber(periods));
557    if (periods < 1) {
558        throw new Errors_1.NumError("Function NOMINAL parameter 2 value is " + periods
559            + ". It should be greater than or equal to 1.");
560    }
561    return (Math.pow(rate + 1, 1 / periods) - 1) * periods;
562};
563exports.NOMINAL = NOMINAL;
564/**
565 * Calculates the modified internal rate of return of a series of investments.
566 * @param values - Range or values of payments. Ignores text values.
567 * @param financeRate - The rate of interest of the investments.
568 * @param reinvestRate - The rate of interest of the reinvestment.
569 * @returns {number}
570 * @constructor
571 * TODO: This relies on NPV and will therefore be prone to floating-point errors.
572 */
573var MIRR = function (values, financeRate, reinvestRate) {
574    ArgsChecker_1.ArgsChecker.checkLength(arguments, 3, "MIRR");
575    values = Filter_1.Filter.flattenAndThrow(values).filter(function (value) {
576        return (typeof value !== "string");
577    }).map(function (value) {
578        return TypeConverter_1.TypeConverter.valueToNumber(value);
579    });
580    var n = values.length;
581    var payments = [];
582    var incomes = [];
583    for (var i = 0; i < n; i++) {
584        if (values[i] < 0) {
585            payments.push(values[i]);
586        }
587        else {
588            incomes.push(values[i]);
589        }
590    }
591    if (incomes.length === 0 || payments.length === 0) {
592        throw new Errors_1.DivZeroError("For MIRR, the values must include positive and negative numbers.");
593    }
594    var num = -NPV(reinvestRate, incomes) * Math.pow(1 + reinvestRate, n - 1);
595    var den = NPV(financeRate, payments) * (1 + financeRate);
596    return Math.pow(num / den, 1 / (n - 1)) - 1;
597};
598exports.MIRR = MIRR;
599/**
600 * Calculates the internal rate of return for an investment. The values represent cash flow values at regular intervals;
601 * at least one value must be negative (payments), and at least one value must be positive (income).
602 *
603 * Relevant StackOverflow discussion: https://stackoverflow.com/questions/15089151/javascript-irr-internal-rate-of-return-formula-accuracy
604 *
605 * @param values - Range containing values. Ignores text values.
606 * @param guess - [OPTIONAL] - The estimated value. Defaults to 0.01.
607 * @returns {number}
608 * @constructor
609 */
610var IRR = function (values, guess) {
611    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "IRR");
612    values = Filter_1.Filter.flattenAndThrow(values).filter(function (value) {
613        return (typeof value !== "string");
614    }).map(function (value) {
615        return TypeConverter_1.TypeConverter.valueToNumber(value);
616    });
617    guess = (guess === undefined) ? 0.1 : TypeConverter_1.TypeConverter.firstValueAsNumber(guess);
618    var min = -1.0;
619    var max = 10.0;
620    var val;
621    var counter = 1;
622    var MAX_ITERATIONS = 500000;
623    do {
624        guess = (min + max) / 2;
625        val = 0;
626        for (var j = 0; j < values.length; j++) {
627            val += values[j] / Math.pow((1 + guess), j);
628        }
629        if (val > 0) {
630            min = guess;
631        }
632        else {
633            max = guess;
634        }
635    } while (Math.abs(val) > 0.000001 && ++counter < MAX_ITERATIONS);
636    return guess;
637};
638exports.IRR = IRR;
639/**
640 * Calculates the periodic amortization for an investment with regular payments and a constant interest rate.
641 * @param rate - The periodic interest rate.
642 * @param period - The period for which the compound interest is calculated.
643 * @param periods - The total number of periods during which the annuity is paid.
644 * @param present - The present cash value in sequence of payments.
645 * @param future - [OPTIONAL] - The desired value (future value) at the end of the periods.
646 * @param type - [OPTIONAL] - Defines whether the payment is due at the beginning (1) or the end (0) of a period.
647 * @returns {number}
648 * @constructor
649 */
650var IPMT = function (rate, period, periods, present, future, type) {
651    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 6, "IPMT");
652    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
653    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
654    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
655    present = TypeConverter_1.TypeConverter.firstValueAsNumber(present);
656    future = (typeof future === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(future);
657    type = (typeof type === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
658    var payment = PMT(rate, periods, present, future, type);
659    var interest;
660    if (period === 1) {
661        if (type === 1) {
662            interest = 0;
663        }
664        else {
665            interest = -present;
666        }
667    }
668    else {
669        if (type === 1) {
670            interest = FV(rate, period - 2, payment, present, 1) - payment;
671        }
672        else {
673            interest = FV(rate, period - 1, payment, present, 0);
674        }
675    }
676    return interest * rate;
677};
678exports.IPMT = IPMT;
679/**
680 * Returns for a given period the payment on the principal for an investment that is based on periodic and constant
681 * payments and a constant interest rate.
682 * @param rate - The periodic interest rate.
683 * @param period - The amortization period.
684 * @param periods - The total number of periods during which the annuity is paid.
685 * @param present - The present value in the sequence of payments.
686 * @param future - [OPTIONAL] - The desired future value. Defaults to 0.
687 * @param type - [OPTIONAL] - Indicates how the year is to be calculated. 0 indicates payments are due at end of
688 * period, 1 indicates payments are due at beginning of period. Defaults to 0.
689 * @returns {number}
690 * @constructor
691 */
692var PPMT = function (rate, period, periods, present, future, type) {
693    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 4, 6, "PPMT");
694    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
695    period = TypeConverter_1.TypeConverter.firstValueAsNumber(period);
696    if (period < 1) {
697        throw new Errors_1.NumError("Function PPMT parameter 2 value is " + period + ", but should be greater than or equal to 1.");
698    }
699    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
700    if (periods <= 0) {
701        throw new Errors_1.NumError("Function PPMT parameter 3 value is " + periods + ", but should be greater than 0.");
702    }
703    present = TypeConverter_1.TypeConverter.firstValueAsNumber(present);
704    future = (typeof future === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(future);
705    type = (typeof type === 'undefined') ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
706    return PMT(rate, periods, present, future, type) - IPMT(rate, period, periods, present, future, type);
707};
708exports.PPMT = PPMT;
709/**
710 * Calculates the accumulated value of the starting capital for a series of periodically varying interest rates.
711 * @param principal - The starting capital.
712 * @param rateSchedule - Range or Array that is a series of interest rates.
713 * @returns {number}
714 * @constructor
715 */
716var FVSCHEDULE = function (principal, rateSchedule) {
717    ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "FVSCHEDULE");
718    var future = TypeConverter_1.TypeConverter.firstValueAsNumber(principal);
719    rateSchedule = Filter_1.Filter.flattenAndThrow(rateSchedule);
720    for (var i = 0; i < rateSchedule.length; i++) {
721        // Apply scheduled interest
722        future *= 1 + rateSchedule[i];
723    }
724    return future;
725};
726exports.FVSCHEDULE = FVSCHEDULE;
727/**
728 * Returns the present value of an investment resulting from a series of regular payments.
729 * @param rate - The interest rate per period.
730 * @param periods - The total number of payment periods
731 * @param paymentPerPeriod - The regular payment made per period.
732 * @param future - [OPTIONAL defaults to 0] The future value remaining after the final installment has been made
733 * @param type - [OPTIONAL defaults to 0] Defines whether the payment is due at the beginning (1) or the end (0) of a
734 * period.
735 * @constructor
736 */
737var PV = function (rate, periods, paymentPerPeriod, future, type) {
738    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 5, "PV");
739    rate = TypeConverter_1.TypeConverter.firstValueAsNumber(rate);
740    if (rate < 0) {
741        throw new Errors_1.NumError("Function PV parameter 21value is " + rate + ", but should be greater than or equal to 0.");
742    }
743    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
744    paymentPerPeriod = TypeConverter_1.TypeConverter.firstValueAsNumber(paymentPerPeriod);
745    future = MoreUtils_1.isUndefined(future) ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(future);
746    type = MoreUtils_1.isUndefined(type) ? 0 : TypeConverter_1.TypeConverter.firstValueAsNumber(type);
747    if (rate === 0) {
748        return -paymentPerPeriod * periods - future;
749    }
750    else {
751        return (((1 - Math.pow(1 + rate, periods)) / rate) * paymentPerPeriod * (1 + rate * type) - future) / Math.pow(1 + rate, periods);
752    }
753};
754exports.PV = PV;
755/**
756 * Returns the constant interest rate per period of an annuity.
757 * @param periods - The total number of periods, during which payments are made (payment period).
758 * @param paymentPerPeriod - The constant payment (annuity) paid during each period.
759 * @param presentValue - The cash value in the sequence of payments
760 * @param futureValue - [OPTIONAL defaults to 0] The future value, which is reached at the end of the periodic payments.
761 * @param beginningOrEnd - [OPTIONAL defaults to 0] Defines whether the payment is due at the beginning (1) or the end
762 * (0) of a period.
763 * @param guessRate - [OPTIONAL] - Determines the estimated value of the interest with iterative
764 * calculation.
765 * @constructor
766 */
767var RATE = function (periods, paymentPerPeriod, presentValue, futureValue, beginningOrEnd, guessRate) {
768    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 3, 6, "RATE");
769    periods = TypeConverter_1.TypeConverter.firstValueAsNumber(periods);
770    if (periods < 1) {
771        throw new Errors_1.NumError("Function RATE parameter 1 value is" + periods + ", but it should be greater than 0.");
772    }
773    paymentPerPeriod = TypeConverter_1.TypeConverter.firstValueAsNumber(paymentPerPeriod);
774    presentValue = TypeConverter_1.TypeConverter.firstValueAsNumber(presentValue);
775    futureValue = MoreUtils_1.isDefined(futureValue) ? TypeConverter_1.TypeConverter.firstValueAsNumber(futureValue) : 0;
776    beginningOrEnd = MoreUtils_1.isDefined(beginningOrEnd) ? TypeConverter_1.TypeConverter.firstValueAsNumber(beginningOrEnd) : 0;
777    guessRate = MoreUtils_1.isDefined(guessRate) ? TypeConverter_1.TypeConverter.firstValueAsNumber(guessRate) : 0.1;
778    // Sets the limits for possible guesses to any
779    // number between 0% and 100%
780    var lowLimit = 0;
781    var highLimit = 1;
782    var guess = guessRate;
783    // Defines a tolerance of up to +/- 0.00005% of pmt, to accept
784    // the solution as valid.
785    var tolerance = Math.abs(0.00000005 * paymentPerPeriod);
786    // Tries at most 40 times to find a solution within the tolerance.
787    for (var i = 0; i < 40; i++) {
788        // Resets the balance to the original pv.
789        var balance = presentValue;
790        // Calculates the balance at the end of the loan, based
791        // on loan conditions.
792        for (var j = 0; j < periods; j++) {
793            if (beginningOrEnd == 0) {
794                // Interests applied before payment
795                balance = balance * (1 + guess) + paymentPerPeriod;
796            }
797            else {
798                // Payments applied before insterests
799                balance = (balance + paymentPerPeriod) * (1 + guess);
800            }
801        }
802        // Returns the guess if balance is within tolerance.  If not, adjusts
803        // the limits and starts with a new guess.
804        if (Math.abs(balance + futureValue) < tolerance) {
805            return guess;
806        }
807        else if (balance + futureValue > 0) {
808            // Sets a new highLimit knowing that
809            // the current guess was too big.
810            highLimit = guess;
811        }
812        else {
813            // Sets a new lowLimit knowing that
814            // the current guess was too small.
815            lowLimit = guess;
816        }
817        // Calculates the new guess.
818        guess = (highLimit + lowLimit) / 2;
819    }
820    throw new Errors_1.NumError("RATE attempted to complete but it was not able to.");
821};
822exports.RATE = RATE;