RE: financial_class.php

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi
 
I checked code, there is no problem at all. 
 
Give me your input and output then only can judge where is problem!
 
Thanks,
Muthukumar Selvarasu,
Project Manager (Web Development),
Webmasters Ltd.
From: php-objects@xxxxxxxxxxxxxxx [mailto:php-objects@xxxxxxxxxxxxxxx] On
Behalf Of Kaneshalingam
Sent: Wednesday, January 02, 2008 8:29 PM
To: php-objects@xxxxxxxxxxxxxxx
Subject: RE:  financial_class.php
 
Thanks Muthukumar,

I can not rectify the problem,

I place entire code here.

Look at this and sort out my prob

<?php
/**
* EGM Mathematical Finance class. 
* 
* Financial functions with the Excel function names and
* parameter order.
* 
* @version $Id: financial_class.php,v 1.0.6 2004-06-30 13:20:56-05 egarcia
Exp $
* @author Enrique García M. <egarcia@xxxxxx <mailto:egarcia%40egm.as> >
* @copyright (c) 2003-2004 Enrique García M.
* @since Saturday, January 7, 2003
**/

/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/

/**
* Constants to define the accuracy in numeric aproximations, and the max
* iterations to solve
*/
define('FINANCIAL_ACCURACY', 1.0e-6);
define('FINANCIAL_MAX_ITERATIONS', 100);

define('FINANCIAL_SECS_PER_DAY', 24 * 60 * 60);
define('FINANCIAL_HALF_SEC', 0.5 / FINANCIAL_SECS_PER_DAY);

/**
* Constants for the day-counting
* rules are mandated by NASD Uniform Practice Code, Section 46, and MSRB
Rule G-33,
* described in Mayle (1993, 17?23, A3?A15). See Public Securities
Association (1990)
* for other rules applicable to state and municipal bonds.
*
* base 0: BASIS_MSRB_30_360
* MSRB/NSAD 30/360 daycount method 
* see MSRB Rule G-33
* http://www.msrb.org/msrb1/rules/ruleg33.htm
* http://www.msrb.org/msrb1/rules/interpg33.htm
* Number of days = (Y2 - Y1) 360 + (M2 - M1) 30 + (D2 - D1)
* The variables "Yl," "M1," and "D1" are defined as the year, month, and
day, respectively,
* of the date on which the computation period begins (June 15, 1982, in your
example),
* and "Y2,a" "M2," and "D2" as the year, month, and day of the date on which
the
* computation period ends (July 1, 1982, in your example).
* For purposes of this formula, if the symbol "D2" has a value of "31," and
the symbol "D1"
* has a value of "30" or "31," the value of the symbol "D2" shall be changed
to "30."
* If the symbol "D1" has a value of "31," the value of the symbol "D1" shall
be changed to
* "30." For purposes of this rule time periods shall be computed to include
the day
* specified in the rule for the beginning of the period but not to include
the day
* specified for the end of the period.
*
* base 1: BASIS_ACTACT
* Actual/Actual daycount method
* date adjustment: no change
* date difference: serial delta (# of days)
*
* base 2: BASIS_ACT_360
* Actual/360 daycount method
* date adjustment: no change
* date difference: serial delta
* 360/freq for length of coupon period
*
* base 3: BASIS_ACT_365
* Actual/365 daycount method (short term and Canadian bonds only)
* date adjustment: no change
* date difference: serial delta
* 365/freq for length of coupon period, (with decimal answer)
* base 4: BASIS_30E_360
* date adjustment: from_date is changed from 31st to 30th
* to_date is changed from 31st to 30th
* date difference: each month 30 days, within a month serial delta
* base 5: BASIS_30Ep_360
* date adjustment: from_date is changed from 31st to 30th
* to_date is changed from 31st to 1st of following month
* date difference: each month 30 days, within a month serial delta
*/
define('FINANCIAL_BASIS_MSRB_30_360', 0);
define('FINANCIAL_BASIS_ACT_ACT', 1);
define('FINANCIAL_BASIS_ACT_360', 2);
define('FINANCIAL_BASIS_ACT_365', 3);
define('FINANCIAL_BASIS_30E_360', 4);
define('FINANCIAL_BASIS_30Ep_360', 5);

class Financial
{
function Financial()
{
// forces the precision for calculations
ini_set('precision', '14');
}

/**
* DATEADD
* Returns a new Unix timestamp value based on adding an interval to the
specified date.
* @param string $datepart is the parameter that specifies on which part of
the date to return a new value.
* @param integer $number is the value used to increment datepart. If you
specify a value that is not an integer, the fractional part of the value is
discarded.
* @param integer $date a Unix timestamp value. 
* @return integer a Unix timestamp.
*/
function DATEADD($datepart, $number, $date)
{
$number = intval($number);
switch (strtolower($datepart)) {
case 'yy':
case 'yyyy':
case 'year':
$d = getdate($date);
$d['year'] += $number;
if (($d['mday'] == 29) && ($d['mon'] == 2) && (date('L', mktime(0, 0, 0, 1,
1, $d['year'])) == 0)) $d['mday'] = 28;
return mktime($d['hours'], $d['minutes'], $d['seconds'], $d['mon'],
$d['mday'], $d['year']);
break;
case 'm':
case 'mm':
case 'month':
$d = getdate($date);
$d['mon'] += $number;
while($d['mon'] > 12) {
$d['mon'] -= 12;
$d['year']++;
}
while($d['mon'] < 1) {
$d['mon'] += 12;
$d['year']--;
}
$l = date('t', mktime(0,0,0,$d['mon'],1,$d['year']));
if ($d['mday'] > $l) $d['mday'] = $l;
return mktime($d['hours'], $d['minutes'], $d['seconds'], $d['mon'],
$d['mday'], $d['year']);
break;
case 'd':
case 'dd':
case 'day':
return ($date + $number * 86400); 
break;
default:
die("Unsupported operation");
}
}

/**
* DATEDIFF
* Returns the number of date and time boundaries crossed between two
specified dates.
* @param string $datepart is the parameter that specifies on which part of
the date to calculate the difference.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation. 
* @return integer the number between the two dates.
*/
function DATEDIFF($datepart, $startdate, $enddate)
{
switch (strtolower($datepart)) {
case 'yy':
case 'yyyy':
case 'year':
$di = getdate($startdate);
$df = getdate($enddate);
return $df['year'] - $di['year'];
break;
case 'q':
case 'qq':
case 'quarter':
die("Unsupported operation");
break;
case 'n':
case 'mi':
case 'minute':
return ceil(($enddate - $startdate) / 60); 
break;
case 'hh':
case 'hour':
return ceil(($enddate - $startdate) / 3600); 
break;
case 'd':
case 'dd':
case 'day':
return ceil(($enddate - $startdate) / 86400); 
break;
case 'wk':
case 'ww':
case 'week':
return ceil(($enddate - $startdate) / 604800); 
break;
case 'm':
case 'mm':
case 'month':
$di = getdate($startdate);
$df = getdate($enddate);
return ($df['year'] - $di['year']) * 12 + ($df['mon'] - $di['mon']);
break;
default:
die("Unsupported operation");
}
}

/**
* Determine if the basis is valid
* @param integer $basis
* @return bool
*/
function _is_valid_basis($basis)
{
return (($basis >= FINANCIAL_BASIS_MSRB_30_360) && ($basis <=
FINANCIAL_BASIS_30Ep_360));
}

/**
* Determine if the frequency is valid
* @param integer $frequency
* @return bool
*/
function _is_valid_frequency($frequency)
{
return (($frequency == 1) || ($frequency == 2) || ($frequency == 4));
}

/**
* DAYS360
* Returns the number of days between two dates based on a 360-day year
* (twelve 30-day months), which is used in some accounting calculations.
* Use this function to help compute payments if your accounting system
* is based on twelve 30-day months.
* @param integer $start_date is the beginning date (Unix timestamp) for the
calculation.
* @param integer $end_date is the ending date (Unix timestamp) for the
calculation.
* @param bool $method is a logical value that specifies whether to use the
U.S. or European method in the calculation.
* @return integer the number of days between two dates based on a 360-day
year
*/
function DAYS360($start_date, $end_date, $method = false)
{
if ($method) {
return $this->Thirty360USdayCount($start_date, $end_date);
} else {
return $this->Thirty360EUdayCount($start_date, $end_date);
}
}

/**
* Thirty360USdayCount
* Returns the number of days between two dates based on a 360-day year
* (twelve 30-day months) using the US method.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return integer the number of days between two dates
*/
function Thirty360USdayCount($startdate, $enddate)
{
$d1 = getdate($startdate);
$d2 = getdate($enddate);
$dd1 = $d1['mday']; $mm1 = $d1['mon']; $yy1 = $d1['year'];
$dd2 = $d2['mday']; $mm2 = $d2['mon']; $yy2 = $d2['year'];

if ($dd2 == 31 && $dd1 < 30) { $dd2 = 1; $mm2++; }

return 360 * ($yy2 - $yy1) + 30 * ($mm2 - $mm1 - 1) + max(0, 30 - $dd1) +
min(30, $dd2);
}

/**
* Thirty360USyearFraction
* Returns the period between two dates as a fraction of year.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return float the fraction of years between two dates
*/
function Thirty360USyearFraction($startdate, $enddate)
{
return $this->Thirty360USdayCount($startdate, $enddate) / 360.0;
}

/**
* Thirty360EUdayCount
* Returns the number of days between two dates based on a 360-day year
* (twelve 30-day months) using the EUROPEAN method.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return integer the number of days between two dates
*/
function Thirty360EUdayCount($startdate, $enddate)
{
$d1 = getdate($startdate);
$d2 = getdate($enddate);
$dd1 = $d1['mday']; $mm1 = $d1['mon']; $yy1 = $d1['year'];
$dd2 = $d2['mday']; $mm2 = $d2['mon']; $yy2 = $d2['year'];

return 360 * ($yy2 - $yy1) + 30 * ($mm2 - $mm1 - 1) + max(0, 30 - $dd1) +
min(30, $dd2);
}

/**
* Thirty360EUyearFraction
* Returns the period between two dates as a fraction of year.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return float the fraction of years between two dates
*/
function Thirty360EUyearFraction($startdate, $enddate)
{
return $this->Thirty360EUdayCount($startdate, $enddate) / 360.0;
}

/**
* ActualActualdayCount
* Returns the number of days between two dates.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return integer the number of days between two dates
*/
function ActualActualdayCount($startdate, $enddate)
{
return $this->DATEDIFF('day', $startdate, $enddate);
}

/**
* ActualActualyearFraction
* Returns the period between two dates as a fraction of year.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @param date $refPeriodStart is the reference beginning date (Unix
timestamp) for the inner calculation.
* @param date $refPeriodEnd is the reference ending date (Unix timestamp)
for the inner calculation.
* @return float the fraction of years between two dates
*/
function ActualActualyearFraction($startdate, $enddate, $refPeriodStart =
null, $refPeriodEnd = null)
{
$t = time();
if (!isset($refPeriodStart)) $refPeriodStart = $startdate;
if (!isset($refPeriodEnd)) $refPeriodEnd = $enddate;

/*
if ($this->DATEDIFF('day', $startdate, $enddate) == 0) return 0.0;
$d1 = getdate($startdate);
$d2 = getdate($enddate);
$dib1 = ((date('L', $startdate) == 1) ? 366.0 : 365.0);
$dib2 = ((date('L', $enddate) == 1) ? 366.0 : 365.0);

$sum = $d2['year'] - $d1['year'] - 1;
$sum += $this->ActualActualdayCount($startdate, mktime(0,0,0,1,1,$d1['year']
+ 1)) / $dib1;
$sum += $this->ActualActualdayCount(mktime(0,0,0,1,1,$d2['year']), $enddate)
/ $dib2;
return $sum;
*/

if ($this->DATEDIFF('day', $startdate, $enddate) == 0) return 0.0;

if ($startdate > $enddate) die("Invalid dates");
if (!($refPeriodStart != $t) && ($refPeriodEnd != $t) &&
($refPeriodEnd > $refPeriodStart) && ($refPeriodEnd > $startdate))
die("Invalid reference period");

$months = intval(0.5 + 12 * $this->DATEDIFF('day', $refPeriodStart,
$refPeriodEnd) / 365);
$period = $months / 12.0;
if($months == 0) die("number of months does not divide 12 exactly");
if ($enddate <= $refPeriodEnd) {
// here refPeriodEnd is a future (notional?) payment date
if ($startdate >= $refPeriodStart) {
// here refPeriodStart is the last (maybe notional)
// payment date.
// refPeriodStart <= startdate <= enddate <= refPeriodEnd
// [maybe the equality should be enforced, since
// refPeriodStart < startdate <= enddate < refPeriodEnd
// could give wrong results] ???
return $period * $this->ActualActualdayCount($startdate, $enddate) /
$this->ActualActualdayCount($refPeriodStart, $refPeriodEnd);
} else {
// here refPeriodStart is the next (maybe notional)
// payment date and refPeriodEnd is the second next
// (maybe notional) payment date.
// startdate < refPeriodStart < refPeriodEnd
// AND enddate <= refPeriodEnd
// this case is long first coupon
// the last notional payment date
$previousRef = $this->DATEADD('month', -$months, $refPeriodStart);
if ($enddate > $refPeriodStart)
return $this->ActualActualyearFraction($startdate, $refPeriodStart,
$previousRef,
$refPeriodStart) +
$this->ActualActualyearFraction($refPeriodStart, $enddate, $refPeriodStart,
$refPeriodEnd);
else
return
$this->ActualActualyearFraction($startdate,$enddate,$previousRef,$refPeriodS
tart);
}
} else {
// here refPeriodEnd is the last (notional?) payment date
// startdate < refPeriodEnd < enddate AND refPeriodStart < refPeriodEnd
if ($refPeriodStart > $startdate) die("Invalid dates");

// now it is: refPeriodStart <= startdate < refPeriodEnd < enddate

// the part from startdate to refPeriodEnd
$sum = $this->ActualActualyearFraction($startdate, $refPeriodEnd,
$refPeriodStart, $refPeriodEnd);

// the part from refPeriodEnd to enddate
// count how many regular periods are in [refPeriodEnd, enddate],
// then add the remaining time
$i = 0;
do {
$newRefStart = $this->DATEADD('month', $months * $i, $refPeriodEnd);
$newRefEnd = $this->DATEADD('month', $months * ($i + 1), $refPeriodEnd);
if ($enddate < $newRefEnd) {
break;
} else {
$sum += $period;
$i++;
}
} while (true);
$sum += $this->ActualActualyearFraction($newRefStart, $newRefEnd,
$newRefStart, $newRefEnd);
return $sum;
}
}

/**
* Actual360dayCount
* Returns the number of days between two dates.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return integer the number of days between two dates
*/
function Actual360dayCount($startdate, $enddate)
{
return $this->DATEDIFF('day', $startdate, $enddate);
}

/**
* Actual360yearFraction
* Returns the period between two dates as a fraction of 360 days year.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return float the fraction of years between two dates
*/
function Actual360yearFraction($startdate, $enddate)
{
return $this->Actual360dayCount($startdate, $enddate) / 360.0;
}

/**
* Actual365dayCount
* Returns the number of days between two dates.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return integer the number of days between two dates
*/
function Actual365dayCount($startdate, $enddate)
{
return $this->DATEDIFF('day', $startdate, $enddate);
}

/**
* Actual365yearFraction
* Returns the period between two dates as a fraction of 365 days year.
* @param integer $startdate is the beginning date (Unix timestamp) for the
calculation.
* @param integer $enddate is the ending date (Unix timestamp) for the
calculation.
* @return float the fraction of years between two dates
*/
function Actual365yearFraction($startdate, $enddate)
{
return $this->Actual365dayCount($startdate, $enddate) / 365.0;
}

/**
* DOLLARDE
* Converts a dollar price expressed as a fraction into a dollar
* price expressed as a decimal number. Use DOLLARDE to convert
* fractional dollar numbers, such as securities prices, to decimal
* numbers.
* @param float $fractional_dollar is a number expressed as a fraction.
* @param integer $fraction is the integer to use in the denominator of the
fraction.
* @return float dollar price expressed as a decimal number.
*/
function DOLLARDE($fractional_dollar, $fraction)
{
$fraction = intval($fraction);
$integer = intval($fractional_dollar);
return $integer + 100 * ($fractional_dollar - $integer) / $fraction;
}

/**
* DOLLARFR
* Converts a dollar price expressed as a decimal number into a
* dollar price expressed as a fraction. Use DOLLARFR to convert
* decimal numbers to fractional dollar numbers, such as securities
* prices.
* @param float $decimal_dollar is a decimal number.
* @param integer $fraction is the integer to use in the denominator of the
fraction.
* @return float dollar price expressed as a fraction.
*/
function DOLLARFR($decimal_dollar, $fraction)
{
$fraction = intval($fraction);
$integer = intval($decimal_dollar);
return ($decimal_dollar - $integer) * $fraction / 100 + $integer;
}

/**
* DDB
* Returns the depreciation of an asset for a specified period using
* the double-declining balance method or some other method you specify.
* @param float $cost is the initial cost of the asset.
* @param float $salvage is the value at the end of the depreciation
(sometimes called the salvage value of the asset).
* @param integer $life is the number of periods over which the asset is
being depreciated (sometimes called the useful life of the asset).
* @param integer $period is the period for which you want to calculate the
depreciation. Period must use the same units as life.
* @param float $factor is the rate at which the balance declines. If factor
is omitted, it is assumed to be 2 (the double-declining balance method).
* @return float the depreciation of n periods.
*/
function DDB($cost, $salvage, $life, $period, $factor = 2)
{
$x = 0;
$n = 0;
$life = intval($life);
$period = intval($period);
while ($period > $n) {
$x = $factor * $cost / $life;
if (($cost - $x) < $salvage) $x = $cost- $salvage;
if ($x < 0) $x = 0;
$cost -= $x;
$n++;
}
return $x;
}

/**
* SLN
* Returns the straight-line depreciation of an asset for one period.
* @param float $cost is the initial cost of the asset.
* @param float $salvage is the value at the end of the depreciation
(sometimes called the salvage value of the asset).
* @param integer $life is the number of periods over which the asset is
being depreciated (sometimes called the useful life of the asset).
* @return float the depreciation allowance for each period.
*/
function SLN($cost, $salvage, $life)
{
$sln = ($cost - $salvage) / $life;
return (is_finite($sln) ? $sln: null);
}

/**
* SYD
* Returns the sum-of-years' digits depreciation of an asset for
* a specified period.
* 
* (cost - salvage) * (life - per + 1) * 2
* SYD = -----------------------------------------
* life * (1 + life)
*
* @param float $cost is the initial cost of the asset.
* @param float $salvage is the value at the end of the depreciation
(sometimes called the salvage value of the asset).
* @param integer $life is the number of periods over which the asset is
depreciated (sometimes called the useful life of the asset).
* @param integer $per is the period and must use the same units as life. 
*/
function SYD($cost, $salvage, $life, $per)
{
$life = intval($life);
$per = intval($per);
$syd = (($cost - $salvage) * ($life - $per + 1) * 2) / ($life * (1 +
$life));
return (is_finite($syd) ? $syd: null);
}

/**
* @param float $fWert
* @param float $fRest
* @param float $fDauer
* @param float $fPeriode
* @param float $fFaktor
* @return float
*/
function _ScGetGDA($fWert, $fRest, $fDauer,$fPeriode, $fFaktor)
{
$fZins = $fFaktor / $fDauer;
if ($fZins >= 1.0) {
$fZins = 1.0;
if ($fPeriode == 1.0)
$fAlterWert = $fWert;
else
$fAlterWert = 0.0;
} else
$fAlterWert = $fWert * pow(1.0 - $fZins, $fPeriode - 1.0);

$fNeuerWert = $fWert * pow(1.0 - $fZins, $fPeriode);

if ($fNeuerWert < $fRest)
$fGda = $fAlterWert - $fRest;
else
$fGda = $fAlterWert - $fNeuerWert;

if ($fGda < 0.0) $fGda = 0.0;

return $fGda;
}

/**
* @param float $cost
* @param float $salvage
* @param float $life
* @param float $life1
* @param float $period
* @param float $factor
* @return float
*/
function _ScInterVDB($cost, $salvage, $life, $life1, $period, $factor)
{
$fVdb = 0;
$fIntEnd = ceil($period);
$nLoopEnd = $fIntEnd;
$fRestwert = $cost - $salvage;
$bNowLia = false;

$fLia = 0;
for ($i = 1; $i <= $nLoopEnd; $i++) {
if (!$bNowLia) {
$fGda = $this->_ScGetGDA($cost, $salvage, $life, $i, $factor);
$fLia = $fRestwert / ($life1 - (float)($i - 1));

if ($fLia > $fGda) {
$fTerm = $fLia;
$bNowLia = true;
} else {
$fTerm = $fGda;
$fRestwert -= $fGda;
}
} else
$fTerm = fLia;

if ($i == $nLoopEnd)
$fTerm *= ($period + 1.0 - $fIntEnd);
$fVdb += $fTerm;
}
return $fVdb;
}

/**
* VDB
* Returns the depreciation of an asset for any period you specify,
* including partial periods, using the double-declining balance method
* or some other method you specify. VDB stands for variable declining
balance.
* 
* @param float $cost is the initial cost of the asset.
* @param float $salvage is the value at the end of the depreciation
(sometimes called the salvage value of the asset).
* @param integer $life is the number of periods over which the asset is
depreciated (sometimes called the useful life of the asset).
* @param integer $start_period is the starting period for which you want to
calculate the depreciation. Start_period must use the same units as life.
* @param integer $end_period is the ending period for which you want to
calculate the depreciation. End_period must use the same units as life.
* @param float $factor is the rate at which the balance declines. If factor
is omitted, it is assumed to be 2 (the double-declining balance method).
Change factor if you do not want to use the double-declining balance method.
* @param bool $no_switch is a logical value specifying whether to switch to
straight-line depreciation when depreciation is greater than the declining
balance calculation.
* @return float the depreciation of an asset.
*/
function VDB($cost, $salvage, $life, $start_period, $end_period, $factor =
2.0, $no_switch = false)
{
// pre-validations
if (($start_period < 0)
|| ($end_period < $start_period)
|| ($end_period > $life)
|| ($cost < 0) || ($salvage > $cost)
|| ($factor <= 0))
return null;

// this implementation is borrowed from OppenOffice 1.0,
// 'sc/source/core/tool/interpr2.cxx' with a small changes
// from me.
$fVdb = 0.0;
$fIntStart = floor($start_period);
$fIntEnd = ceil($end_period);

if ($no_switch) {
$nLoopStart = (int) $fIntStart;
$nLoopEnd = (int) $fIntEnd;

for ($i = $nLoopStart + 1; $i <= $nLoopEnd; $i++) {
$fTerm = $this->_ScGetGDA($cost, $salvage, $life, $i, $factor);
if ($i == $nLoopStart + 1)
$fTerm *= (min($end_period, $fIntStart + 1.0) - $start_period);
elseif ($i == $nLoopEnd)
$fTerm *= ($end_period + 1.0 - $fIntEnd);
$fVdb += $fTerm;
}
} else {
$life1 = $life;

if ($start_period != $fIntStart)
if ($factor > 1) {
if ($start_period >= ($life / 2)) {
$fPart = $start_period - ($life / 2);
$start_period = $life / 2;
$end_period -= $fPart;
$life1 += 1;
}
}

$cost -= $this->_ScInterVDB($cost, $salvage, $life, $life1, $start_period,
$factor);
$fVdb = $this->_ScInterVDB($cost, $salvage, $life, $life - $start_period,
$end_period - $start_period, $factor);
}

return $fVdb;
}

/**
* Present value interest factor
*
* nper
* PVIF = (1 + rate)
*
* @param float $rate is the interest rate per period.
* @param integer $nper is the total number of periods.
* @return float the present value interest factor
*/
function _calculate_pvif ($rate, $nper)
{
return (pow(1 + $rate, $nper));
}

/**
* Future value interest factor of annuities
*
* nper
* (1 + rate) - 1
* FVIFA = -------------------
* rate
*
* @param float $rate is the interest rate per period.
* @param integer $nper is the total number of periods.
* @return float the present value interest factor of annuities
*/
function _calculate_fvifa ($rate, $nper)
{
// Removable singularity at rate == 0
if ($rate == 0)
return $nper;
else
// FIXME: this sucks for very small rates
return (pow(1 + $rate, $nper) - 1) / $rate;
}

function _calculate_interest_part ($pv, $pmt, $rate, $per)
{
return -($pv * pow(1 + $rate, $per) * $rate +
$pmt * (pow(1 + $rate, $per) - 1));
}

function _calculate_pmt ($rate, $nper, $pv, $fv, $type)
{
// Calculate the PVIF and FVIFA
$pvif = $this->_calculate_pvif ($rate, $nper);
$fvifa = $this->_calculate_fvifa ($rate, $nper);

return ((-$pv * $pvif - $fv ) / ((1.0 + $rate * $type) * $fvifa));
}

/**
* PV
* Returns the present value of an investment. The present value is
* the total amount that a series of future payments is worth now.
* For example, when you borrow money, the loan amount is the present
* value to the lender.
* 
* If rate = 0:
* PV = -(FV + PMT * nper)
* 
* Else
* / nper \
* | 1 - (1 + rate) |
* PMT * (1 + rate * type) * | ----------------- | - FV
* \ rate /
* PV = ------------------------------------------------------
* nper
* (1 + rate)
*
* @param float $rate is the interest rate per period.
* @param integer $nper is the total number of payment periods in an annuity.
* @param float $pmt is the payment made each period and cannot change over
the life of the annuity.
* @param float $fv is the future value, or a cash balance you want to attain
after the last payment is made.
* @param integer $type is the number 0 or 1 and indicates when payments are
due.
* @return float the present value of an investment.
*/
function PV($rate, $nper, $pmt, $fv = 0.0, $type = 0)
{
// Calculate the PVIF and FVIFA
$pvif = $this->_calculate_pvif ($rate, $nper);
$fvifa = $this->_calculate_fvifa ($rate, $nper);

if ($pvif == 0)
return null;
$pv = ((-$fv - $pmt * (1.0 + $rate * $type) * $fvifa) / $pvif);
return (is_finite($pv) ? $pv: null);
}

/**
* FV
* Returns the future value of an investment based on periodic,
* constant payments and a constant interest rate.
* 
* For a more complete description of the arguments in FV, see the PV
function.
* 
* Rate: is the interest rate per period.
* Nper: is the total number of payment periods in an annuity.
* Pmt: is the payment made each period; it cannot change over the life of
the
* annuity. Typically, pmt contains principal and interest but no other fees
* or taxes. If pmt is omitted, you must include the pv argument.
* Pv: is the present value, or the lump-sum amount that a series of future
* payments is worth right now. If pv is omitted, it is assumed to be 0
(zero),
* and you must include the pmt argument.
* Type: is the number 0 or 1 and indicates when payments are due. If type is
* omitted, it is assumed to be 0.
* 0 or omitted, At the end of the period
* 1, At the beginning of the period
* 
* If rate = 0:
* FV = -(PV + PMT * nper)
* 
* Else
* / nper \
* | 1 - (1 + rate) | nper
* FV = PMT * (1 + rate * type) * | ------------------ | - PV * (1 + rate)
* \ rate /
* 
**/
function FV($rate, $nper, $pmt, $pv = 0.0, $type = 0)
{
$pvif = $this->_calculate_pvif ($rate, $nper);
$fvifa = $this->_calculate_fvifa ($rate, $nper);

$fv = (-(($pv * $pvif) + $pmt *
(1.0 + $rate * $type) * $fvifa));

return (is_finite($fv) ? $fv: null);
}

/**
* FVSCHEDULE
* Returns the future value of an initial principal after applying a series
* of compound interest rates. Use FVSCHEDULE to calculate the future value
* of an investment with a variable or adjustable rate.
* 
**/
function FVSCHEDULE($principal, $schedule)
{
$n = count($schedule);
for ($i = 0; $i < $n; $i++)
$principal *= 1 + $schedule[$i];
return $principal;
}

/**
* PMT
* Calculates the payment for a loan based on constant payments
* and a constant interest rate.
* 
* For a more complete description of the arguments in PMT, see the PV
function.
* 
* Rate: is the interest rate for the loan.
* Nper: is the total number of payments for the loan.
* Pv: is the present value, or the total amount that a series of future
payments
* is worth now; also known as the principal.
* Fv: is the future value, or a cash balance you want to attain after the
last
* payment is made. If fv is omitted, it is assumed to be 0 (zero), that is,
* the future value of a loan is 0.
* Type: is the number 0 (zero) or 1 and indicates when payments are due.
* 0 or omitted, At the end of the period
* 1, At the beginning of the period
* 
* If rate = 0:
* -(FV + PV)
* PMT = ------------
* nper
* 
* Else
* 
* nper
* FV + PV * (1 + rate)
* PMT = --------------------------------------------
* / nper \
* | 1 - (1 + rate) |
* (1 + rate * type) * | ------------------ |
* \ rate /
* 
**/
function PMT($rate, $nper, $pv, $fv = 0.0, $type = 0)
{
$pmt = $this->_calculate_pmt ($rate, $nper, $pv, $fv, $type);
return (is_finite($pmt) ? $pmt: null);
}

/**
* IPMT
* Returns the interest payment for a given period for an investment based
* on periodic, constant payments and a constant interest rate.
* 
* For a more complete description of the arguments in IPMT, see the PV
function.
* 
*/
function IPMT($rate, $per, $nper, $pv, $fv = 0.0, $type = 0)
{
if (($per < 1) || ($per >= ($nper + 1)))
return null;
else {
$pmt = $this->_calculate_pmt ($rate, $nper, $pv, $fv, $type);
$ipmt = $this->_calculate_interest_part ($pv, $pmt, $rate, $per - 1);
return (is_finite($ipmt) ? $ipmt: null);
}
}

/**
* PPMT
* Returns the payment on the principal for a given period for an
* investment based on periodic, constant payments and a constant
* interest rate.
* 
**/
function PPMT($rate, $per, $nper, $pv, $fv = 0.0, $type = 0)
{
if (($per < 1) || ($per >= ($nper + 1)))
return null;
else {
$pmt = $this->_calculate_pmt ($rate, $nper, $pv, $fv, $type);
$ipmt = $this->_calculate_interest_part ($pv, $pmt, $rate, $per - 1);
return ((is_finite($pmt) && is_finite($ipmt)) ? $pmt - $ipmt: null);
}
}

/**
* NPER
* Returns the number of periods for an investment based on periodic,
* constant payments and a constant interest rate.
* 
* For a complete description of the arguments nper, pmt, pv, fv, and type,
see PV.
* 
* Nper: is the total number of payment periods in an annuity.
* Pmt: is the payment made each period and cannot change over the life
* of the annuity. Typically, pmt includes principal and interest but no
* other fees or taxes. If pmt is omitted, you must include the fv argument.
* Pv: is the present value Â? the total amount that a series of future
payments
* is worth now.
* Fv: is the future value, or a cash balance you want to attain after the
* last payment is made. If fv is omitted, it is assumed to be 0 (the future
* value of a loan, for example, is 0).
* Type: is the number 0 or 1 and indicates when payments are due.
* 0 or omitted, At the end of the period
* 1, At the beginning of the period
* 
* If rate = 0:
* -(FV + PV)
* nper = -----------
* PMT
* 
* Else
* / PMT * (1 + rate * type) - FV * rate \
* log | ------------------------------------- |
* \ PMT * (1 + rate * type) + PV * rate /
* nper = -----------------------------------------------
* log (1 + rate)
* 
**/
function NPER($rate, $pmt, $pv, $fv = 0.0, $type = 0)
{
if (($rate == 0) && ($pmt != 0))
$nper = (-($fv + $pv) / $pmt);
elseif ($rate <= 0.0)
return null;
else {
$tmp = ($pmt * (1.0 + $rate * $type) - $fv * $rate) /
($pv * $rate + $pmt * (1.0 + $rate * $type));
if ($tmp <= 0.0)
return null;
$nper = (log10($tmp) / log10(1.0 + $rate));
}
return (is_finite($nper) ? $nper: null);
}

/*
* EFFECT
* Returns the effective annual interest rate, given the nominal annual
* interest rate and the number of compounding periods per year.
* 
* / nominal_rate \ npery
* EFFECT = | 1 + -------------- | - 1
* \ npery /
* 
**/
function EFFECT($nominal_rate, $npery)
{
$npery = intval($npery);
if (($nominal_rate <= 0) || ($npery < 1)) return null;
$effect = pow(1 + $nominal_rate / $npery, $npery) - 1;
return (is_finite($effect) ? $effect: null);
}

/**
* NOMINAL
* Returns the nominal annual interest rate, given the effective rate
* and the number of compounding periods per year.
* 
* (1 / npery)
* NOMINAL = npery * (1 + effect_rate) - npery
* 
**/
function NOMINAL($effect_rate, $npery)
{
$npery = intval($npery);
if (($effect_rate <= 0) || ($npery < 1)) return null;
$nominal = $npery * pow(1 + $effect_rate, 1 / $npery) - $npery;
return (is_finite($nominal) ? $nominal: null);
}

/**
* DISC
* Returns the discount rate for a security.
* 
* redemption - pr
* DISC = ---------------------------
* redemption * yearfraction
* 
**/
function DISC($settlement, $maturity, $pr, $redemption, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (($pr <= 0) || ($redemption <= 0)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual days/actual days
$dsm = $this->ActualActualyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual days/360
$dsm = $this->Actual360yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual days/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUyearFraction($settlement, $maturity);
break;
}
$disc = ($redemption - $pr) / ($redemption * $dsm);
return (is_finite($disc) ? $disc: null);
}

/**
* RECEIVED
* Returns the amount received at maturity for a fully invested security.
* 
* investment
* RECEIVED = -----------------------------
* 1 - discount * yearfraction
* 
**/
function RECEIVED($settlement, $maturity, $investment, $discount, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (($investment <= 0) || ($discount <= 0)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual/360
$dsm = $this->Actual360yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUyearFraction($settlement, $maturity);
break;
}
$received = $investment / (1 - $discount * $dsm);
return (is_finite($received) ? $received: null);
}

/**
* INTRATE
* Returns the interest rate for a fully invested security.
* 
* redemption - investment
* INTRATE = ---------------------------
* investment * yearfraction
* 
**/
function INTRATE($settlement, $maturity, $investment, $redemption, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (($investment <= 0) || ($redemption <= 0)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/360
$dsm = $this->Actual360yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUyearFraction($settlement, $maturity);
break;
}
$intrate = ($redemption - $investment) / ($investment * $dsm);
return (is_finite($intrate) ? $intrate: null);
}

/**
* NPV
* Calculates the net present value of an investment by using a
* discount rate and a series of future payments (negative values)
* and income (positive values).
* 
* n / values(i) \
* NPV = SUM | -------------- |
* i=1 | i |
* \ (1 + rate) /
* 
**/
function NPV($rate, $values)
{
if (!is_array($values)) return null;

$npv = 0.0;
for ($i = 0; $i < count($values); $i++)
{
$npv += $values[$i] / pow(1 + $rate, $i + 1);
}
return (is_finite($npv) ? $npv: null);
}

/**
* XNPV
* Returns the net present value for a schedule of cash flows that
* is not necessarily periodic. To calculate the net present value
* for a series of cash flows that is periodic, use the NPV function.
* 
* n / values(i) \
* NPV = SUM | ---------------------------------------- |
* i=1 | ((dates(i) - dates(1)) / 365) |
* \ (1 + rate) /
* 
**/
function XNPV($rate, $values, $dates)
{
if ((!is_array($values)) || (!is_array($dates))) return null;
if (count($values) != count($dates)) return null;

$xnpv = 0.0;
for ($i = 0; $i < count($values); $i++)
{
$xnpv += $values[$i] / pow(1 + $rate, $this->DATEDIFF('day', $dates[0],
$dates[$i]) / 365);
}
return (is_finite($xnpv) ? $xnpv: null);
}

/*
* IRR
* Returns the internal rate of return for a series of cash flows
* represented by the numbers in values. These cash flows do not
* have to be even, as they would be for an annuity. However, the
* cash flows must occur at regular intervals, such as monthly or
* annually. The internal rate of return is the interest rate
* received for an investment consisting of payments (negative
* values) and income (positive values) that occur at regular periods.
* 
*/
function IRR($values, $guess = 0.1)
{
if (!is_array($values)) return null;

// create an initial bracket, with a root somewhere between bot and top
$x1 = 0.0;
$x2 = $guess;
$f1 = $this->NPV($x1, $values);
$f2 = $this->NPV($x2, $values);
for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
if (($f1 * $f2) < 0.0) break;
if (abs($f1) < abs($f2)) {
$f1 = $this->NPV($x1 += 1.6 * ($x1 - $x2), $values);
} else {
$f2 = $this->NPV($x2 += 1.6 * ($x2 - $x1), $values);
}
}
if (($f1 * $f2) > 0.0) return null;

$f = $this->NPV($x1, $values);
if ($f < 0.0) {
$rtb = $x1;
$dx = $x2 - $x1;
} else {
$rtb = $x2;
$dx = $x1 - $x2;
}

for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
$dx *= 0.5;
$x_mid = $rtb + $dx;
$f_mid = $this->NPV($x_mid, $values);
if ($f_mid <= 0.0) $rtb = $x_mid;
if ((abs($f_mid) < FINANCIAL_ACCURACY) || (abs($dx) < FINANCIAL_ACCURACY))
return $x_mid;
}
return null;
}

/*
* MIRR
* Returns the modified internal rate of return for a series
* of periodic cash flows. MIRR considers both the cost of
* the investment and the interest received on reinvestment
* of cash.
* 
**/
function MIRR($values, $finance_rate, $reinvert_rate)
{
$n = count($values);
for ($i = 0, $npv_pos = $npv_neg = 0; $i < $n; $i++) {
$v = $values[$i];
if ($v >= 0)
$npv_pos += $v / pow(1.0 + $reinvert_rate, $i);
else
$npv_neg += $v / pow(1.0 + $finance_rate, $i);
}

if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvert_rate <= -1))
return null;

/*
* I have my doubts about this formula, but it sort of looks like
* the one Microsoft claims to use and it produces the results
* that Excel does. -- MW.
*/
$mirr = pow((-$npv_pos * pow(1 + $reinvert_rate, $n))
/ ($npv_neg * (1 + $reinvert_rate)), (1.0 / ($n - 1))) - 1.0;
return (is_finite($mirr) ? $mirr: null);
}

/*
* XIRR
* Returns the internal rate of return for a schedule of cash flows
* that is not necessarily periodic. To calculate the internal rate
* of return for a series of periodic cash flows, use the IRR function.
* 
* Adapted from routine in Numerical Recipes in C, and translated
* from the Bernt A Oedegaard algorithm in C
* 
**/
function XIRR($values, $dates, $guess = 0.1)
{
if ((!is_array($values)) && (!is_array($dates))) return null;
if (count($values) != count($dates)) return null;

// create an initial bracket, with a root somewhere between bot and top
$x1 = 0.0;
$x2 = $guess;
$f1 = $this->XNPV($x1, $values, $dates);
$f2 = $this->XNPV($x2, $values, $dates);
for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
if (($f1 * $f2) < 0.0) break;
if (abs($f1) < abs($f2)) {
$f1 = $this->XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
} else {
$f2 = $this->XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
}
}
if (($f1 * $f2) > 0.0) return null;

$f = $this->XNPV($x1, $values, $dates);
if ($f < 0.0) {
$rtb = $x1;
$dx = $x2 - $x1;
} else {
$rtb = $x2;
$dx = $x1 - $x2;
}

for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
$dx *= 0.5;
$x_mid = $rtb + $dx;
$f_mid = $this->XNPV($x_mid, $values, $dates);
if ($f_mid <= 0.0) $rtb = $x_mid;
if ((abs($f_mid) < FINANCIAL_ACCURACY) || (abs($dx) < FINANCIAL_ACCURACY))
return $x_mid;
}
return null;
}

/**
* RATE
* 
**/
function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1)
{
$rate = $guess;
$i = 0;
$x0 = 0;
$x1 = $rate;

if (abs($rate) < FINANCIAL_ACCURACY) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}
$y0 = $pv + $pmt * $nper + $fv;
$y1 = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;

// find root by secant method
while ((abs($y0 - $y1) > FINANCIAL_ACCURACY) && ($i <
FINANCIAL_MAX_ITERATIONS))
{
$rate = ($y1 * $x0 - $y0 * $x1) / ($y1 - $y0);
$x0 = $x1;
$x1 = $rate;

if (abs($rate) < FINANCIAL_ACCURACY) {
$y = $pv * (1 + $nper * $rate) + $pmt * (1 + $rate * $type) * $nper + $fv;
} else {
$f = exp($nper * log(1 + $rate));
$y = $pv * $f + $pmt * (1 / $rate + $type) * ($f - 1) + $fv;
}

$y0 = $y1;
$y1 = $y;
$i++;
}
return $rate;
}

/**
* DELTA
* Tests whether two values are equal. Returns 1 if number1 = number2;
returns 0 otherwise.
* Use this function to filter a set of values. For example, by summing
several DELTA functions
* you calculate the count of equal pairs. This function is also known as the
Kronecker Delta function.
*/
function DELTA($number1, $number2 = 0)
{
if (is_nan($number1) || is_nan($number2)) return null;
if ($number1 == $number2) {
return 1;
} else {
return 0;
}
}

/*
* Returns the yield on a security that pays periodic interest.
* Use YIELD to calculate bond yield.
* 
* Settlement: is the security's settlement date. The security
* settlement date is the date after the issue date when the
* security is traded to the buyer.
* Maturity: is the security's maturity date. The maturity date
* is the date when the security expires.
* Rate: is the security's annual coupon rate.
* Pr: is the security's price per $100 face value.
* Redemption: is the security's redemption value per $100 face value.
* Frequency: is the number of coupon payments per year. For annual
* payments, frequency = 1; for semiannual, frequency = 2; for
* quarterly, frequency = 4.
* Basis: is the type of day count basis to use.
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
* 3 Actual/365
* 4 European 30/360
*
*/
function YIELD($settlement, $maturity, $rate, $pr, $redemption, $frequency,
$basis = FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (!$this->_is_valid_frequency($frequency)) return null;
if ($rate < 0) return null;
if (($pr <= 0) || ($redemption <= 0)) return null;
if ($settlement >= $maturity) return null;

// TODO: Not yet implemented
return null;
}

/**
* PRICEDISC
* Returns the price per $100 face value of a discounted security.
**/
function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (($discount <= 0) || ($redemption <= 0)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual/360
$dsm = $this->Actual360yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUyearFraction($settlement, $maturity);
break;
}

return $redemption - $discount * $redemption * $dsm;
}

/**
* YIELDDISC
* Returns the annual yield for a discounted security.
**/
function YIELDDISC($settlement, $maturity, $pr, $redemption, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (($pr <= 0) || ($redemption <= 0)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualyearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual/360
$dsm = $this->Actual360yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUyearFraction($settlement, $maturity);
break;
}

return ($redemption - $pr) / ($pr * $dsm);
}

/**
* COUPNUM
* Returns the number of coupons payable between the settlement
* date and maturity date, rounded up to the nearest whole coupon.
*
*/
function COUPNUM($settlement, $maturity, $frequency, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (!$this->_is_valid_frequency($frequency)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USdayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualdayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual/360
$dsm = $this->Actual360dayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUdayCount($settlement, $maturity);
break;
}

switch ($frequency) {
case 1: // anual payments
return ceil($dsm / 360);
case 2: // semiannual
return ceil($dsm / 180);
case 4: // quarterly
return ceil($dsm / 90);
}
return null;
}

/**
* COUPDAYBS
* Returns the number of days in the coupon period that contains
* the settlement date.
*
*/
function COUPDAYBS($settlement, $maturity, $frequency, $basis =
FINANCIAL_BASIS_MSRB_30_360)
{
if (!$this->_is_valid_basis($basis)) return null;
if (!$this->_is_valid_frequency($frequency)) return null;
if ($settlement >= $maturity) return null;

switch ($basis) {
case FINANCIAL_BASIS_MSRB_30_360: // US(NASD) 30/360
$dsm = $this->Thirty360USdayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_ACT: // Actual/actual
$dsm = $this->ActualActualdayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_360: // Actual/360
$dsm = $this->Actual360dayCount($settlement, $maturity);
break;
case FINANCIAL_BASIS_ACT_365: // Actual/365
$dsm = $this->Actual365yearFraction($settlement, $maturity);
break;
case FINANCIAL_BASIS_30E_360: // European 30/360
$dsm = $this->Thirty360EUdayCount($settlement, $maturity);
break;
}

switch ($frequency) {
case 1: // anual payments
return 365 - ($dsm % 360);
case 2: // semiannual
return 365 - ($dsm % 360);
case 4: // quarterly
return $this->DATEDIFF('day', $this->DATEADD('day', -ceil($dsm / 90) * 90 -
($dsm % 90), $maturity), $settlement);
}
return null;
}
}

?>

-- 
Best Regards

Eng. T. Kaneshalingam, AMIE(SL)
Project Manager,

E-commerce & Content Services
LankaCom Services (Pvt) Ltd
65C, Dharmapala Mawatha,
Colombo 07.
Sri Lanka.
E - kanesh@xxxxxxxxxxxx <mailto:kanesh%40lankacom.net> 
M - +94 777227960
T - +94 112437545
F - +94 112437547
W - www.lankacom.net

---------------------------------
Looking for last minute shopping deals? Find them fast with Yahoo! Search.

[Non-text portions of this message have been removed]
 


[Non-text portions of this message have been removed]


[Index of Archives]     [PHP Home]     [PHP Users]     [PHP Soap]     [Kernel Newbies]     [Yosemite]     [Yosemite Campsites]

  Powered by Linux