/* DEC *BondYield(yield, price, coupon, ppy, mop, dap, yrp, mom, dam, yrm) * * ARGUMENT * DEC *price; * DEC *yield; * DEC *coupon; * int ppy; * int mop, dap, yrp; * int mom, dam, yrm; * * DESCRIPTION * Calculate the yield of a bond given the price, coupon rate * for receiving interest on a bond, number of payments per year, and the * puchase and maturity dates. * * SIDE EFFECTS * None. * * RETURNS * yield if successful, otherwise GM_NULL * * POSSIBLE ERRORS * GM_NULLPOINTER * GM_INIT * GM_ARGVAL * * AUTHOR * Jared Levy * Copyright (C) 1988-1990 Greenleaf Software Inc. All rights reserved. * * MODIFICATIONS * * Mark Nelson * Added one line to convert nominal interest rate to effective. * */ #include #include "gmsystem.h" DEC *BondYield(yield, price, coupon, ppy, mop, dap, yrp, mom, dam, yrm) DEC *price, *yield, *coupon; int ppy, mop, dap, yrp, mom, dam, yrm; { DEC dtemp, *temp=&dtemp, dtemp2, *temp2=&dtemp2; DEC dnper, *nper=&dnper, dpmt, *pmt=&dpmt; DEC dpv, *pv=&dpv, dfv, *fv=&dfv, *p; DEC ddsc, *dsc=&ddsc, ddcs, *dcs=&ddcs; int ndays, npay; _MacStart(GM_BONDYLD); _MacInVarD(coupon); _MacInVarD(price); _MacOutVarD(yield); if (ppy<1||ppy>12) { _MacErr(GM_ARGVAL); _MacRet(GM_NULL); } /* calculate # of periods, including partial period */ ndays = DaysBetweenDates360(mom, dam, yrm, mop, dap, yrp); if (ndays < 0) { if (ndays!=GM_ARGVAL&&ndays!=GM_OVERFLOW) _MacErr(GM_ARGVAL); _MacRet(GM_NULL); } /* calculate number of interest payments remaining */ (void) ConvLongToDecimal(temp, (long)ppy * (long) ndays); (void) ConvLongToDecimal(temp2, 360L); (void) _DivDec80Bit(nper, temp, temp2); (void) _TruncateDec80Bit(temp, nper, 0); npay=temp->dc.sl[0]; (void) _SubDec80Bit(dsc, nper, temp); /* days purchase - next int */ (void) _SubDec80Bit(dcs, &decOne, dsc); /* days last int - purchass */ /* calculate coupon rate per period */ (void) ConvLongToDecimal(temp2, (long)ppy); (void) _DivDec80Bit(pmt, coupon, temp2); (void) _AddDec80Bit(fv, &decHundred, pmt); (void) _MulDec80Bit(temp, pmt, dcs); (void) _AddDec80Bit(pv, price, temp); if (CompareDecimal(nper, &decOne)<=0) { /* < 1 period to maturity */ _DivDec80Bit(temp, fv, pv); _SubDec80Bit(temp, temp, &decOne); _DivDec80Bit(yield, temp, dsc); _MulDec80Bit(yield, yield, &decHundred); _ScaleDec80Bit(yield, yield, wIntrPrec); } else { /* > 1 period to maturity */ _MacDChgs(pv); p = _InterestAux(3, npay, dsc, yield, pv, pmt, fv, GM_BEGIN); if (!p) _MacRet(GM_NULL); } /* * At this point, yield contains the nominal interest rate for the bond. * This needs to be converted to the effective interest rate. Rather than * call the NominalToEffective routine, I import most of the code. */ yield->dc.id += 2; _AddDec80Bit( yield, yield, &decOne ); if (_IntPwrDec80Bit( yield, yield, ppy ) != GM_SUCCESS ) { _MacErr( GM_ARGVAL ); _MacRet( GM_NULL ); } _SubDec80Bit( yield, yield, &decOne ); if (yield->dc.id >= GM_MINID+2) yield->dc.id -= 2; else (void) _MulUnsArrByPwrOf10(yield->dc.sl, 5, 2); if (_Sq5UnsTo4Uns(yield)!=GM_SUCCESS) { _MacErr(GM_ARGVAL); _MacRet(GM_NULL); } _MacRet(yield); }