Current File : //opt/RZphp83/includes/Math/Finance.php |
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Math_Finance: Class of financial functions
*
* Assorted financial functions for interest rates, bonds, amortizations and time value of money calculations (annuities)
* Same interface as Excel financial functions.
*
* PHP versions 4 and 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category Math
* @package Math_Finance
* @author Original Author <alejandro.pedraza@dataenlace.com>
* @copyright 2005 Alejandro Pedraza
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id: Finance.php 274632 2009-01-26 14:29:28Z clockwerx $
* @link http://pear.php.net/Math/Finance
* @since File available since Release 1.2.0
*/
// to be able to throw PEAR errors
require_once 'PEAR.php';
// precision of calculations
define('FINANCE_PRECISION', 1E-6);
// payment types
define('FINANCE_PAY_END', 0);
define('FINANCE_PAY_BEGIN', 1);
// types of daycount basis
define('FINANCE_COUNT_NASD', 0);
define('FINANCE_COUNT_ACTUAL_ACTUAL', 1);
define('FINANCE_COUNT_ACTUAL_360', 2);
define('FINANCE_COUNT_ACTUAL_365', 3);
define('FINANCE_COUNT_EUROPEAN', 4);
/**
* Math_Finance: Main class
*
* @category Math
* @package Math_Finance
* @author Original Author <alejandro.pedraza@dataenlace.com>
* @copyright 2005 Alejandro Pedraza
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version Release: @package_version@
* @link http://pear.php.net/Math/Finance
* @since Class available since Release 1.2.0
*/
class Math_Finance
{
/*******************************************************************
** Interest Rates Conversion Functions *****
*******************************************************************/
/**
* Returns the effective interest rate given the nominal rate and the number of compounding payments per year
* Excel equivalent: EFFECT
*
* @param float Nominal interest rate
* @param int Number of compounding payments per year
* @return float
* @static
* @access public
*/
function effectiveRate($nominal_rate, $npery)
{
$npery = (int)$npery;
if ($npery < 0) {
return PEAR::raiseError('Number of compounding payments per year is not positive');
}
$effect = pow((1 + $nominal_rate / $npery), $npery) - 1;
return $effect;
}
/**
* Returns the nominal interest rate given the effective rate and the number of compounding payments per year
* Excel equivalent: NOMINAL
*
* @param float Effective interest rate
* @param int Number of compounding payments per year
* @return float
* @static
* @access public
*/
function nominalRate($effect_rate, $npery)
{
$npery = (int)$npery;
if ($npery < 0) {
return PEAR::raiseError('Number of compounding payments per year is not positive');
}
$nominal = $npery * (pow($effect_rate + 1, 1/$npery) - 1);
return $nominal;
}
/*******************************************************************
** TVM (annuities) Functions *****
*******************************************************************/
/**
* Returns the Present Value of a cash flow with constant payments and interest rate (annuities)
* Excel equivalent: PV
*
* TVM functions solve for a term in the following formula:
* pv(1+r)^n + pmt(1+r.type)((1+r)^n - 1)/r) +fv = 0
*
*
* @param float Interest rate per period
* @param int Number of periods
* @param float Periodic payment (annuity)
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function presentValue($rate, $nper, $pmt, $fv = 0, $type = 0)
{
if ($nper < 0) {
return PEAR::raiseError('Number of periods must be positive');
}
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
if ($rate) {
$pv = (-$pmt * (1 + $rate * $type) * ((pow(1 + $rate, $nper) - 1) / $rate) - $fv) / pow(1 + $rate, $nper);
} else {
$pv = -$fv - $pmt * $nper;
}
return $pv;
}
/**
* Returns the Future Value of a cash flow with constant payments and interest rate (annuities)
* Excel equivalent: FV
*
* @param float Interest rate per period
* @param int Number of periods
* @param float Periodic payment (annuity)
* @param float Present Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function futureValue($rate, $nper, $pmt, $pv = 0, $type = 0)
{
if ($nper < 0) {
return PEAR::raiseError('Number of periods must be positive');
}
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
if ($rate) {
$fv = -$pv * pow(1 + $rate, $nper) - $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate;
} else {
$fv = -$pv - $pmt * $nper;
}
return $fv;
}
/**
* Returns the constant payment (annuity) for a cash flow with a constant interest rate
* Excel equivalent: PMT
*
* @param float Interest rate per period
* @param int Number of periods
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function payment($rate, $nper, $pv, $fv = 0, $type = 0)
{
if ($nper < 0) {
return PEAR::raiseError('Number of periods must be positive');
}
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
if ($rate) {
$pmt = (-$fv - $pv * pow(1 + $rate, $nper)) / (1 + $rate * $type) / ((pow(1 + $rate, $nper) - 1) / $rate);
} else {
$pmt = (-$pv - $fv) / $nper;
}
return $pmt;
}
/**
* Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate
* Excel equivalent: NPER
*
* @param float Interest rate per period
* @param float Periodic payment (annuity)
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function periods($rate, $pmt, $pv, $fv = 0, $type = 0)
{
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
if ($rate) {
if ($pmt == 0 && $pv == 0) {
return PEAR::raiseError('Payment and Present Value can\'t be both zero when the rate is not zero');
}
$nper = log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate))
/ log(1 + $rate);
} else {
if ($pmt == 0) {
return PEAR::raiseError('Rate and Payment can\'t be both zero');
}
$nper = (-$pv -$fv) / $pmt;
}
return $nper;
}
/**
* Returns the periodic interest rate for a cash flow with constant periodic payments (annuities)
* Excel equivalent: RATE
*
* @param int Number of periods
* @param float Periodic payment (annuity)
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @param float guess for the interest rate
* @return float
* @static
* @access public
*/
function rate($nper, $pmt, $pv, $fv = 0, $type = 0, $guess = 0.1)
{
// To solve the equation
require_once 'Math/Numerical/RootFinding/NewtonRaphson.php';
// To preserve some variables in the Newton-Raphson callback functions
require_once 'Math/Finance_FunctionParameters.php';
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
// Utilization of a Singleton class to preserve given values of other variables in the callback functions
$parameters = array(
'nper' => $nper,
'pmt' => $pmt,
'pv' => $pv,
'fv' => $fv,
'type' => $type,
);
$parameters_class =& Math_Finance_FunctionParameters::getInstance($parameters, True);
$newtonRaphson = new Math_Numerical_RootFinding_Newtonraphson(array('err_tolerance' => FINANCE_PRECISION));
return $newtonRaphson->compute(array('Math_Finance', '_tvm'), array('Math_Finance', '_dtvm'), $guess);
}
/**
* Callback function only used by Newton-Raphson algorithm. Returns value of function to be solved.
*
* Uses a previously instanced Singleton class to retrieve given values of other variables in the function
*
* @param float Interest rate
* @return float
* @static
* @access private
*/
function _tvm($rate)
{
require_once 'Math/Finance_FunctionParameters.php';
$parameters_class =& Math_Finance_FunctionParameters::getInstance();
$nper = $parameters_class->parameters['nper'];
$pmt = $parameters_class->parameters['pmt'];
$pv = $parameters_class->parameters['pv'];
$fv = $parameters_class->parameters['fv'];
$type = $parameters_class->parameters['type'];
return $pv * pow(1 + $rate, $nper) + $pmt * (1 + $rate * $type) * (pow(1 + $rate, $nper) - 1) / $rate + $fv;
}
/**
* Callback function only used by Newton-Raphson algorithm. Returns value of derivative of function to be solved.
*
* Uses a previously instanced Singleton class to retrieve given values of other variables in the function
*
* @return float
* @static
* @access private
*/
function _dtvm($rate)
{
require_once 'Math/Finance_FunctionParameters.php';
$parameters_class =& Math_Finance_FunctionParameters::getInstance();
$nper = $parameters_class->parameters['nper'];
$pmt = $parameters_class->parameters['pmt'];
$pv = $parameters_class->parameters['pv'];
$type = $parameters_class->parameters['type'];
return $nper * $pv * pow(1 + $rate, $nper - 1)
+ $pmt *
($type * (pow(1 + $rate, $nper) - 1) / $rate
+ (1 + $rate * $type) * ($nper * $rate * pow(1 + $rate, $nper - 1) - pow(1 + $rate, $nper) + 1) / pow($rate,2));
}
/**
* Returns the interest payment for a given period for a cash flow with constant periodic payments (annuities)
* and interest rate.
* Excel equivalent: IMPT
*
* @param float Interest rate per period
* @param int Period for which the interest payment will be calculated
* @param int Number of periods
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function interestPayment($rate, $per, $nper, $pv, $fv = 0, $type = 0)
{
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
$interestAndPrincipal = Math_Finance::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
return $interestAndPrincipal[0];
}
/**
* Returns the principal payment for a given period for a cash flow with constant periodic payments (annuities)
* and interest rate
* Excel equivalent: PPMT
*
* @param float Interest rate per period
* @param int Period for which the principal payment will be calculated
* @param int Number of periods
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return float
* @static
* @access public
*/
function principalPayment($rate, $per, $nper, $pv, $fv = 0, $type = 0)
{
if ($type != FINANCE_PAY_END && $type != FINANCE_PAY_BEGIN) {
return PEAR::raiseError('Payment type must be FINANCE_PAY_END or FINANCE_PAY_BEGIN');
}
$interestAndPrincipal = Math_Finance::_interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type);
return $interestAndPrincipal[1];
}
/**
* Returns the interest and principal payment for a given period for a cash flow with constant
* periodic payments (annuities) and interest rate
*
* @param float Interest rate per period
* @param int Number of periods
* @param float Present Value
* @param float Future Value
* @param int Payment type:
FINANCE_PAY_END (default): at the end of each period
FINANCE_PAY_BEGIN: at the beginning of each period
* @return array
* @static
* @access private
*/
function _interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type)
{
$pmt = Math_Finance::payment($rate, $nper, $pv, $fv, $type);
//echo "pmt: $pmt\n\n";
$capital = $pv;
for ($i = 1; $i<= $per; $i++) {
// in first period of advanced payments no interests are paid
$interest = ($type && $i == 1)? 0 : -$capital * $rate;
$principal = $pmt - $interest;
$capital += $principal;
//echo "$i\t$capital\t$interest\t$principal\n";
}
return array($interest, $principal);
}
/*******************************************************************
** Cash Flow Functions *****
*******************************************************************/
/**
* Returns the Net Present Value of a cash flow series given a discount rate
* Excel equivalent: NPV
*
* @param float Discount interest rate
* @param array Cash flow series
* @return float
* @static
* @access public
*/
function netPresentValue($rate, $values)
{
if (!is_array($values)) {
return PEAR::raiseError('The cash flow series most be an array');
}
return MATH_Finance::_npv($rate, $values);
}
/**
* Returns the internal rate of return of a cash flow series
* Excel equivalent: IRR
*
* @param array Cash flow series
* @param float guess for the interest rate
* @return float
* @static
* @access public
*/
function internalRateOfReturn($values, $guess = 0.1)
{
// To solve the equation
require_once 'Math/Numerical/RootFinding/NewtonRaphson.php';
// To preserve some variables in the Newton-Raphson callback functions
require_once 'Math/Finance_FunctionParameters.php';
if (!is_array($values)) {
return PEAR::raiseError('The cash flow series most be an array');
}
if (min($values) * max($values) >= 0) {
return PEAR::raiseError('Cash flow must contain at least one positive value and one negative value');
}
$parameters_class =& Math_Finance_FunctionParameters::getInstance(array('values' => $values), True);
$newtonRaphson = new Math_Numerical_RootFinding_Newtonraphson(array('err_tolerance' => FINANCE_PRECISION));
return $newtonRaphson->compute(array('Math_Finance', '_npv'), array('Math_Finance', '_dnpv'), $guess);
}
/**
* Function used by NPV() and as a callback by Newton-Raphson algorithm.
* Returns value of Net Present Value of a cash flow series.
*
* Uses a previously instanced Singleton class to retrieve given values of other variables in the function
*
* @param float Discount interest rate
* @param array Cash flow series
* @return float
* @static
* @access private
*/
function _npv($rate, $values = array())
{
require_once 'Math/Finance_FunctionParameters.php';
if (!$values) {
// called from IRR
$parameters_class =& Math_Finance_FunctionParameters::getInstance();
$values = $parameters_class->parameters['values'];
}
$npv = 0;
$nper = count($values);
for ($i = 1; $i <= $nper; $i++) {
$npv += $values[$i-1]/ pow(1 + $rate, $i);
}
return $npv;
}
/**
* Callback function used by by Newton-Raphson algorithm to calculate IRR.
* Returns value of derivative function to be solved.
*
* Uses a previously instanced Singleton class to retrieve given values of other variables in the function
*
* @param float Discount interest rate
* @param array Cash flow series
* @return float
* @static
* @access private
*/
function _dnpv($rate, $values = array())
{
require_once 'Math/Finance_FunctionParameters.php';
if (!$values) {
// called from IRR
$parameters_class =& Math_Finance_FunctionParameters::getInstance();
$values = $parameters_class->parameters['values'];
}
$dnpv = 0;
$nper = count($values);
for ($i = 1; $i <= $nper; $i++) {
$dnpv += $values[$i-1] * (-$i) * pow(1 + $rate, $i - 1) / pow(1 + $rate, 2 * $i);
}
return $dnpv;
}
/**
* Returns the internal rate of return of a cash flow series, considering both financial and reinvestment rates
* Excel equivalent: MIRR
*
* @param array Cash flow series
* @param float Interest rate on the money used in the cash flow
* @param float Interest rate received when reinvested
* @return float
* @static
* @access public
*/
function modifiedInternalRateOfReturn($values, $finance_rate, $reinvest_rate)
{
if (!is_array($values)) {
return PEAR::raiseError('The cash flow series most be an array');
}
if (min($values) * max($values) >= 0) {
return PEAR::raiseError('Cash flow must contain at least one positive value and one negative value');
}
$positive_flows = $negative_flows = array();
foreach ($values as $value) {
if ($value >= 0) {
$positive_flows[] = $value;
$negative_flows[] = 0;
} else {
$positive_flows[] = 0;
$negative_flows[] = $value;
}
}
$nper = count($values);
return pow(-Math_Finance::netPresentValue($reinvest_rate, $positive_flows) * pow(1 + $reinvest_rate, $nper)
/ Math_Finance::netPresentValue($finance_rate, $negative_flows) / (1 + $finance_rate), 1/($nper - 1)) - 1;
}
/*******************************************************************
** Bonds Functions *****
*******************************************************************/
/**
* Returns the difference of days between two dates based on a daycount basis
*
* @param int First date (UNIX timestamp)
* @param int Second date (UNIX timestamp)
* @param int Type of day count basis:
FINANCE_COUNT_NASD(default): US(NASD) 30/360
FINANCE_COUNT_ACTUAL_ACTUAL: Actual/actual
FINANCE_COUNT_ACTUAL_360: Actual/360
FINANCE_COUNT_ACTUAL_365: Actual/365
FINANCE_COUNT_EUROPEAN: European 30/360
* @return int
* @static
* @access public
*/
function daysDifference($date1, $date2, $basis)
{
$y1 = date('Y', $date1);
$m1 = date('n', $date1);
$d1 = date('j', $date1);
$y2 = date('Y', $date2);
$m2 = date('n', $date2);
$d2 = date('j', $date2);
switch ($basis) {
case FINANCE_COUNT_NASD:
if ($d2 == 31 && ($d1 == 30 || $d1 == 31)) {
$d2 = 30;
}
if ($d1 == 31) {
$d1 = 30;
}
return ($y2 - $y1) * 360 + ($m2 - $m1) * 30 + $d2 - $d1;
case FINANCE_COUNT_ACTUAL_ACTUAL:
case FINANCE_COUNT_ACTUAL_360:
case FINANCE_COUNT_ACTUAL_365:
return ($date2 - $date1) / 86400;
case FINANCE_COUNT_EUROPEAN: // European 30/360
return ($y2 - $y1) * 360 + ($m2 - $m1) * 30 + $d2 - $d1;
}
}
/**
* Returns the number of days in the year based on a daycount basis
*
* @param int Year
* @param int Type of day count basis:
FINANCE_COUNT_NASD(default): US(NASD) 30/360
FINANCE_COUNT_ACTUAL_ACTUAL: Actual/actual
FINANCE_COUNT_ACTUAL_360: Actual/360
FINANCE_COUNT_ACTUAL_365: Actual/365
FINANCE_COUNT_EUROPEAN: European 30/360
* @return int
* @static
* @access public
*/
function daysPerYear($year, $basis)
{
switch ($basis) {
case FINANCE_COUNT_NASD:
return 360;
case FINANCE_COUNT_ACTUAL_ACTUAL:
return checkdate(2, 29, $year)? 366 : 365;
case FINANCE_COUNT_ACTUAL_360:
return 360;
case FINANCE_COUNT_ACTUAL_365:
return 365;
case FINANCE_COUNT_EUROPEAN:
return 360;
}
}
/**
* Returns the yield for a treasury bill
* Excel equivalent: TBILLYIELD
*
* @param int Settlement date (UNIX timestamp)
* @param int Maturity date (UNIX timestamp)
* @param float TBill price per $100 face value
* @return float
* @static
* @access public
*/
function TBillYield($settlement, $maturity, $pr)
{
if ($settlement >= $maturity) {
return PEAR::raiseError('Maturity must happen before settlement!');
}
$dsm = ($maturity - $settlement) / 86400; // transform to days
if ($dsm > 360) {
return PEAR::raiseError("maturity can't be more than one year after settlement");
}
return (100 - $pr) * 360 / $pr / $dsm;
}
/**
* Returns the price per $100 face value for a Treasury bill
* Excel equivalent: TBILLPRICE
*
* @param int Settlement date (UNIX timestamp)
* @param int Maturity date (UNIX timestamp)
* @param float T-Bill discount rate
* @return float
* @static
* @access public
*/
function TBillPrice($settlement, $maturity, $discount)
{
if ($settlement >= $maturity) {
return PEAR::raiseError('Maturity must happen before settlement!');
}
$dsm = ($maturity - $settlement) / 86400; // transform to days
if ($dsm > 360) {
return PEAR::raiseError("maturity can't be more than one year after settlement");
}
return 100 * (1 - $discount * $dsm / 360);
}
/**
* Returns the bond-equivalent yield for a Treasury bill
* Excel equivalent: TBILLEQ
*
* @param int Settlement date (UNIX timestamp)
* @param int Maturity date (UNIX timestamp)
* @param float T-Bill discount rate
* @return float
* @static
* @access public
*/
function TBillEquivalentYield($settlement, $maturity, $discount)
{
if ($settlement >= $maturity) {
return PEAR::raiseError('Maturity must happen before settlement!');
}
$dsm = Math_Finance::daysDifference($settlement, $maturity, FINANCE_COUNT_ACTUAL_365);
if ($dsm <= 182) {
// for one half year or less, the bond-equivalent-yield is equivalent to an actual/365 interest rate
return 365 * $discount / (360 - $discount * $dsm);
} elseif ($dsm == 366
&& ((date('m', $settlement) <= 2 && checkdate(2, 29, date('Y', $settlement)))
|| (date('m', $settlement) > 2 && checkdate(2, 29, date('Y', $maturity))))) {
return 2 * (sqrt(1 - $discount * 366 / ($discount * 366 - 360)) - 1);
} elseif ($dsm > 365) {
return PEAR::raiseError("maturity can't be more than one year after settlement");
} else {
// thanks to Zhang Qingpo (zhangqingpo@yahoo.com.cn) for solving this riddle :)
return (-$dsm + sqrt(pow($dsm, 2) - (2 * $dsm - 365) * $discount * $dsm * 365 / ($discount * $dsm - 360))) / ($dsm - 365 / 2);
}
}
/**
* Returns the discount rate for a bond
* Excel equivalent: DISC
*
* @param int Settlement date (UNIX timestamp)
* @param int Maturity date (UNIX timestamp)
* @param float The bond's price per $100 face value
* @param float The bond's redemption value per $100 face value
* @param int Type of day count basis:
FINANCE_COUNT_NASD(default): US(NASD) 30/360
FINANCE_COUNT_ACTUAL_ACTUAL: Actual/actual
FINANCE_COUNT_ACTUAL_360: Actual/360
FINANCE_COUNT_ACTUAL_365: Actual/365
FINANCE_COUNT_EUROPEAN: European 30/360
* @return float
* @static
* @access public
*/
function discountRate($settlement, $maturity, $pr, $redemption, $basis = 0)
{
$days_per_year = Math_Finance::daysPerYear(date('Y', $settlement), $basis);
$dsm = Math_Finance::daysDifference($settlement, $maturity, $basis);
return ($redemption - $pr) * $days_per_year / $redemption / $dsm;
}
/**
* Returns the price per $100 face value of a discounted bond
* Excel equivalent: PRICEDISC
*
* @param int Settlement date (UNIX timestamp)
* @param int Maturity date (UNIX timestamp)
* @param float The bond's discount rate
* @param float The bond's redemption value per $100 face value
* @param int Type of day count basis:
FINANCE_COUNT_NASD(default): US(NASD) 30/360
FINANCE_COUNT_ACTUAL_ACTUAL: Actual/actual
FINANCE_COUNT_ACTUAL_360: Actual/360
FINANCE_COUNT_ACTUAL_365: Actual/365
FINANCE_COUNT_EUROPEAN: European 30/360
* @return float
* @static
* @access public
*/
function priceDiscount($settlement, $maturity, $discount, $redemption, $basis = 0)
{
$days_per_year = Math_Finance::daysPerYear(date('Y', $settlement), $basis);
$dsm = Math_Finance::daysDifference($settlement, $maturity, $basis);
return $redemption - $discount * $redemption * $dsm / $days_per_year;
}
/*******************************************************************
** Depreciation Functions *****
*******************************************************************/
/**
* Returns the depreciation of an asset using the fixed-declining balance method
* Excel equivalent: DB
*
* @param float The initial cost of the asset
* @param float Salvage value of the asset
* @param int Number of depreciation periods (same unit as $life)
* @param int Number of months in the first year, defaults to 12
* @return float
* @static
* @access public
*/
function depreciationFixedDeclining($cost, $salvage, $life, $period, $month = 12)
{
$cost = (float) $cost;
$salvage = (float) $salvage;
$life = (int) $life;
$period = (int) $period;
$month = (int) $month;
if ($cost < 0 || $life < 0) {
return PEAR::raiseError('cost and life must be absolute positive numbers');
}
if ($period < 1) {
return PEAR::raiseError('period must be greater or equal than one');
}
$rate = 1 - pow(($salvage / $cost), (1 / $life));
$rate = round($rate, 3);
$acc_depreciation = 0;
for ($i = 1; $i <= $period; $i++) {
if ($i == 1) {
$depreciation_period = $cost * $rate * $month / 12;
} elseif ($i == ($life + 1)) {
$depreciation_period = ($cost - $acc_depreciation) * $rate * (12 - $month) / 12;
} else {
$depreciation_period = ($cost - $acc_depreciation) * $rate;
}
$acc_depreciation += $depreciation_period;
}
return $depreciation_period;
}
/**
* Returns the straight-line depreciation of an asset for each period
* Excel equivalent: SLN
*
* @param float The initial cost of the asset
* @param float Salvage value of the asset
* @param int Number of depreciation periods
* @return float
* @static
* @access public
*/
function depreciationStraightLine($cost, $salvage, $life)
{
$life = (int) $life;
if ($cost < 0 || $life < 0) {
return PEAR::raiseError('cost and life must be absolute positive numbers');
}
return (($cost - $salvage) / $life);
}
/**
* Returns the depreciation for an asset in a given period using the sum-of-years' digits method
* Excel equivalent: SYD
*
* @param float The initial cost of the asset
* @param float Salvage value of the asset
* @param int Number of depreciation periods
* @param int Period (must be in the same unit as $life)
* @return float
* @static
* @access public
*/
function depreciationSYD($cost, $salvage, $life, $per)
{
return (($cost - $salvage) * ($life - $per + 1) * 2 / ($life) / ($life +1));
}
}
?>