Extract ACCRINT() and ACCRINTM() Financial functions into their own class (#1956)
* Extract ACCRINT() and ACCRINTM() Financial functions into their own class Implement additional validations, with additional unit tests Add support for the new calculation method argument for ACCRINT() * Additional tests for Amortization functions
This commit is contained in:
parent
d36f9d5a23
commit
c699d144e2
|
|
@ -233,12 +233,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'ACCRINT' => [
|
'ACCRINT' => [
|
||||||
'category' => Category::CATEGORY_FINANCIAL,
|
'category' => Category::CATEGORY_FINANCIAL,
|
||||||
'functionCall' => [Financial::class, 'ACCRINT'],
|
'functionCall' => [Financial\Securities\AccruedInterest::class, 'periodic'],
|
||||||
'argumentCount' => '4-7',
|
'argumentCount' => '4-8',
|
||||||
],
|
],
|
||||||
'ACCRINTM' => [
|
'ACCRINTM' => [
|
||||||
'category' => Category::CATEGORY_FINANCIAL,
|
'category' => Category::CATEGORY_FINANCIAL,
|
||||||
'functionCall' => [Financial::class, 'ACCRINTM'],
|
'functionCall' => [Financial\Securities\AccruedInterest::class, 'atMaturity'],
|
||||||
'argumentCount' => '3-5',
|
'argumentCount' => '3-5',
|
||||||
],
|
],
|
||||||
'ACOS' => [
|
'ACOS' => [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
trait BaseValidations
|
||||||
|
{
|
||||||
|
protected static function validateFloat($value): float
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateInt($value): int
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) floor($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class BesselI
|
class BesselI
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BESSELI.
|
* BESSELI.
|
||||||
*
|
*
|
||||||
|
|
@ -32,18 +35,20 @@ class BesselI
|
||||||
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
||||||
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
||||||
|
|
||||||
if ((is_numeric($x)) && (is_numeric($ord))) {
|
try {
|
||||||
$ord = (int) floor($ord);
|
$x = self::validateFloat($x);
|
||||||
if ($ord < 0) {
|
$ord = self::validateInt($ord);
|
||||||
return Functions::NAN();
|
} catch (Exception $e) {
|
||||||
}
|
return $e->getMessage();
|
||||||
|
|
||||||
$fResult = self::calculate((float) $x, $ord);
|
|
||||||
|
|
||||||
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
if ($ord < 0) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fResult = self::calculate($x, $ord);
|
||||||
|
|
||||||
|
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calculate(float $x, int $ord): float
|
private static function calculate(float $x, int $ord): float
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class BesselJ
|
class BesselJ
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BESSELJ.
|
* BESSELJ.
|
||||||
*
|
*
|
||||||
|
|
@ -30,18 +33,20 @@ class BesselJ
|
||||||
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
||||||
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
|
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
|
||||||
|
|
||||||
if ((is_numeric($x)) && (is_numeric($ord))) {
|
try {
|
||||||
$ord = (int) floor($ord);
|
$x = self::validateFloat($x);
|
||||||
if ($ord < 0) {
|
$ord = self::validateInt($ord);
|
||||||
return Functions::NAN();
|
} catch (Exception $e) {
|
||||||
}
|
return $e->getMessage();
|
||||||
|
|
||||||
$fResult = self::calculate((float) $x, $ord);
|
|
||||||
|
|
||||||
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
if ($ord < 0) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fResult = self::calculate($x, $ord);
|
||||||
|
|
||||||
|
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calculate(float $x, int $ord): float
|
private static function calculate(float $x, int $ord): float
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class BesselK
|
class BesselK
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BESSELK.
|
* BESSELK.
|
||||||
*
|
*
|
||||||
|
|
@ -28,25 +31,26 @@ class BesselK
|
||||||
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
||||||
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
||||||
|
|
||||||
if ((is_numeric($x)) && (is_numeric($ord))) {
|
try {
|
||||||
$ord = (int) floor($ord);
|
$x = self::validateFloat($x);
|
||||||
$x = (float) $x;
|
$ord = self::validateInt($ord);
|
||||||
if (($ord < 0) || ($x <= 0.0)) {
|
} catch (Exception $e) {
|
||||||
return Functions::NAN();
|
return $e->getMessage();
|
||||||
}
|
|
||||||
|
|
||||||
$fBk = self::calculate($x, $ord);
|
|
||||||
|
|
||||||
return (is_nan($fBk)) ? Functions::NAN() : $fBk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
if (($ord < 0) || ($x <= 0.0)) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fBk = self::calculate($x, $ord);
|
||||||
|
|
||||||
|
return (is_nan($fBk)) ? Functions::NAN() : $fBk;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calculate($x, $ord): float
|
private static function calculate(float $x, int $ord): float
|
||||||
{
|
{
|
||||||
// special cases
|
// special cases
|
||||||
switch (floor($ord)) {
|
switch ($ord) {
|
||||||
case 0:
|
case 0:
|
||||||
return self::besselK0($x);
|
return self::besselK0($x);
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class BesselY
|
class BesselY
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BESSELY.
|
* BESSELY.
|
||||||
*
|
*
|
||||||
|
|
@ -27,25 +30,26 @@ class BesselY
|
||||||
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
|
||||||
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
|
||||||
|
|
||||||
if ((is_numeric($x)) && (is_numeric($ord))) {
|
try {
|
||||||
$ord = (int) floor($ord);
|
$x = self::validateFloat($x);
|
||||||
$x = (float) $x;
|
$ord = self::validateInt($ord);
|
||||||
if (($ord < 0) || ($x <= 0.0)) {
|
} catch (Exception $e) {
|
||||||
return Functions::NAN();
|
return $e->getMessage();
|
||||||
}
|
|
||||||
|
|
||||||
$fBy = self::calculate($x, $ord);
|
|
||||||
|
|
||||||
return (is_nan($fBy)) ? Functions::NAN() : $fBy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Functions::VALUE();
|
if (($ord < 0) || ($x <= 0.0)) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
$fBy = self::calculate($x, $ord);
|
||||||
|
|
||||||
|
return (is_nan($fBy)) ? Functions::NAN() : $fBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function calculate($x, $ord): float
|
private static function calculate(float $x, int $ord): float
|
||||||
{
|
{
|
||||||
// special cases
|
// special cases
|
||||||
switch (floor($ord)) {
|
switch ($ord) {
|
||||||
case 0:
|
case 0:
|
||||||
return self::besselY0($x);
|
return self::besselY0($x);
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Compare
|
class Compare
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DELTA.
|
* DELTA.
|
||||||
*
|
*
|
||||||
|
|
@ -27,8 +30,11 @@ class Compare
|
||||||
$a = Functions::flattenSingleValue($a);
|
$a = Functions::flattenSingleValue($a);
|
||||||
$b = Functions::flattenSingleValue($b);
|
$b = Functions::flattenSingleValue($b);
|
||||||
|
|
||||||
if (!is_numeric($a) || !is_numeric($b)) {
|
try {
|
||||||
return Functions::VALUE();
|
$a = self::validateFloat($a);
|
||||||
|
$b = self::validateFloat($b);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) ($a == $b);
|
return (int) ($a == $b);
|
||||||
|
|
@ -54,8 +60,11 @@ class Compare
|
||||||
$number = Functions::flattenSingleValue($number);
|
$number = Functions::flattenSingleValue($number);
|
||||||
$step = Functions::flattenSingleValue($step);
|
$step = Functions::flattenSingleValue($step);
|
||||||
|
|
||||||
if (!is_numeric($number) || !is_numeric($step)) {
|
try {
|
||||||
return Functions::VALUE();
|
$number = self::validateFloat($number);
|
||||||
|
$step = self::validateFloat($step);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) ($number >= $step);
|
return (int) ($number >= $step);
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
|
||||||
|
|
||||||
use Complex\Complex as ComplexObject;
|
use Complex\Complex as ComplexObject;
|
||||||
use Complex\Exception as ComplexException;
|
use Complex\Exception as ComplexException;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Complex
|
class Complex
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* COMPLEX.
|
* COMPLEX.
|
||||||
*
|
*
|
||||||
|
|
@ -29,10 +32,14 @@ class Complex
|
||||||
$imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary);
|
$imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary);
|
||||||
$suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix);
|
$suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix);
|
||||||
|
|
||||||
if (
|
try {
|
||||||
((is_numeric($realNumber)) && (is_numeric($imaginary))) &&
|
$realNumber = self::validateFloat($realNumber);
|
||||||
(($suffix == 'i') || ($suffix == 'j') || ($suffix == ''))
|
$imaginary = self::validateFloat($imaginary);
|
||||||
) {
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($suffix == 'i') || ($suffix == 'j') || ($suffix == '')) {
|
||||||
$complex = new ComplexObject($realNumber, $imaginary, $suffix);
|
$complex = new ComplexObject($realNumber, $imaginary, $suffix);
|
||||||
|
|
||||||
return (string) $complex;
|
return (string) $complex;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ class Erf
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* ERF(lower[,upper])
|
* ERF(lower[,upper])
|
||||||
*
|
*
|
||||||
* @param float $lower lower bound for integrating ERF
|
* @param mixed (float) $lower lower bound for integrating ERF
|
||||||
* @param float $upper upper bound for integrating ERF.
|
* @param mixed (float) $upper upper bound for integrating ERF.
|
||||||
* If omitted, ERF integrates between zero and lower_limit
|
* If omitted, ERF integrates between zero and lower_limit
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
|
|
@ -52,7 +52,7 @@ class Erf
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* ERF.PRECISE(limit)
|
* ERF.PRECISE(limit)
|
||||||
*
|
*
|
||||||
* @param float $limit bound for integrating ERF
|
* @param mixed (float) $limit bound for integrating ERF
|
||||||
*
|
*
|
||||||
* @return float|string
|
* @return float|string
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -35,57 +35,58 @@ class Financial
|
||||||
* Returns the accrued interest for a security that pays periodic interest.
|
* Returns the accrued interest for a security that pays periodic interest.
|
||||||
*
|
*
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis])
|
* ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis][,calc_method])
|
||||||
|
*
|
||||||
|
* @Deprecated 1.18.0
|
||||||
|
*
|
||||||
|
* @see Financial\Securities\AccruedInterest::periodic()
|
||||||
|
* Use the periodic() method in the Financial\Securities\AccruedInterest class instead
|
||||||
*
|
*
|
||||||
* @param mixed $issue the security's issue date
|
* @param mixed $issue the security's issue date
|
||||||
* @param mixed $firstinterest the security's first interest date
|
* @param mixed $firstinterest the security's first interest date
|
||||||
* @param mixed $settlement The security's settlement date.
|
* @param mixed $settlement The security's settlement date.
|
||||||
* The security settlement date is the date after the issue date
|
* The security settlement date is the date after the issue date
|
||||||
* when the security is traded to the buyer.
|
* when the security is traded to the buyer.
|
||||||
* @param mixed (float) $rate the security's annual coupon rate
|
* @param mixed (float) $rate the security's annual coupon rate
|
||||||
* @param mixed (float) $par The security's par value.
|
* @param mixed (float) $par The security's par value.
|
||||||
* If you omit par, ACCRINT uses $1,000.
|
* If you omit par, ACCRINT uses $1,000.
|
||||||
* @param mixed (int) $frequency the number of coupon payments per year.
|
* @param mixed (int) $frequency The number of coupon payments per year.
|
||||||
* Valid frequency values are:
|
* Valid frequency values are:
|
||||||
* 1 Annual
|
* 1 Annual
|
||||||
* 2 Semi-Annual
|
* 2 Semi-Annual
|
||||||
* 4 Quarterly
|
* 4 Quarterly
|
||||||
* @param mixed (int) $basis The type of day count to use.
|
* @param mixed (int) $basis The type of day count to use.
|
||||||
* 0 or omitted US (NASD) 30/360
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
|
* @param mixed (bool) $calcMethod
|
||||||
|
* If true, use Issue to Settlement
|
||||||
|
* If false, use FirstInterest to Settlement
|
||||||
*
|
*
|
||||||
* @return float|string Result, or a string containing an error
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0)
|
public static function ACCRINT(
|
||||||
{
|
$issue,
|
||||||
$issue = Functions::flattenSingleValue($issue);
|
$firstinterest,
|
||||||
$firstinterest = Functions::flattenSingleValue($firstinterest);
|
$settlement,
|
||||||
$settlement = Functions::flattenSingleValue($settlement);
|
$rate,
|
||||||
$rate = Functions::flattenSingleValue($rate);
|
$par = 1000,
|
||||||
$par = ($par === null) ? 1000 : Functions::flattenSingleValue($par);
|
$frequency = 1,
|
||||||
$frequency = ($frequency === null) ? 1 : Functions::flattenSingleValue($frequency);
|
$basis = 0,
|
||||||
$basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis);
|
$calcMethod = true
|
||||||
|
) {
|
||||||
// Validate
|
return Securities\AccruedInterest::periodic(
|
||||||
if ((is_numeric($rate)) && (is_numeric($par))) {
|
$issue,
|
||||||
$rate = (float) $rate;
|
$firstinterest,
|
||||||
$par = (float) $par;
|
$settlement,
|
||||||
if (($rate <= 0) || ($par <= 0)) {
|
$rate,
|
||||||
return Functions::NAN();
|
$par,
|
||||||
}
|
$frequency,
|
||||||
$daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis);
|
$basis,
|
||||||
if (!is_numeric($daysBetweenIssueAndSettlement)) {
|
$calcMethod
|
||||||
// return date error
|
);
|
||||||
return $daysBetweenIssueAndSettlement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $par * $rate * $daysBetweenIssueAndSettlement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Functions::VALUE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -96,45 +97,28 @@ class Financial
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* ACCRINTM(issue,settlement,rate[,par[,basis]])
|
* ACCRINTM(issue,settlement,rate[,par[,basis]])
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.18.0
|
||||||
|
*
|
||||||
|
* @see Financial\Securities\AccruedInterest::atMaturity()
|
||||||
|
* Use the atMaturity() method in the Financial\Securities\AccruedInterest class instead
|
||||||
|
*
|
||||||
* @param mixed $issue The security's issue date
|
* @param mixed $issue The security's issue date
|
||||||
* @param mixed $settlement The security's settlement (or maturity) date
|
* @param mixed $settlement The security's settlement (or maturity) date
|
||||||
* @param mixed (float) $rate The security's annual coupon rate
|
* @param mixed (float) $rate The security's annual coupon rate
|
||||||
* @param mixed (float) $par The security's par value.
|
* @param mixed (float) $par The security's par value.
|
||||||
* If you omit par, ACCRINT uses $1,000.
|
* If you omit par, ACCRINT uses $1,000.
|
||||||
* @param mixed (int) $basis The type of day count to use.
|
* @param mixed (int) $basis The type of day count to use.
|
||||||
* 0 or omitted US (NASD) 30/360
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float|string Result, or a string containing an error
|
* @return float|string Result, or a string containing an error
|
||||||
*/
|
*/
|
||||||
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
|
public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0)
|
||||||
{
|
{
|
||||||
$issue = Functions::flattenSingleValue($issue);
|
return Securities\AccruedInterest::atMaturity($issue, $settlement, $rate, $par, $basis);
|
||||||
$settlement = Functions::flattenSingleValue($settlement);
|
|
||||||
$rate = Functions::flattenSingleValue($rate);
|
|
||||||
$par = ($par === null) ? 1000 : Functions::flattenSingleValue($par);
|
|
||||||
$basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis);
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if ((is_numeric($rate)) && (is_numeric($par))) {
|
|
||||||
$rate = (float) $rate;
|
|
||||||
$par = (float) $par;
|
|
||||||
if (($rate <= 0) || ($par <= 0)) {
|
|
||||||
return Functions::NAN();
|
|
||||||
}
|
|
||||||
$daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis);
|
|
||||||
if (!is_numeric($daysBetweenIssueAndSettlement)) {
|
|
||||||
// return date error
|
|
||||||
return $daysBetweenIssueAndSettlement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $par * $rate * $daysBetweenIssueAndSettlement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Functions::VALUE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -163,11 +147,11 @@ class Financial
|
||||||
* @param float $period The period
|
* @param float $period The period
|
||||||
* @param float $rate Rate of depreciation
|
* @param float $rate Rate of depreciation
|
||||||
* @param int $basis The type of day count to use.
|
* @param int $basis The type of day count to use.
|
||||||
* 0 or omitted US (NASD) 30/360
|
* 0 or omitted US (NASD) 30/360
|
||||||
* 1 Actual/actual
|
* 1 Actual/actual
|
||||||
* 2 Actual/360
|
* 2 Actual/360
|
||||||
* 3 Actual/365
|
* 3 Actual/365
|
||||||
* 4 European 30/360
|
* 4 European 30/360
|
||||||
*
|
*
|
||||||
* @return float|string (string containing the error type if there is an error)
|
* @return float|string (string containing the error type if there is an error)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,13 @@
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
||||||
|
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Amortization
|
class Amortization
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AMORDEGRC.
|
* AMORDEGRC.
|
||||||
*
|
*
|
||||||
|
|
@ -47,6 +50,18 @@ class Amortization
|
||||||
$rate = Functions::flattenSingleValue($rate);
|
$rate = Functions::flattenSingleValue($rate);
|
||||||
$basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis);
|
$basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$cost = self::validateFloat($cost);
|
||||||
|
$purchased = self::validateDate($purchased);
|
||||||
|
$firstPeriod = self::validateDate($firstPeriod);
|
||||||
|
$salvage = self::validateFloat($salvage);
|
||||||
|
$period = self::validateFloat($period);
|
||||||
|
$rate = self::validateFloat($rate);
|
||||||
|
$basis = self::validateBasis($basis);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$yearFrac = DateTimeExcel\YearFrac::funcYearFrac($purchased, $firstPeriod, $basis);
|
$yearFrac = DateTimeExcel\YearFrac::funcYearFrac($purchased, $firstPeriod, $basis);
|
||||||
if (is_string($yearFrac)) {
|
if (is_string($yearFrac)) {
|
||||||
return $yearFrac;
|
return $yearFrac;
|
||||||
|
|
@ -113,6 +128,18 @@ class Amortization
|
||||||
$rate = Functions::flattenSingleValue($rate);
|
$rate = Functions::flattenSingleValue($rate);
|
||||||
$basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis);
|
$basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$cost = self::validateFloat($cost);
|
||||||
|
$purchased = self::validateDate($purchased);
|
||||||
|
$firstPeriod = self::validateDate($firstPeriod);
|
||||||
|
$salvage = self::validateFloat($salvage);
|
||||||
|
$period = self::validateFloat($period);
|
||||||
|
$rate = self::validateFloat($rate);
|
||||||
|
$basis = self::validateBasis($basis);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
$fOneRate = $cost * $rate;
|
$fOneRate = $cost * $rate;
|
||||||
$fCostDelta = $cost - $salvage;
|
$fCostDelta = $cost - $salvage;
|
||||||
// Note, quirky variation for leap years on the YEARFRAC for this function
|
// Note, quirky variation for leap years on the YEARFRAC for this function
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants as SecuritiesConstants;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
trait BaseValidations
|
||||||
|
{
|
||||||
|
protected static function validateDate($date)
|
||||||
|
{
|
||||||
|
return DateTimeExcel\Helpers::getDateValue($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateSettlementDate($settlement)
|
||||||
|
{
|
||||||
|
return self::validateDate($settlement);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateMaturityDate($maturity)
|
||||||
|
{
|
||||||
|
return self::validateDate($maturity);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateFloat($value): float
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateInt($value): int
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) floor($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateFrequency($frequency): int
|
||||||
|
{
|
||||||
|
$frequency = self::validateInt($frequency);
|
||||||
|
if (
|
||||||
|
($frequency !== SecuritiesConstants::FREQUENCY_ANNUAL) &&
|
||||||
|
($frequency !== SecuritiesConstants::FREQUENCY_SEMI_ANNUAL) &&
|
||||||
|
($frequency !== SecuritiesConstants::FREQUENCY_QUARTERLY)
|
||||||
|
) {
|
||||||
|
throw new Exception(Functions::NAN());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validateBasis($basis): int
|
||||||
|
{
|
||||||
|
if (!is_numeric($basis)) {
|
||||||
|
throw new Exception(Functions::VALUE());
|
||||||
|
}
|
||||||
|
|
||||||
|
$basis = (int) $basis;
|
||||||
|
if (($basis < 0) || ($basis > 4)) {
|
||||||
|
throw new Exception(Functions::NAN());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $basis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
@ -10,6 +9,8 @@ use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||||
|
|
||||||
class Coupons
|
class Coupons
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
public const FREQUENCY_ANNUAL = 1;
|
public const FREQUENCY_ANNUAL = 1;
|
||||||
public const FREQUENCY_SEMI_ANNUAL = 2;
|
public const FREQUENCY_SEMI_ANNUAL = 2;
|
||||||
public const FREQUENCY_QUARTERLY = 4;
|
public const FREQUENCY_QUARTERLY = 4;
|
||||||
|
|
@ -62,6 +63,9 @@ class Coupons
|
||||||
}
|
}
|
||||||
|
|
||||||
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis);
|
$daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis);
|
||||||
|
if (is_string($daysPerYear)) {
|
||||||
|
return Functions::VALUE();
|
||||||
|
}
|
||||||
$prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
|
$prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
|
||||||
|
|
||||||
if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) {
|
if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) {
|
||||||
|
|
@ -185,7 +189,7 @@ class Coupons
|
||||||
|
|
||||||
if ($basis === Helpers::DAYS_PER_YEAR_NASD) {
|
if ($basis === Helpers::DAYS_PER_YEAR_NASD) {
|
||||||
$settlementDate = Date::excelToDateTimeObject($settlement);
|
$settlementDate = Date::excelToDateTimeObject($settlement);
|
||||||
$settlementEoM = self::isLastDayOfMonth($settlementDate);
|
$settlementEoM = Helpers::isLastDayOfMonth($settlementDate);
|
||||||
if ($settlementEoM) {
|
if ($settlementEoM) {
|
||||||
++$settlement;
|
++$settlement;
|
||||||
}
|
}
|
||||||
|
|
@ -340,26 +344,12 @@ class Coupons
|
||||||
return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
|
return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* isLastDayOfMonth.
|
|
||||||
*
|
|
||||||
* Returns a boolean TRUE/FALSE indicating if this date is the last date of the month
|
|
||||||
*
|
|
||||||
* @param DateTime $testDate The date for testing
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private static function isLastDayOfMonth(DateTime $testDate)
|
|
||||||
{
|
|
||||||
return $testDate->format('d') === $testDate->format('t');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next)
|
private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next)
|
||||||
{
|
{
|
||||||
$months = 12 / $frequency;
|
$months = 12 / $frequency;
|
||||||
|
|
||||||
$result = Date::excelToDateTimeObject($maturity);
|
$result = Date::excelToDateTimeObject($maturity);
|
||||||
$maturityEoM = self::isLastDayOfMonth($result);
|
$maturityEoM = Helpers::isLastDayOfMonth($result);
|
||||||
|
|
||||||
while ($settlement < Date::PHPToExcel($result)) {
|
while ($settlement < Date::PHPToExcel($result)) {
|
||||||
$result->modify('-' . $months . ' months');
|
$result->modify('-' . $months . ' months');
|
||||||
|
|
@ -375,62 +365,10 @@ class Coupons
|
||||||
return Date::PHPToExcel($result);
|
return Date::PHPToExcel($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function validateInputDate($date)
|
|
||||||
{
|
|
||||||
$date = DateTimeExcel\Helpers::getDateValue($date);
|
|
||||||
if (is_string($date)) {
|
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $date;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function validateSettlementDate($settlement)
|
|
||||||
{
|
|
||||||
return self::validateInputDate($settlement);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function validateMaturityDate($maturity)
|
|
||||||
{
|
|
||||||
return self::validateInputDate($maturity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function validateCouponPeriod($settlement, $maturity): void
|
private static function validateCouponPeriod($settlement, $maturity): void
|
||||||
{
|
{
|
||||||
if ($settlement >= $maturity) {
|
if ($settlement >= $maturity) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function validateFrequency($frequency): int
|
|
||||||
{
|
|
||||||
if (!is_numeric($frequency)) {
|
|
||||||
throw new Exception(Functions::NAN());
|
|
||||||
}
|
|
||||||
|
|
||||||
$frequency = (int) $frequency;
|
|
||||||
if (
|
|
||||||
($frequency !== self::FREQUENCY_ANNUAL) &&
|
|
||||||
($frequency !== self::FREQUENCY_SEMI_ANNUAL) &&
|
|
||||||
($frequency !== self::FREQUENCY_QUARTERLY)
|
|
||||||
) {
|
|
||||||
throw new Exception(Functions::NAN());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $frequency;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function validateBasis($basis): int
|
|
||||||
{
|
|
||||||
if (!is_numeric($basis)) {
|
|
||||||
throw new Exception(Functions::NAN());
|
|
||||||
}
|
|
||||||
|
|
||||||
$basis = (int) $basis;
|
|
||||||
if (($basis < 0) || ($basis > 4)) {
|
|
||||||
throw new Exception(Functions::NAN());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $basis;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Depreciation
|
class Depreciation
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DB.
|
* DB.
|
||||||
*
|
*
|
||||||
|
|
@ -203,11 +205,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validateCost($cost, bool $negativeValueAllowed = false): float
|
private static function validateCost($cost, bool $negativeValueAllowed = false): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($cost)) {
|
$cost = self::validateFloat($cost);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$cost = (float) $cost;
|
|
||||||
if ($cost < 0.0 && $negativeValueAllowed === false) {
|
if ($cost < 0.0 && $negativeValueAllowed === false) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -217,11 +215,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float
|
private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($salvage)) {
|
$salvage = self::validateFloat($salvage);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$salvage = (float) $salvage;
|
|
||||||
if ($salvage < 0.0 && $negativeValueAllowed === false) {
|
if ($salvage < 0.0 && $negativeValueAllowed === false) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -231,11 +225,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validateLife($life, bool $negativeValueAllowed = false): float
|
private static function validateLife($life, bool $negativeValueAllowed = false): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($life)) {
|
$life = self::validateFloat($life);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$life = (float) $life;
|
|
||||||
if ($life < 0.0 && $negativeValueAllowed === false) {
|
if ($life < 0.0 && $negativeValueAllowed === false) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -245,11 +235,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validatePeriod($period, bool $negativeValueAllowed = false): float
|
private static function validatePeriod($period, bool $negativeValueAllowed = false): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($period)) {
|
$period = self::validateFloat($period);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$period = (float) $period;
|
|
||||||
if ($period <= 0.0 && $negativeValueAllowed === false) {
|
if ($period <= 0.0 && $negativeValueAllowed === false) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -259,11 +245,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validateMonth($month): int
|
private static function validateMonth($month): int
|
||||||
{
|
{
|
||||||
if (!is_numeric($month)) {
|
$month = self::validateInt($month);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$month = (int) $month;
|
|
||||||
if ($month < 1) {
|
if ($month < 1) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -273,11 +255,7 @@ class Depreciation
|
||||||
|
|
||||||
private static function validateFactor($factor): float
|
private static function validateFactor($factor): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($factor)) {
|
$factor = self::validateFloat($factor);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$factor = (float) $factor;
|
|
||||||
if ($factor <= 0.0) {
|
if ($factor <= 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
||||||
|
|
||||||
|
use DateTimeInterface;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
|
@ -47,4 +48,18 @@ class Helpers
|
||||||
|
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isLastDayOfMonth.
|
||||||
|
*
|
||||||
|
* Returns a boolean TRUE/FALSE indicating if this date is the last date of the month
|
||||||
|
*
|
||||||
|
* @param DateTimeInterface $date The date for testing
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isLastDayOfMonth(DateTimeInterface $date)
|
||||||
|
{
|
||||||
|
return $date->format('d') === $date->format('t');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class InterestRate
|
class InterestRate
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EFFECT.
|
* EFFECT.
|
||||||
*
|
*
|
||||||
|
|
@ -25,16 +28,17 @@ class InterestRate
|
||||||
$nominalRate = Functions::flattenSingleValue($nominalRate);
|
$nominalRate = Functions::flattenSingleValue($nominalRate);
|
||||||
$periodsPerYear = Functions::flattenSingleValue($periodsPerYear);
|
$periodsPerYear = Functions::flattenSingleValue($periodsPerYear);
|
||||||
|
|
||||||
// Validate parameters
|
try {
|
||||||
if (!is_numeric($nominalRate) || !is_numeric($periodsPerYear)) {
|
$nominalRate = self::validateFloat($nominalRate);
|
||||||
return Functions::VALUE();
|
$periodsPerYear = self::validateInt($periodsPerYear);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($nominalRate <= 0 || $periodsPerYear < 1) {
|
if ($nominalRate <= 0 || $periodsPerYear < 1) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
$periodsPerYear = (int) $periodsPerYear;
|
|
||||||
|
|
||||||
return ((1 + $nominalRate / $periodsPerYear) ** $periodsPerYear) - 1;
|
return ((1 + $nominalRate / $periodsPerYear) ** $periodsPerYear) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,16 +57,17 @@ class InterestRate
|
||||||
$effectiveRate = Functions::flattenSingleValue($effectiveRate);
|
$effectiveRate = Functions::flattenSingleValue($effectiveRate);
|
||||||
$periodsPerYear = Functions::flattenSingleValue($periodsPerYear);
|
$periodsPerYear = Functions::flattenSingleValue($periodsPerYear);
|
||||||
|
|
||||||
// Validate parameters
|
try {
|
||||||
if (!is_numeric($effectiveRate) || !is_numeric($periodsPerYear)) {
|
$effectiveRate = self::validateFloat($effectiveRate);
|
||||||
return Functions::VALUE();
|
$periodsPerYear = self::validateInt($periodsPerYear);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($effectiveRate <= 0 || $periodsPerYear < 1) {
|
if ($effectiveRate <= 0 || $periodsPerYear < 1) {
|
||||||
return Functions::NAN();
|
return Functions::NAN();
|
||||||
}
|
}
|
||||||
|
|
||||||
$periodsPerYear = (int) $periodsPerYear;
|
|
||||||
|
|
||||||
// Calculate
|
// Calculate
|
||||||
return $periodsPerYear * (($effectiveRate + 1) ** (1 / $periodsPerYear) - 1);
|
return $periodsPerYear * (($effectiveRate + 1) ** (1 / $periodsPerYear) - 1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class AccruedInterest
|
||||||
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
|
public const ACCRINT_CALCMODE_ISSUE_TO_SETTLEMENT = true;
|
||||||
|
|
||||||
|
public const ACCRINT_CALCMODE_FIRST_INTEREST_TO_SETTLEMENT = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACCRINT.
|
||||||
|
*
|
||||||
|
* Returns the accrued interest for a security that pays periodic interest.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis][,calc_method])
|
||||||
|
*
|
||||||
|
* @param mixed $issue the security's issue date
|
||||||
|
* @param mixed $firstinterest the security's first interest date
|
||||||
|
* @param mixed $settlement The security's settlement date.
|
||||||
|
* The security settlement date is the date after the issue date
|
||||||
|
* when the security is traded to the buyer.
|
||||||
|
* @param mixed (float) $rate The security's annual coupon rate
|
||||||
|
* @param mixed (float) $par The security's par value.
|
||||||
|
* If you omit par, ACCRINT uses $1,000.
|
||||||
|
* @param mixed (int) $frequency The number of coupon payments per year.
|
||||||
|
* Valid frequency values are:
|
||||||
|
* 1 Annual
|
||||||
|
* 2 Semi-Annual
|
||||||
|
* 4 Quarterly
|
||||||
|
* @param mixed (int) $basis The type of day count to use.
|
||||||
|
* 0 or omitted US (NASD) 30/360
|
||||||
|
* 1 Actual/actual
|
||||||
|
* 2 Actual/360
|
||||||
|
* 3 Actual/365
|
||||||
|
* 4 European 30/360
|
||||||
|
* @param mixed $parValue
|
||||||
|
* @param mixed $calcMethod
|
||||||
|
*
|
||||||
|
* @return float|string Result, or a string containing an error
|
||||||
|
*/
|
||||||
|
public static function periodic(
|
||||||
|
$issue,
|
||||||
|
$firstinterest,
|
||||||
|
$settlement,
|
||||||
|
$rate,
|
||||||
|
$parValue = 1000,
|
||||||
|
$frequency = 1,
|
||||||
|
$basis = 0,
|
||||||
|
$calcMethod = self::ACCRINT_CALCMODE_ISSUE_TO_SETTLEMENT
|
||||||
|
) {
|
||||||
|
$issue = Functions::flattenSingleValue($issue);
|
||||||
|
$firstinterest = Functions::flattenSingleValue($firstinterest);
|
||||||
|
$settlement = Functions::flattenSingleValue($settlement);
|
||||||
|
$rate = Functions::flattenSingleValue($rate);
|
||||||
|
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
|
||||||
|
$frequency = ($frequency === null) ? 1 : Functions::flattenSingleValue($frequency);
|
||||||
|
$basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$issue = self::validateIssueDate($issue);
|
||||||
|
$settlement = self::validateSettlementDate($settlement);
|
||||||
|
self::validateSecurityPeriod($issue, $settlement);
|
||||||
|
$rate = self::validateRate($rate);
|
||||||
|
$parValue = self::validateParValue($parValue);
|
||||||
|
$frequency = self::validateFrequency($frequency);
|
||||||
|
$basis = self::validateBasis($basis);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis);
|
||||||
|
if (!is_numeric($daysBetweenIssueAndSettlement)) {
|
||||||
|
// return date error
|
||||||
|
return $daysBetweenIssueAndSettlement;
|
||||||
|
}
|
||||||
|
$daysBetweenFirstInterestAndSettlement = DateTime::YEARFRAC($firstinterest, $settlement, $basis);
|
||||||
|
if (!is_numeric($daysBetweenFirstInterestAndSettlement)) {
|
||||||
|
// return date error
|
||||||
|
return $daysBetweenFirstInterestAndSettlement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parValue * $rate * $daysBetweenIssueAndSettlement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACCRINTM.
|
||||||
|
*
|
||||||
|
* Returns the accrued interest for a security that pays interest at maturity.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* ACCRINTM(issue,settlement,rate[,par[,basis]])
|
||||||
|
*
|
||||||
|
* @param mixed $issue The security's issue date
|
||||||
|
* @param mixed $settlement The security's settlement (or maturity) date
|
||||||
|
* @param mixed (float) $rate The security's annual coupon rate
|
||||||
|
* @param mixed (float) $par The security's par value.
|
||||||
|
* If you omit par, ACCRINT uses $1,000.
|
||||||
|
* @param mixed (int) $basis The type of day count to use.
|
||||||
|
* 0 or omitted US (NASD) 30/360
|
||||||
|
* 1 Actual/actual
|
||||||
|
* 2 Actual/360
|
||||||
|
* 3 Actual/365
|
||||||
|
* 4 European 30/360
|
||||||
|
* @param mixed $parValue
|
||||||
|
*
|
||||||
|
* @return float|string Result, or a string containing an error
|
||||||
|
*/
|
||||||
|
public static function atMaturity($issue, $settlement, $rate, $parValue = 1000, $basis = 0)
|
||||||
|
{
|
||||||
|
$issue = Functions::flattenSingleValue($issue);
|
||||||
|
$settlement = Functions::flattenSingleValue($settlement);
|
||||||
|
$rate = Functions::flattenSingleValue($rate);
|
||||||
|
$parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue);
|
||||||
|
$basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$issue = self::validateIssueDate($issue);
|
||||||
|
$settlement = self::validateSettlementDate($settlement);
|
||||||
|
self::validateSecurityPeriod($issue, $settlement);
|
||||||
|
$rate = self::validateRate($rate);
|
||||||
|
$parValue = self::validateParValue($parValue);
|
||||||
|
$basis = self::validateBasis($basis);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis);
|
||||||
|
if (!is_numeric($daysBetweenIssueAndSettlement)) {
|
||||||
|
// return date error
|
||||||
|
return $daysBetweenIssueAndSettlement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parValue * $rate * $daysBetweenIssueAndSettlement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,31 +7,35 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants as SecuritiesConstants;
|
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants as SecuritiesConstants;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
abstract class BaseValidations
|
trait BaseValidations
|
||||||
{
|
{
|
||||||
protected static function validateInputDate($date)
|
protected static function validateDate($date)
|
||||||
{
|
{
|
||||||
$date = DateTimeExcel\Helpers::getDateValue($date);
|
return DateTimeExcel\Helpers::getDateValue($date);
|
||||||
if (is_string($date)) {
|
}
|
||||||
|
|
||||||
|
protected static function validateFloat($value): float
|
||||||
|
{
|
||||||
|
if (!is_numeric($value)) {
|
||||||
throw new Exception(Functions::VALUE());
|
throw new Exception(Functions::VALUE());
|
||||||
}
|
}
|
||||||
|
|
||||||
return $date;
|
return (float) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function validateSettlementDate($settlement)
|
protected static function validateSettlementDate($settlement)
|
||||||
{
|
{
|
||||||
return self::validateInputDate($settlement);
|
return self::validateDate($settlement);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function validateMaturityDate($maturity)
|
protected static function validateMaturityDate($maturity)
|
||||||
{
|
{
|
||||||
return self::validateInputDate($maturity);
|
return self::validateDate($maturity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function validateIssueDate($issue)
|
protected static function validateIssueDate($issue)
|
||||||
{
|
{
|
||||||
return self::validateInputDate($issue);
|
return self::validateDate($issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function validateSecurityPeriod($settlement, $maturity): void
|
protected static function validateSecurityPeriod($settlement, $maturity): void
|
||||||
|
|
@ -43,11 +47,7 @@ abstract class BaseValidations
|
||||||
|
|
||||||
protected static function validateRate($rate): float
|
protected static function validateRate($rate): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($rate)) {
|
$rate = self::validateFloat($rate);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$rate = (float) $rate;
|
|
||||||
if ($rate < 0.0) {
|
if ($rate < 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -55,13 +55,19 @@ abstract class BaseValidations
|
||||||
return $rate;
|
return $rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function validatePrice($price): float
|
protected static function validateParValue($parValue): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($price)) {
|
$parValue = self::validateFloat($parValue);
|
||||||
throw new Exception(Functions::VALUE());
|
if ($parValue < 0.0) {
|
||||||
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
||||||
$price = (float) $price;
|
return $parValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function validatePrice($price): float
|
||||||
|
{
|
||||||
|
$price = self::validateFloat($price);
|
||||||
if ($price < 0.0) {
|
if ($price < 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -71,11 +77,7 @@ abstract class BaseValidations
|
||||||
|
|
||||||
protected static function validateYield($yield): float
|
protected static function validateYield($yield): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($yield)) {
|
$yield = self::validateFloat($yield);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$yield = (float) $yield;
|
|
||||||
if ($yield < 0.0) {
|
if ($yield < 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -85,11 +87,7 @@ abstract class BaseValidations
|
||||||
|
|
||||||
protected static function validateRedemption($redemption): float
|
protected static function validateRedemption($redemption): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($redemption)) {
|
$redemption = self::validateFloat($redemption);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$redemption = (float) $redemption;
|
|
||||||
if ($redemption <= 0.0) {
|
if ($redemption <= 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
@ -99,11 +97,7 @@ abstract class BaseValidations
|
||||||
|
|
||||||
protected static function validateDiscount($discount): float
|
protected static function validateDiscount($discount): float
|
||||||
{
|
{
|
||||||
if (!is_numeric($discount)) {
|
$discount = self::validateFloat($discount);
|
||||||
throw new Exception(Functions::VALUE());
|
|
||||||
}
|
|
||||||
|
|
||||||
$discount = (float) $discount;
|
|
||||||
if ($discount <= 0.0) {
|
if ($discount <= 0.0) {
|
||||||
throw new Exception(Functions::NAN());
|
throw new Exception(Functions::NAN());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers;
|
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Price extends BaseValidations
|
class Price
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PRICE.
|
* PRICE.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers;
|
use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers;
|
||||||
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class Yields extends BaseValidations
|
class Yields
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* YIELDDISC.
|
* YIELDDISC.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
class TreasuryBill
|
class TreasuryBill
|
||||||
{
|
{
|
||||||
|
use BaseValidations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TBILLEQ.
|
* TBILLEQ.
|
||||||
*
|
*
|
||||||
|
|
@ -29,8 +31,8 @@ class TreasuryBill
|
||||||
$discount = Functions::flattenSingleValue($discount);
|
$discount = Functions::flattenSingleValue($discount);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$maturity = DateTimeExcel\Helpers::getDateValue($maturity);
|
$settlement = self::validateSettlementDate($settlement);
|
||||||
$settlement = DateTimeExcel\Helpers::getDateValue($settlement);
|
$maturity = self::validateMaturityDate($maturity);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
@ -75,8 +77,8 @@ class TreasuryBill
|
||||||
$discount = Functions::flattenSingleValue($discount);
|
$discount = Functions::flattenSingleValue($discount);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$maturity = DateTimeExcel\Helpers::getDateValue($maturity);
|
$settlement = self::validateSettlementDate($settlement);
|
||||||
$settlement = DateTimeExcel\Helpers::getDateValue($settlement);
|
$maturity = self::validateMaturityDate($maturity);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
@ -126,8 +128,8 @@ class TreasuryBill
|
||||||
$price = Functions::flattenSingleValue($price);
|
$price = Functions::flattenSingleValue($price);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$maturity = DateTimeExcel\Helpers::getDateValue($maturity);
|
$settlement = self::validateSettlementDate($settlement);
|
||||||
$settlement = DateTimeExcel\Helpers::getDateValue($settlement);
|
$maturity = self::validateMaturityDate($maturity);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class AccrintMTest extends TestCase
|
||||||
public function testACCRINTM($expectedResult, ...$args): void
|
public function testACCRINTM($expectedResult, ...$args): void
|
||||||
{
|
{
|
||||||
$result = Financial::ACCRINTM(...$args);
|
$result = Financial::ACCRINTM(...$args);
|
||||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function providerACCRINTM()
|
public function providerACCRINTM()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class AccrintTest extends TestCase
|
||||||
public function testACCRINT($expectedResult, ...$args): void
|
public function testACCRINT($expectedResult, ...$args): void
|
||||||
{
|
{
|
||||||
$result = Financial::ACCRINT(...$args);
|
$result = Financial::ACCRINT(...$args);
|
||||||
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function providerACCRINT()
|
public function providerACCRINT()
|
||||||
|
|
|
||||||
|
|
@ -4,72 +4,83 @@
|
||||||
|
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
16.666666666666998,
|
16.6666666666666,
|
||||||
'2008-03-01',
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0,
|
||||||
'2008-08-31',
|
|
||||||
'2008-05-01',
|
|
||||||
0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
15.555555555555999,
|
15.5555555555559,
|
||||||
'2008-03-05',
|
'2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0,
|
||||||
'2008-08-31',
|
],
|
||||||
'2008-05-01',
|
[
|
||||||
0.10000000000000001,
|
15.5555555555559,
|
||||||
1000,
|
'2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true,
|
||||||
2,
|
],
|
||||||
0,
|
[
|
||||||
|
7.22222222222222,
|
||||||
|
'2008-04-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
200,
|
200,
|
||||||
'2010-01-01',
|
'2010-01-01', '2010-06-30', '2010-04-01', 0.08, 10000, 4,
|
||||||
'2010-06-30',
|
],
|
||||||
'2010-04-01',
|
[
|
||||||
0.080000000000000002,
|
1600,
|
||||||
10000,
|
'2012-01-01', '2012-04-01', '2013-12-31', 0.08, 10000, 4,
|
||||||
4,
|
],
|
||||||
|
[
|
||||||
|
32.363013698630134,
|
||||||
|
'2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 5000, 4, 3, 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
6.472602739726027,
|
||||||
|
'2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 1000, 4, 3, 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
18.05555555555555,
|
||||||
|
'2017-08-05', '2017-11-10', '2017-10-10', 0.05, 2000, 4, 0, 1,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
'2008-03-05',
|
'2008-03-05', '2008-08-31', '2008-05-01', -0.10, 1000, 2, 0,
|
||||||
'2008-08-31',
|
|
||||||
'2008-05-01',
|
|
||||||
-0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'Invalid Date',
|
'Invalid Date', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0,
|
||||||
'2008-08-31',
|
|
||||||
'2008-05-01',
|
|
||||||
0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'2008-03-01',
|
'2008-03-01', '2008-08-31', '2008-05-01', 'ABC', 1000, 2, 0,
|
||||||
'2008-08-31',
|
|
||||||
'2008-05-01',
|
|
||||||
'ABC',
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
[
|
'Non-numeric Rate' => [
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'2008-03-01',
|
'2008-03-01', '2008-08-31', '2008-05-01', 'NaN', 1000, 2, 0,
|
||||||
'2008-08-31',
|
],
|
||||||
'2008-05-01',
|
'Invalid Rate' => [
|
||||||
0.10000000000000001,
|
'#NUM!',
|
||||||
1000,
|
'2008-03-01', '2008-08-31', '2008-05-01', -0.10, 1000, 2, 0,
|
||||||
2,
|
],
|
||||||
'ABC',
|
'Non-numeric Par Value' => [
|
||||||
|
'#VALUE!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, 'NaN', 2, 0,
|
||||||
|
],
|
||||||
|
'Invalid Par Value' => [
|
||||||
|
'#NUM!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, -1000, 2, 0,
|
||||||
|
],
|
||||||
|
'Non-numeric Frequency' => [
|
||||||
|
'#VALUE!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 'NaN', 0,
|
||||||
|
],
|
||||||
|
'Invalid Frequency' => [
|
||||||
|
'#NUM!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, -1000, 3, 0,
|
||||||
|
],
|
||||||
|
'Non-numeric Basis' => [
|
||||||
|
'#VALUE!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 'ABC',
|
||||||
|
],
|
||||||
|
'Invalid Basis' => [
|
||||||
|
'#NUM!',
|
||||||
|
'2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, -2,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -5,41 +5,50 @@
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
20.547945205478999,
|
20.547945205478999,
|
||||||
'2008-04-01',
|
'2008-04-01', '2008-06-15', 0.10, 1000, 3,
|
||||||
'2008-06-15',
|
|
||||||
0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
3,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
800,
|
800,
|
||||||
'2010-01-01',
|
'2010-01-01', '2010-12-31', 0.08, 10000,
|
||||||
'2010-12-31',
|
],
|
||||||
0.080000000000000002,
|
[
|
||||||
10000,
|
365.958904109589,
|
||||||
|
'2012-01-01', '2013-02-15', 0.065, 5000, 3,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
73.1917808219178,
|
||||||
|
'2012-01-01', '2013-02-15', 0.065, 1000, 3,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#NUM!',
|
'#NUM!',
|
||||||
'2008-03-05',
|
'2008-03-05', '2008-08-31', -0.10, 1000, 2,
|
||||||
'2008-08-31',
|
|
||||||
-0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'Invalid Date',
|
'Invalid Date', '2008-08-31', 0.10, 1000, 2,
|
||||||
'2008-08-31',
|
|
||||||
0.10000000000000001,
|
|
||||||
1000,
|
|
||||||
2,
|
|
||||||
],
|
],
|
||||||
[
|
'Non-numeric Rate' => [
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
'2008-03-01',
|
'2008-03-01', '2008-08-31', 'NaN', 1000, 2,
|
||||||
'2008-08-31',
|
],
|
||||||
'ABC',
|
'Invalid Rate' => [
|
||||||
1000,
|
'#NUM!',
|
||||||
2,
|
'2008-03-01', '2008-08-31', -0.10, 1000, 2,
|
||||||
|
],
|
||||||
|
'Non-numeric Par Value' => [
|
||||||
|
'#VALUE!',
|
||||||
|
'2008-03-01', '2008-08-31', 0.10, 'NaN', 2,
|
||||||
|
],
|
||||||
|
'Invalid Par Value' => [
|
||||||
|
'#NUM!',
|
||||||
|
'2008-03-01', '2008-08-31', 0.10, -1000, 2,
|
||||||
|
],
|
||||||
|
'Non-numeric Basis' => [
|
||||||
|
'#VALUE!',
|
||||||
|
'2008-03-01', '2008-08-31', 0.10, 1000, 'NaN',
|
||||||
|
],
|
||||||
|
'Invalid Basis' => [
|
||||||
|
'#NUM!',
|
||||||
|
'2008-03-01', '2008-08-31', 0.10, 1000, 99,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,14 @@ return [
|
||||||
42,
|
42,
|
||||||
150, '2011-01-01', '2011-09-30', 20, 1, 0.4, 4,
|
150, '2011-01-01', '2011-09-30', 20, 1, 0.4, 4,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
2813,
|
||||||
|
10000, '2012-03-01', '2012-12-31', 1500, 1, 0.3, 1,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
'NaN', '2012-03-01', '2020-12-25', 20, 1, 0.2, 4,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
550, 'notADate', '2020-12-25', 20, 1, 0.2, 4,
|
550, 'notADate', '2020-12-25', 20, 1, 0.2, 4,
|
||||||
|
|
@ -55,4 +63,8 @@ return [
|
||||||
'#VALUE!',
|
'#VALUE!',
|
||||||
550, '2011-01-01', 'notADate', 20, 1, 0.2, 4,
|
550, '2011-01-01', 'notADate', 20, 1, 0.2, 4,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'#VALUE!',
|
||||||
|
550, '2012-03-01', '2020-12-25', 'NaN', 1, 0.2, 4,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -59,7 +59,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -73,7 +73,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -52,7 +52,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -52,7 +52,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -53,7 +53,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ return [
|
||||||
1,
|
1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Frequency' => [
|
'Non-Numeric Frequency' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
'NaN',
|
'NaN',
|
||||||
|
|
@ -52,7 +52,7 @@ return [
|
||||||
-1,
|
-1,
|
||||||
],
|
],
|
||||||
'Non-Numeric Basis' => [
|
'Non-Numeric Basis' => [
|
||||||
'#NUM!',
|
'#VALUE!',
|
||||||
'25-Jan-2007',
|
'25-Jan-2007',
|
||||||
'15-Nov-2008',
|
'15-Nov-2008',
|
||||||
4,
|
4,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue