UNPKG

@digifi/jexl-functions

Version:
284 lines (283 loc) 13.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const errors_1 = require("../errors"); const module_1 = require("../utils/module"); const dayjs_1 = __importDefault(require("../dayjs")); const date_and_time_1 = __importDefault(require("./date-and-time")); exports.default = (0, module_1.createModule)(({ safeFlatten, coerceToNumber }, options) => { const dateTimeModule = (0, date_and_time_1.default)(options); const FV = (rate, periods, payment, value, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = coerceToNumber(periods); const coercedPayment = coerceToNumber(payment); const coercedValue = value ? coerceToNumber(value) : 0; const coercedType = type ? coerceToNumber(type) : 0; if (coercedRate === 0) { return -(coercedValue + coercedPayment * coercedPeriods); } const term = Math.pow(1 + coercedRate, coercedPeriods); if (coercedType === 1) { return -(coercedValue * term + (coercedPayment * (1 + coercedRate) * (term - 1)) / coercedRate); } return -(coercedValue * term + (coercedPayment * (term - 1)) / coercedRate); }; const PMT = (rate, periods, present, future, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = coerceToNumber(periods); const coercedPresent = coerceToNumber(present); const coercedFuture = future ? coerceToNumber(future) : 0; const coercedType = type ? coerceToNumber(type) : 0; if (coercedRate === 0) { return -(coercedPresent + coercedFuture) / coercedPeriods; } const term = Math.pow(1 + coercedRate, coercedPeriods); if (coercedType === 1) { return -(((coercedFuture * coercedRate) / (term - 1) + (coercedPresent * coercedRate) / (1 - 1 / term)) / (1 + coercedRate)); } return -((coercedFuture * coercedRate) / (term - 1) + (coercedPresent * coercedRate) / (1 - 1 / term)); }; const ACCRINT = (issue, first, settlement, rate, par, frequency, basis) => { const coercedRate = coerceToNumber(rate); const coercedPar = par ? coerceToNumber(par) : 0; const coercedFrequency = coerceToNumber(frequency); const issueDate = (0, dayjs_1.default)(issue); const firstDate = (0, dayjs_1.default)(first); const settlementDate = (0, dayjs_1.default)(settlement); if (!issueDate.isValid()) { throw new errors_1.JexlFunctionExecutionError('Issue date is not valid.'); } if (!firstDate.isValid()) { throw new errors_1.JexlFunctionExecutionError('First date is not valid.'); } if (!settlementDate.isValid()) { throw new errors_1.JexlFunctionExecutionError('Settlement date is not valid.'); } if (coercedRate <= 0) { throw new errors_1.JexlFunctionExecutionError('Rate is lower or equal 0.'); } if (coercedPar <= 0) { throw new errors_1.JexlFunctionExecutionError('Par is lower or equal 0'); } if (![1, 2, 4].includes(coercedFrequency)) { throw new errors_1.JexlFunctionExecutionError('Frequency should be equal to [1, 2, 4]'); } if (settlementDate <= issueDate) { throw new errors_1.JexlFunctionExecutionError('Settlement date should be greater than issue date'); } return coercedPar * coercedRate * dateTimeModule.YEARFRAC(issue, settlement, basis); }; const CUMIPMT = (rate, periods, value, start, end, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = Math.abs(coerceToNumber(periods)); const coercedValue = coerceToNumber(value); const coercedEnd = Math.abs(coerceToNumber(end)); const coercedStart = Math.abs(coerceToNumber(start)); if (coercedRate <= 0) { throw new errors_1.JexlFunctionExecutionError('Rate should be more than 0.'); } if (coercedPeriods <= 0) { throw new errors_1.JexlFunctionExecutionError('Periods should be more than 0.'); } if (coercedValue <= 0) { throw new errors_1.JexlFunctionExecutionError('Value should be more than 0.'); } if (coercedEnd < coercedStart) { throw new errors_1.JexlFunctionExecutionError('End should be more than start.'); } const differenceBetweenEndAndStart = coercedEnd - coercedStart; if (differenceBetweenEndAndStart > options.defaultMaxArraySize) { throw new errors_1.JexlFunctionExecutionError(`Difference between end and start should be not more than: ${options.defaultMaxArraySize}`); } if (type !== 0 && type !== 1) { throw new errors_1.JexlFunctionExecutionError('Type should be equal 0 or 1.'); } const payment = PMT(coercedRate, coercedPeriods, coercedValue, 0, type); let interest = coercedStart === 1 && type === 0 ? -coercedValue : 0; const startFrom = coercedStart === 1 ? coercedStart + 1 : coercedStart; for (let i = startFrom; i <= coercedEnd; i++) { if (type === 1) { interest = interest + FV(coercedRate, i - 2, payment, coercedValue, 1) - payment; } else { interest = interest + FV(coercedRate, i - 1, payment, coercedValue, 0); } } return interest * coercedRate; }; const CUMPRINC = (rate, periods, value, start, end, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = Math.abs(coerceToNumber(periods)); const coercedValue = coerceToNumber(value); const coercedEnd = Math.abs(coerceToNumber(end)); const coercedStart = Math.abs(coerceToNumber(start)); const coercedType = type ? coerceToNumber(type) : 0; if (coercedRate <= 0) { throw new errors_1.JexlFunctionExecutionError('Rate should be more than 0.'); } if (coercedPeriods <= 0) { throw new errors_1.JexlFunctionExecutionError('Periods should be more than 0.'); } if (coercedValue <= 0) { throw new errors_1.JexlFunctionExecutionError('Value should be more than 0.'); } if (coercedEnd < coercedStart) { throw new errors_1.JexlFunctionExecutionError('End should be more than start.'); } let principal = 0; const payment = PMT(coercedRate, coercedPeriods, coercedValue, 0, coercedType); const startFrom = coercedStart === 1 ? coercedStart + 1 : coercedStart; if (startFrom === 1) { principal = coercedType === 0 ? payment + coercedValue * coercedRate : payment; } for (let i = startFrom; i <= coercedEnd; i++) { if (coercedType > 0) { principal = principal + payment - (FV(coercedRate, i - 2, payment, coercedValue, 1) - payment) * coercedRate; } else { principal = principal + payment - FV(coercedRate, i - 1, payment, coercedValue, 0) * coercedRate; } } return principal; }; const IPMT = (rate, period, periods, present, future, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriod = coerceToNumber(period); const coercedPresent = coerceToNumber(present); const coercedType = type ? coerceToNumber(type) : 0; const payment = PMT(rate, periods, present, future, type); if (coercedPeriod === 1) { return type === 1 ? 0 : (-coercedPresent * coercedRate); } return coercedType === 1 ? (FV(coercedRate, coercedPeriod - 2, payment, coercedPresent, 1) - payment) * coercedRate : (FV(coercedRate, coercedPeriod - 1, payment, coercedPresent, 0)) * coercedRate; }; const EFFECT = (rate, periods) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = coerceToNumber(periods); if (coercedRate <= 0 || coercedPeriods < 1) { throw new errors_1.JexlFunctionExecutionError('Incorrect incoming arguments.'); } const flooredPeriods = Math.trunc(coercedPeriods); return Math.pow(1 + coercedRate / flooredPeriods, flooredPeriods) - 1; }; const RATE = (periods, payment, present, future, type, guess) => { const coercedGuess = guess === undefined ? 0.01 : coerceToNumber(guess); const coercedFuture = future ? coerceToNumber(future) : 0; const coercedType = type ? 1 : 0; const coercedPeriods = coerceToNumber(periods); const coercedPayment = coerceToNumber(payment); const coercedPresent = coerceToNumber(present); const epsMax = 1e-10; const maxIterations = 20; let rate = coercedGuess; for (let i = 0; i < maxIterations; i++) { if (rate <= -1) { throw new errors_1.JexlFunctionExecutionError('Incorrect rate.'); } let y; let f; if (Math.abs(rate) < epsMax) { y = coercedPresent * (1 + coercedPeriods * rate) + coercedPayment * (1 + rate * coercedType) * coercedPeriods + coercedFuture; } else { f = Math.pow(1 + rate, coercedPeriods); y = coercedPresent * f + coercedPayment * (1 / rate + coercedType) * (f - 1) + coercedFuture; } if (Math.abs(y) < epsMax) { return rate; } let dy; if (Math.abs(rate) < epsMax) { dy = coercedPresent * coercedPeriods + coercedPayment * coercedType * coercedPeriods; } else { const df = coercedPeriods * Math.pow(1 + rate, coercedPeriods - 1); f = Math.pow(1 + rate, coercedPeriods); dy = coercedPresent * df + coercedPayment * (1 / rate + coercedType) * df + coercedPayment * (-1 / (rate * rate)) * (f - 1); } rate = rate - y / dy; } return rate; }; const ISPMT = (rate, period, periods, value) => { return coerceToNumber(value) * coerceToNumber(rate) * (coerceToNumber(period) / coerceToNumber(periods) - 1); }; const NOMINAL = (rate, periods) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = coerceToNumber(periods); if (coercedRate <= 0 || coercedPeriods < 1) { throw new errors_1.JexlFunctionExecutionError('Incorrect arguments.'); } const flooredPeriods = Math.trunc(coercedPeriods); return (Math.pow(coercedRate + 1, 1 / flooredPeriods) - 1) * flooredPeriods; }; const NPER = (rate, payment, present, future, type) => { const coercedType = type ? coerceToNumber(type) : 0; const coercedFuture = future ? coerceToNumber(future) : 0; const coercedRate = coerceToNumber(rate); const coercedPayment = coerceToNumber(payment); const coercedPresent = coerceToNumber(present); if (coercedRate === 0) { return -(coercedPresent + coercedFuture) / coercedPayment; } const num = coercedPayment * (1 + coercedRate * coercedType) - coercedFuture * coercedRate; const den = coercedPresent * coercedRate + coercedPayment * (1 + coercedRate * coercedType); return Math.log(num / den) / Math.log(1 + coercedRate); }; const NPV = (rate, ...args) => { const coercedRate = coerceToNumber(rate); return safeFlatten(args).reduce((result, arg, index) => { return result + coerceToNumber(arg) / Math.pow(1 + coercedRate, index + 1); }, 0); }; const PDURATION = (rate, present, future) => { const coercedRate = coerceToNumber(rate); if (coercedRate <= 0) { throw new errors_1.JexlFunctionExecutionError('Invalid arguments.'); } return (Math.log(coerceToNumber(future)) - Math.log(coerceToNumber(present))) / Math.log(1 + coercedRate); }; const PPMT = (rate, period, periods, present, future, type) => { return PMT(rate, periods, present, future, type) - IPMT(rate, period, periods, present, future, type); }; const PV = (rate, periods, payment, future, type) => { const coercedRate = coerceToNumber(rate); const coercedPeriods = coerceToNumber(periods); const coercedPayment = coerceToNumber(payment); const coercedFuture = future ? coerceToNumber(future) : 0; const coercedType = type ? coerceToNumber(type) : 0; if (coercedRate === 0) { return -coercedPayment * coercedPeriods - coercedFuture; } return ((((1 - Math.pow(1 + coercedRate, coercedPeriods)) / coercedRate) * coercedPayment * (1 + coercedRate * coercedType) - coercedFuture) / Math.pow(1 + coercedRate, coercedPeriods)); }; const DELTA = (firstValue, secondValue) => { return firstValue === secondValue ? 1 : 0; }; return { EFFECT, FV, PMT, IPMT, RATE, ISPMT, NOMINAL, NPER, NPV, PDURATION, PPMT, PV, DELTA, ACCRINT, CUMPRINC, CUMIPMT, }; });