/** * @return string */ public function getApproxBondYTM() { // we need to calculate the coupon payment C = F*(c/payment frequency) $couponPayment = MathFuncs::mul($this->bondFaceValue, MathFuncs::div($this->bondAnnualCouponRate, $this->bondPaymentFrequency)); // we use a formula to approximate the YTM = (C+(F-P)/n)/((F+P)/2) $approxYTM = MathFuncs::div(MathFuncs::add($couponPayment, MathFuncs::div(MathFuncs::sub($this->bondFaceValue, $this->bondMarketValue), $this->getBondNoOfPayments())), MathFuncs::div(MathFuncs::add($this->bondFaceValue, $this->bondMarketValue), 2)); return $approxYTM; }
/** * @return string */ public function getBondFairValue() { // we need to get the coupon rate per payment period = c/payment frequency $couponRateForPeriod = MathFuncs::div($this->bondAnnualCouponRate, $this->bondPaymentFrequency); // similarly, we need to calculate the VIR per payment period = i/payment frequency $VIRForPeriod = MathFuncs::div($this->bondVIR, $this->bondPaymentFrequency); // we also save the bond's number of payments to an auxillary variable $bondNoOfPayments = $this->getBondNoOfPayments(); // next, we also need the present value of the unit annuity pertaining to the bond, in arrears $PVofUnitBondAnnuity = MathFuncs::div(MathFuncs::sub(1, Mathfuncs::pow(MathFuncs::div(1, MathFuncs::add(1, $VIRForPeriod)), $bondNoOfPayments)), $VIRForPeriod); // now we can use the formula to calculate the real value of the bond (i.e., the present value of its payments) // PV = F*[c*PVofUnitBondAnnuity+1/((1+i)^n)] $fairValue = MathFuncs::mul($this->bondFaceValue, MathFuncs::add(MathFuncs::mul($couponRateForPeriod, $PVofUnitBondAnnuity), MathFuncs::div(1, MathFuncs::pow(MathFuncs::add(1, $VIRForPeriod), $bondNoOfPayments)))); return $fairValue; }
/** * @return string */ public function getDividendRatio() { return MathFuncs::div($this->getEarningsPerStock(), $this->getDividendPerStock()); }
/** * @return string */ public function getInterestAmount() { // n = P*i*t = IN/ID return MathFuncs::div($this->getInterestNumber(), $this->getInterestDivisor()); }
public function testDiv() { $this->assertEquals("2.685", MathFuncs::div(9.27936, 3.456)); }
/** * @return string [Value of a single debt repayment instance as a string] */ public function getDebtSingleRepayment() { // single repayment 'K = PV/((1-v^n)/i)' return MathFuncs::div($this->debtPrincipal, MathFuncs::div(MathFuncs::sub(1, MathFuncs::pow($this->getDebtDiscountFactor(), $this->debtNoOfCompoundingPeriods)), $this->debtInterest)); }
/** * @param array $resultArray */ private function processArray(array $resultArray) { $this->assertEquals("40000", $resultArray["debtPrincipal"]); $this->assertEquals("6", $resultArray["debtNoOfCompoundingPeriods"]); $this->assertEquals(MathFuncs::div($resultArray["debtPeriodLength"]["days"], TimeUtils::getDaysFromYears(1)), $resultArray["debtPeriodLength"]["years"]); $this->assertEquals(MathFuncs::div($resultArray["debtPeriodLength"]["days"], TimeUtils::getDaysFromMonths(1)), $resultArray["debtPeriodLength"]["months"]); $this->assertEquals(MathFuncs::div($resultArray["debtLength"]["days"], TimeUtils::getDaysFromYears(1)), $resultArray["debtLength"]["years"]); $this->assertEquals(MathFuncs::div($resultArray["debtLength"]["days"], TimeUtils::getDaysFromMonths(1)), $resultArray["debtLength"]["months"]); $this->assertEquals("0.12", $resultArray["debtInterest"]); $repayments = $resultArray["debtRepayments"]; $INDIVIDUAL_REPAYMENT = "9729.03"; $this->assertEquals("4929.03", round($repayments[1]["principalAmount"], 2)); $this->assertEquals("4800.00", round($repayments[1]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[1]["totalAmount"], 2)); $this->assertEquals("5520.51", round($repayments[2]["principalAmount"], 2)); $this->assertEquals("4208.52", round($repayments[2]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[2]["totalAmount"], 2)); $this->assertEquals("6182.97", round($repayments[3]["principalAmount"], 2)); $this->assertEquals("3546.06", round($repayments[3]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[3]["totalAmount"], 2)); $this->assertEquals("6924.93", round($repayments[4]["principalAmount"], 2)); $this->assertEquals("2804.10", round($repayments[4]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[4]["totalAmount"], 2)); $this->assertEquals("7755.92", round($repayments[5]["principalAmount"], 2)); $this->assertEquals("1973.11", round($repayments[5]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[5]["totalAmount"], 2)); $this->assertEquals("8686.63", round($repayments[6]["principalAmount"], 2)); $this->assertEquals("1042.4", round($repayments[6]["interestAmount"], 2)); $this->assertEquals($INDIVIDUAL_REPAYMENT, round($repayments[6]["totalAmount"], 2)); }
/** * @param AnnuityPaymentTypes $annuityPaymentType * @param AnnuityValueTypes $annuityValueType * @return null|string * @throws Exception */ public function getAnnuityValue(AnnuityPaymentTypes $annuityPaymentType = null, AnnuityValueTypes $annuityValueType) { // if the number of the annuity's compounding periods // is set to zero, we're dealing with a perpetuity if (Helpers::checkIfZero($this->annuityNoOfCompoundingPeriods)) { // we cannot calculate FV of a perpetuity, we therefore return null // in case such a value is demanded if ($annuityValueType->getValue() == AnnuityValueTypes::FUTURE_VALUE) { return null; } // PV of a perpetuity = K/i return Helpers::roundMoneyForDisplay(MathFuncs::div($this->annuitySinglePaymentAmount, $this->annuityInterest)); } // when the annuity is not a perpetuity, we first need to check that // the $annuityPaymentType is not null if (Helpers::checkIfNotNull($annuityPaymentType)) { // discount factor 'v = 1/(1+i)' $discountFactor = MathFuncs::div(1, MathFuncs::add(1, $this->annuityInterest)); if ($annuityValueType->getValue() == AnnuityValueTypes::PRESENT_VALUE) { // PV numerator = 1-v^n $numerator = MathFuncs::sub(1, MathFuncs::pow($discountFactor, $this->annuityNoOfCompoundingPeriods)); } elseif ($annuityValueType->getValue() == AnnuityValueTypes::FUTURE_VALUE) { // FV numerator = (1+i)^n-1 $numerator = MathFuncs::sub(MathFuncs::pow(MathFuncs::add(1, $this->annuityInterest), $this->annuityNoOfCompoundingPeriods), 1); } if ($annuityPaymentType->getValue() == AnnuityPaymentTypes::IN_ADVANCE) { // in advance denom. = 1-v $denominator = MathFuncs::sub(1, $discountFactor); } elseif ($annuityPaymentType->getValue() == AnnuityPaymentTypes::IN_ARREARS) { // in arrears denom. = i $denominator = $this->annuityInterest; } if (isset($numerator) && isset($denominator)) { return MathFuncs::mul(MathFuncs::div($numerator, $denominator), $this->annuitySinglePaymentAmount); } } return null; }
/** * @return mixed * @throws Exception */ public static function getCurrentDayCountConvention() { $dayCountConventionIdentifier = Config::getConfigField('day_count_convention'); $availableDayCountConventions = Config::getConfigField('available_day_count_conventions'); if (is_array($availableDayCountConventions) && array_key_exists($dayCountConventionIdentifier, $availableDayCountConventions)) { $dayCountConvention = $availableDayCountConventions[$dayCountConventionIdentifier]; if (self::isDayCountConventionValid($dayCountConvention)) { $dayCountConvention['days_in_a_month'] = MathFuncs::div($dayCountConvention['days_in_a_year'], 12); return $dayCountConvention; } } throw new Exception(ErrorMessages::getDayCountConventionNotDefinedMessage()); }
/** * @return string * @throws Exception */ public function toMonths() { return MathFuncs::div($this->toDays(), TimeUtils::getCurrentDayCountConvention()['days_in_a_month']); }
/** * @return string */ public function getBondDuration() { // duration of the bond = sum of auxiliary values of all periods / bond present value // auxiliary value for a period = discounted cash flow in the period * number of the period $auxiliaryValue = 0; $i = 1; foreach ($this->getBondDiscountedCashFlows() as $discountedCashFlowEntry) { $auxiliaryValue = MathFuncs::add($auxiliaryValue, MathFuncs::mul($discountedCashFlowEntry, $i++)); } $duration = MathFuncs::div($auxiliaryValue, $this->getBondPresentValue()); return $duration; }
/** * @return string * @throws Exception */ public function getStockPresentValue() { switch ($this->dividendDiscountModelType->getValue()) { case StockDDMTypes::ZERO_GROWTH: // PV = D/i return MathFuncs::div($this->stockAnnualDividendsValue, $this->stockVIR); case StockDDMTypes::MULTIPLE_GROWTH: if ($this->stockAnnualDividendsGrowth === null) { throw new Exception(Strings::getString('message_must_set_growth_value')); } // PV = (D*(1+g))/(i-g) return MathFuncs::mul($this->stockAnnualDividendsValue, MathFuncs::div(MathFuncs::add(1, $this->stockAnnualDividendsGrowth), MathFuncs::sub($this->stockVIR, $this->stockAnnualDividendsGrowth))); } }