| 47 | | } |
|---|
| 48 | | |
|---|
| 49 | | [TestMethod()] |
|---|
| 50 | | public void testYield() { |
|---|
| 51 | | |
|---|
| 52 | | //"Testing consistency of bond price/yield calculation..."); |
|---|
| 53 | | |
|---|
| 54 | | CommonVars vars = new CommonVars(); |
|---|
| 55 | | |
|---|
| 56 | | double tolerance = 1.0e-7; |
|---|
| 57 | | int maxEvaluations = 100; |
|---|
| 58 | | |
|---|
| 59 | | int[] issueMonths = new int[] { -24, -18, -12, -6, 0, 6, 12, 18, 24 }; |
|---|
| 60 | | int[] lengths = new int[] { 3, 5, 10, 15, 20 }; |
|---|
| 61 | | int settlementDays = 3; |
|---|
| 62 | | double[] coupons = new double[] { 0.02, 0.05, 0.08 }; |
|---|
| 63 | | Frequency[] frequencies = new Frequency[] { Frequency.Semiannual, Frequency.Annual }; |
|---|
| 64 | | DayCounter bondDayCount = new Thirty360(); |
|---|
| 65 | | BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted; |
|---|
| 66 | | BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing; |
|---|
| 67 | | double redemption = 100.0; |
|---|
| 68 | | |
|---|
| 69 | | double[] yields = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; |
|---|
| 70 | | Compounding[] compounding = new Compounding[] { Compounding.Compounded, Compounding.Continuous }; |
|---|
| 71 | | |
|---|
| 72 | | for (int i=0; i<issueMonths.Length; i++) { |
|---|
| 73 | | for (int j=0; j<lengths.Length; j++) { |
|---|
| 74 | | for (int k=0; k<coupons.Length; k++) { |
|---|
| 75 | | for (int l=0; l<frequencies.Length; l++) { |
|---|
| 76 | | for (int n=0; n<compounding.Length; n++) { |
|---|
| 77 | | |
|---|
| 78 | | Date dated = vars.calendar.advance(vars.today, issueMonths[i], TimeUnit.Months); |
|---|
| 79 | | Date issue = dated; |
|---|
| 80 | | Date maturity = vars.calendar.advance(issue, lengths[j], TimeUnit.Years); |
|---|
| 81 | | |
|---|
| 82 | | Schedule sch = new Schedule(dated, maturity, new Period(frequencies[l]), vars.calendar, |
|---|
| 83 | | accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); |
|---|
| 84 | | |
|---|
| 85 | | FixedRateBond bond = new FixedRateBond(settlementDays, vars.faceAmount, sch, |
|---|
| 86 | | new List<double>() { coupons[k] }, |
|---|
| 87 | | bondDayCount, paymentConvention, |
|---|
| 88 | | redemption, issue); |
|---|
| 89 | | |
|---|
| 90 | | for (int m=0; m<yields.Length; m++) { |
|---|
| 91 | | |
|---|
| 92 | | double price = bond.cleanPrice(yields[m], bondDayCount, compounding[n], frequencies[l]); |
|---|
| 93 | | double calculated = bond.yield(price, bondDayCount, compounding[n], frequencies[l], null, |
|---|
| 94 | | tolerance, maxEvaluations); |
|---|
| 95 | | |
|---|
| 96 | | if (Math.Abs(yields[m]-calculated) > tolerance) { |
|---|
| 97 | | // the difference might not matter |
|---|
| 98 | | double price2 = bond.cleanPrice(calculated, bondDayCount, compounding[n], frequencies[l]); |
|---|
| 99 | | if (Math.Abs(price-price2)/price > tolerance) { |
|---|
| 100 | | Assert.Fail("yield recalculation failed:\n" |
|---|
| 101 | | + " issue: " + issue + "\n" |
|---|
| 102 | | + " maturity: " + maturity + "\n" |
|---|
| 103 | | + " coupon: " + coupons[k] + "\n" |
|---|
| 104 | | + " frequency: " + frequencies[l] + "\n\n" |
|---|
| 105 | | + " yield: " + yields[m] + " " |
|---|
| 106 | | + (compounding[n] == Compounding.Compounded ? "compounded" : "continuous") + "\n" |
|---|
| 107 | | + " price: " + price + "\n" |
|---|
| 108 | | + " yield': " + calculated + "\n" |
|---|
| 109 | | + " price': " + price2); |
|---|
| 110 | | } |
|---|
| 111 | | } |
|---|
| 112 | | } |
|---|
| 113 | | } |
|---|
| | 130 | } |
|---|
| | 131 | } |
|---|
| | 132 | [TestMethod()] |
|---|
| | 133 | public void testTheoretical() |
|---|
| | 134 | { |
|---|
| | 135 | // "Testing theoretical bond price/yield calculation..."); |
|---|
| | 136 | |
|---|
| | 137 | CommonVars vars = new CommonVars(); |
|---|
| | 138 | |
|---|
| | 139 | double tolerance = 1.0e-7; |
|---|
| | 140 | int maxEvaluations = 100; |
|---|
| | 141 | |
|---|
| | 142 | int[] lengths = new int[] { 3, 5, 10, 15, 20 }; |
|---|
| | 143 | int settlementDays = 3; |
|---|
| | 144 | double[] coupons = new double[] { 0.02, 0.05, 0.08 }; |
|---|
| | 145 | Frequency[] frequencies = new Frequency[] { Frequency.Semiannual, Frequency.Annual }; |
|---|
| | 146 | DayCounter bondDayCount = new Actual360(); |
|---|
| | 147 | BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted; |
|---|
| | 148 | BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing; |
|---|
| | 149 | double redemption = 100.0; |
|---|
| | 150 | |
|---|
| | 151 | double[] yields = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; |
|---|
| | 152 | |
|---|
| | 153 | for (int j = 0; j < lengths.Length; j++) |
|---|
| | 154 | { |
|---|
| | 155 | for (int k = 0; k < coupons.Length; k++) |
|---|
| | 156 | { |
|---|
| | 157 | for (int l = 0; l < frequencies.Length; l++) |
|---|
| | 158 | { |
|---|
| | 159 | |
|---|
| | 160 | Date dated = vars.today; |
|---|
| | 161 | Date issue = dated; |
|---|
| | 162 | Date maturity = vars.calendar.advance(issue, lengths[j], TimeUnit.Years); |
|---|
| | 163 | |
|---|
| | 164 | SimpleQuote rate = new SimpleQuote(0.0); |
|---|
| | 165 | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(vars.today, rate, bondDayCount)); |
|---|
| | 166 | |
|---|
| | 167 | Schedule sch = new Schedule(dated, maturity, new Period(frequencies[l]), vars.calendar, |
|---|
| | 168 | accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); |
|---|
| | 169 | |
|---|
| | 170 | FixedRateBond bond = new FixedRateBond(settlementDays, vars.faceAmount, sch, new List<double>() { coupons[k] }, |
|---|
| | 171 | bondDayCount, paymentConvention, redemption, issue); |
|---|
| | 172 | |
|---|
| | 173 | IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); |
|---|
| | 174 | bond.setPricingEngine(bondEngine); |
|---|
| | 175 | |
|---|
| | 176 | for (int m = 0; m < yields.Length; m++) |
|---|
| | 177 | { |
|---|
| | 178 | |
|---|
| | 179 | rate.setValue(yields[m]); |
|---|
| | 180 | |
|---|
| | 181 | double price = bond.cleanPrice(yields[m], bondDayCount, Compounding.Continuous, frequencies[l]); |
|---|
| | 182 | double calculatedPrice = bond.cleanPrice(); |
|---|
| | 183 | |
|---|
| | 184 | if (Math.Abs(price - calculatedPrice) > tolerance) |
|---|
| | 185 | { |
|---|
| | 186 | Assert.Fail("price calculation failed:" |
|---|
| | 187 | + "\n issue: " + issue |
|---|
| | 188 | + "\n maturity: " + maturity |
|---|
| | 189 | + "\n coupon: " + coupons[k] |
|---|
| | 190 | + "\n frequency: " + frequencies[l] + "\n" |
|---|
| | 191 | + "\n yield: " + yields[m] |
|---|
| | 192 | + "\n expected: " + price |
|---|
| | 193 | + "\n calculated': " + calculatedPrice |
|---|
| | 194 | + "\n error': " + (price - calculatedPrice)); |
|---|
| | 195 | } |
|---|
| | 196 | |
|---|
| | 197 | double calculatedYield = bond.yield(bondDayCount, Compounding.Continuous, frequencies[l], |
|---|
| | 198 | tolerance, maxEvaluations); |
|---|
| | 199 | if (Math.Abs(yields[m] - calculatedYield) > tolerance) |
|---|
| | 200 | { |
|---|
| | 201 | Assert.Fail("yield calculation failed:" |
|---|
| | 202 | + "\n issue: " + issue |
|---|
| | 203 | + "\n maturity: " + maturity |
|---|
| | 204 | + "\n coupon: " + coupons[k] |
|---|
| | 205 | + "\n frequency: " + frequencies[l] + "\n" |
|---|
| | 206 | + "\n yield: " + yields[m] |
|---|
| | 207 | + "\n price: " + price |
|---|
| | 208 | + "\n yield': " + calculatedYield); |
|---|
| | 209 | } |
|---|
| 118 | | } |
|---|
| 119 | | [TestMethod()] |
|---|
| 120 | | public void testTheoretical() { |
|---|
| 121 | | // "Testing theoretical bond price/yield calculation..."); |
|---|
| 122 | | |
|---|
| 123 | | CommonVars vars = new CommonVars(); |
|---|
| 124 | | |
|---|
| 125 | | double tolerance = 1.0e-7; |
|---|
| 126 | | int maxEvaluations = 100; |
|---|
| 127 | | |
|---|
| 128 | | int[] lengths = new int[] { 3, 5, 10, 15, 20 }; |
|---|
| 129 | | int settlementDays = 3; |
|---|
| 130 | | double[] coupons = new double[] { 0.02, 0.05, 0.08 }; |
|---|
| 131 | | Frequency[] frequencies = new Frequency[] { Frequency.Semiannual, Frequency.Annual }; |
|---|
| 132 | | DayCounter bondDayCount = new Actual360(); |
|---|
| 133 | | BusinessDayConvention accrualConvention = BusinessDayConvention.Unadjusted; |
|---|
| 134 | | BusinessDayConvention paymentConvention = BusinessDayConvention.ModifiedFollowing; |
|---|
| 135 | | double redemption = 100.0; |
|---|
| 136 | | |
|---|
| 137 | | double[] yields = new double[] { 0.03, 0.04, 0.05, 0.06, 0.07 }; |
|---|
| 138 | | |
|---|
| 139 | | for (int j=0; j<lengths.Length; j++) { |
|---|
| 140 | | for (int k=0; k<coupons.Length; k++) { |
|---|
| 141 | | for (int l=0; l<frequencies.Length; l++) { |
|---|
| 142 | | |
|---|
| 143 | | Date dated = vars.today; |
|---|
| 144 | | Date issue = dated; |
|---|
| 145 | | Date maturity = vars.calendar.advance(issue, lengths[j], TimeUnit.Years); |
|---|
| 146 | | |
|---|
| 147 | | SimpleQuote rate = new SimpleQuote(0.0); |
|---|
| 148 | | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(vars.today, rate, bondDayCount)); |
|---|
| 149 | | |
|---|
| 150 | | Schedule sch = new Schedule(dated, maturity, new Period(frequencies[l]), vars.calendar, |
|---|
| 151 | | accrualConvention, accrualConvention, DateGeneration.Rule.Backward, false); |
|---|
| 152 | | |
|---|
| 153 | | FixedRateBond bond = new FixedRateBond(settlementDays, vars.faceAmount, sch, new List<double>() { coupons[k] }, |
|---|
| 154 | | bondDayCount, paymentConvention, redemption, issue); |
|---|
| 155 | | |
|---|
| 156 | | IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); |
|---|
| 157 | | bond.setPricingEngine(bondEngine); |
|---|
| 158 | | |
|---|
| 159 | | for (int m=0; m<yields.Length; m++) { |
|---|
| 160 | | |
|---|
| 161 | | rate.setValue(yields[m]); |
|---|
| 162 | | |
|---|
| 163 | | double price = bond.cleanPrice(yields[m], bondDayCount, Compounding.Continuous, frequencies[l]); |
|---|
| 164 | | double calculatedPrice = bond.cleanPrice(); |
|---|
| 165 | | |
|---|
| 166 | | if (Math.Abs(price-calculatedPrice) > tolerance) { |
|---|
| 167 | | Assert.Fail("price calculation failed:" |
|---|
| 168 | | + "\n issue: " + issue |
|---|
| 169 | | + "\n maturity: " + maturity |
|---|
| 170 | | + "\n coupon: " + coupons[k] |
|---|
| 171 | | + "\n frequency: " + frequencies[l] + "\n" |
|---|
| 172 | | + "\n yield: " + yields[m] |
|---|
| 173 | | + "\n expected: " + price |
|---|
| 174 | | + "\n calculated': " + calculatedPrice |
|---|
| 175 | | + "\n error': " + (price-calculatedPrice)); |
|---|
| 176 | | } |
|---|
| 177 | | |
|---|
| 178 | | double calculatedYield = bond.yield(bondDayCount, Compounding.Continuous, frequencies[l], |
|---|
| 179 | | tolerance, maxEvaluations); |
|---|
| 180 | | if (Math.Abs(yields[m]-calculatedYield) > tolerance) { |
|---|
| 181 | | Assert.Fail("yield calculation failed:" |
|---|
| 182 | | + "\n issue: " + issue |
|---|
| 183 | | + "\n maturity: " + maturity |
|---|
| 184 | | + "\n coupon: " + coupons[k] |
|---|
| 185 | | + "\n frequency: " + frequencies[l] + "\n" |
|---|
| 186 | | + "\n yield: " + yields[m] |
|---|
| 187 | | + "\n price: " + price |
|---|
| 188 | | + "\n yield': " + calculatedYield); |
|---|
| 189 | | } |
|---|
| 190 | | } |
|---|
| 191 | | } |
|---|
| 192 | | } |
|---|
| | 213 | } |
|---|
| | 214 | } |
|---|
| | 215 | [TestMethod()] |
|---|
| | 216 | public void testCached() |
|---|
| | 217 | { |
|---|
| | 218 | // ("Testing bond price/yield calculation against cached values..."); |
|---|
| | 219 | |
|---|
| | 220 | CommonVars vars = new CommonVars(); |
|---|
| | 221 | |
|---|
| | 222 | // with implicit settlement calculation: |
|---|
| | 223 | Date today = new Date(22, Month.November, 2004); |
|---|
| | 224 | Settings.setEvaluationDate(today); |
|---|
| | 225 | |
|---|
| | 226 | Calendar bondCalendar = new NullCalendar(); |
|---|
| | 227 | DayCounter bondDayCount = new ActualActual(ActualActual.Convention.ISMA); |
|---|
| | 228 | int settlementDays = 1; |
|---|
| | 229 | |
|---|
| | 230 | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, new SimpleQuote(0.03), new Actual360())); |
|---|
| | 231 | |
|---|
| | 232 | // actual market values from the evaluation date |
|---|
| | 233 | Frequency freq = Frequency.Semiannual; |
|---|
| | 234 | Schedule sch1 = new Schedule(new Date(31, Month.October, 2004), new Date(31, Month.October, 2006), new Period(freq), |
|---|
| | 235 | bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, |
|---|
| | 236 | DateGeneration.Rule.Backward, false); |
|---|
| | 237 | |
|---|
| | 238 | FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch1, new List<double>() { 0.025 }, |
|---|
| | 239 | bondDayCount, BusinessDayConvention.ModifiedFollowing, 100.0, new Date(1, Month.November, 2004)); |
|---|
| | 240 | |
|---|
| | 241 | IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); |
|---|
| | 242 | bond1.setPricingEngine(bondEngine); |
|---|
| | 243 | |
|---|
| | 244 | double marketPrice1 = 99.203125; |
|---|
| | 245 | double marketYield1 = 0.02925; |
|---|
| | 246 | |
|---|
| | 247 | Schedule sch2 = new Schedule(new Date(15, Month.November, 2004), new Date(15, Month.November, 2009), new Period(freq), |
|---|
| | 248 | bondCalendar, BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, |
|---|
| | 249 | DateGeneration.Rule.Backward, false); |
|---|
| | 250 | |
|---|
| | 251 | FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch2, new List<double>() { 0.035 }, |
|---|
| | 252 | bondDayCount, BusinessDayConvention.ModifiedFollowing, |
|---|
| | 253 | 100.0, new Date(15, Month.November, 2004)); |
|---|
| | 254 | |
|---|
| | 255 | bond2.setPricingEngine(bondEngine); |
|---|
| | 256 | |
|---|
| | 257 | double marketPrice2 = 99.6875; |
|---|
| | 258 | double marketYield2 = 0.03569; |
|---|
| | 259 | |
|---|
| | 260 | // calculated values |
|---|
| | 261 | double cachedPrice1a = 99.204505, cachedPrice2a = 99.687192; |
|---|
| | 262 | double cachedPrice1b = 98.943393, cachedPrice2b = 101.986794; |
|---|
| | 263 | double cachedYield1a = 0.029257, cachedYield2a = 0.035689; |
|---|
| | 264 | double cachedYield1b = 0.029045, cachedYield2b = 0.035375; |
|---|
| | 265 | double cachedYield1c = 0.030423, cachedYield2c = 0.030432; |
|---|
| | 266 | |
|---|
| | 267 | // check |
|---|
| | 268 | double tolerance = 1.0e-6; |
|---|
| | 269 | double price, yield; |
|---|
| | 270 | |
|---|
| | 271 | price = bond1.cleanPrice(marketYield1, bondDayCount, Compounding.Compounded, freq); |
|---|
| | 272 | if (Math.Abs(price - cachedPrice1a) > tolerance) |
|---|
| | 273 | { |
|---|
| | 274 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 275 | + "\n calculated: " + price |
|---|
| | 276 | + "\n expected: " + cachedPrice1a |
|---|
| | 277 | + "\n tolerance: " + tolerance |
|---|
| | 278 | + "\n error: " + (price - cachedPrice1a)); |
|---|
| | 279 | } |
|---|
| | 280 | |
|---|
| | 281 | price = bond1.cleanPrice(); |
|---|
| | 282 | if (Math.Abs(price - cachedPrice1b) > tolerance) |
|---|
| | 283 | { |
|---|
| | 284 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 285 | + "\n calculated: " + price |
|---|
| | 286 | + "\n expected: " + cachedPrice1b |
|---|
| | 287 | + "\n tolerance: " + tolerance |
|---|
| | 288 | + "\n error: " + (price - cachedPrice1b)); |
|---|
| | 289 | } |
|---|
| | 290 | |
|---|
| | 291 | yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Compounded, freq); |
|---|
| | 292 | if (Math.Abs(yield - cachedYield1a) > tolerance) |
|---|
| | 293 | { |
|---|
| | 294 | Assert.Fail("failed to reproduce cached compounded yield:" |
|---|
| | 295 | + "\n calculated: " + yield |
|---|
| | 296 | + "\n expected: " + cachedYield1a |
|---|
| | 297 | + "\n tolerance: " + tolerance |
|---|
| | 298 | + "\n error: " + (yield - cachedYield1a)); |
|---|
| | 299 | } |
|---|
| | 300 | |
|---|
| | 301 | yield = bond1.yield(marketPrice1, bondDayCount, Compounding.Continuous, freq); |
|---|
| | 302 | if (Math.Abs(yield - cachedYield1b) > tolerance) |
|---|
| | 303 | { |
|---|
| | 304 | Assert.Fail("failed to reproduce cached continuous yield:" |
|---|
| | 305 | + "\n calculated: " + yield |
|---|
| | 306 | + "\n expected: " + cachedYield1b |
|---|
| | 307 | + "\n tolerance: " + tolerance |
|---|
| | 308 | + "\n error: " + (yield - cachedYield1b)); |
|---|
| | 309 | } |
|---|
| | 310 | |
|---|
| | 311 | yield = bond1.yield(bondDayCount, Compounding.Continuous, freq); |
|---|
| | 312 | if (Math.Abs(yield - cachedYield1c) > tolerance) |
|---|
| | 313 | { |
|---|
| | 314 | Assert.Fail("failed to reproduce cached continuous yield:" |
|---|
| | 315 | + "\n calculated: " + yield |
|---|
| | 316 | + "\n expected: " + cachedYield1c |
|---|
| | 317 | + "\n tolerance: " + tolerance |
|---|
| | 318 | + "\n error: " + (yield - cachedYield1c)); |
|---|
| | 319 | } |
|---|
| | 320 | |
|---|
| | 321 | |
|---|
| | 322 | price = bond2.cleanPrice(marketYield2, bondDayCount, Compounding.Compounded, freq); |
|---|
| | 323 | if (Math.Abs(price - cachedPrice2a) > tolerance) |
|---|
| | 324 | { |
|---|
| | 325 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 326 | + "\n calculated: " + price |
|---|
| | 327 | + "\n expected: " + cachedPrice2a |
|---|
| | 328 | + "\n tolerance: " + tolerance |
|---|
| | 329 | + "\n error: " + (price - cachedPrice2a)); |
|---|
| | 330 | } |
|---|
| | 331 | |
|---|
| | 332 | price = bond2.cleanPrice(); |
|---|
| | 333 | if (Math.Abs(price - cachedPrice2b) > tolerance) |
|---|
| | 334 | { |
|---|
| | 335 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 336 | + "\n calculated: " + price |
|---|
| | 337 | + "\n expected: " + cachedPrice2b |
|---|
| | 338 | + "\n tolerance: " + tolerance |
|---|
| | 339 | + "\n error: " + (price - cachedPrice2b)); |
|---|
| | 340 | } |
|---|
| | 341 | |
|---|
| | 342 | yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Compounded, freq); |
|---|
| | 343 | if (Math.Abs(yield - cachedYield2a) > tolerance) |
|---|
| | 344 | { |
|---|
| | 345 | Assert.Fail("failed to reproduce cached compounded yield:" |
|---|
| | 346 | + "\n calculated: " + yield |
|---|
| | 347 | + "\n expected: " + cachedYield2a |
|---|
| | 348 | + "\n tolerance: " + tolerance |
|---|
| | 349 | + "\n error: " + (yield - cachedYield2a)); |
|---|
| | 350 | } |
|---|
| | 351 | |
|---|
| | 352 | yield = bond2.yield(marketPrice2, bondDayCount, Compounding.Continuous, freq); |
|---|
| | 353 | if (Math.Abs(yield - cachedYield2b) > tolerance) |
|---|
| | 354 | { |
|---|
| | 355 | Assert.Fail("failed to reproduce cached continuous yield:" |
|---|
| | 356 | + "\n calculated: " + yield |
|---|
| | 357 | + "\n expected: " + cachedYield2b |
|---|
| | 358 | + "\n tolerance: " + tolerance |
|---|
| | 359 | + "\n error: " + (yield - cachedYield2b)); |
|---|
| | 360 | } |
|---|
| | 361 | |
|---|
| | 362 | yield = bond2.yield(bondDayCount, Compounding.Continuous, freq); |
|---|
| | 363 | if (Math.Abs(yield - cachedYield2c) > tolerance) |
|---|
| | 364 | { |
|---|
| | 365 | Assert.Fail("failed to reproduce cached continuous yield:" |
|---|
| | 366 | + "\n calculated: " + yield |
|---|
| | 367 | + "\n expected: " + cachedYield2c |
|---|
| | 368 | + "\n tolerance: " + tolerance |
|---|
| | 369 | + "\n error: " + (yield - cachedYield2c)); |
|---|
| | 370 | } |
|---|
| | 371 | |
|---|
| | 372 | // with explicit settlement date: |
|---|
| | 373 | Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2006), new Period(freq), |
|---|
| | 374 | new UnitedStates(UnitedStates.Market.GovernmentBond), BusinessDayConvention.Unadjusted, |
|---|
| | 375 | BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); |
|---|
| | 376 | |
|---|
| | 377 | FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, new List<double>() { 0.02875 }, |
|---|
| | 378 | new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 379 | BusinessDayConvention.ModifiedFollowing, 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 380 | |
|---|
| | 381 | bond3.setPricingEngine(bondEngine); |
|---|
| | 382 | |
|---|
| | 383 | double marketYield3 = 0.02997; |
|---|
| | 384 | |
|---|
| | 385 | Date settlementDate = new Date(30, Month.November, 2004); |
|---|
| | 386 | double cachedPrice3 = 99.764874; |
|---|
| | 387 | |
|---|
| | 388 | price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq, settlementDate); |
|---|
| | 389 | if (Math.Abs(price - cachedPrice3) > tolerance) |
|---|
| | 390 | { |
|---|
| | 391 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 392 | + "\n calculated: " + price + "" |
|---|
| | 393 | + "\n expected: " + cachedPrice3 + "" |
|---|
| | 394 | + "\n error: " + (price - cachedPrice3)); |
|---|
| | 395 | } |
|---|
| | 396 | |
|---|
| | 397 | // this should give the same result since the issue date is the |
|---|
| | 398 | // earliest possible settlement date |
|---|
| | 399 | Settings.setEvaluationDate(new Date(22, Month.November, 2004)); |
|---|
| | 400 | |
|---|
| | 401 | price = bond3.cleanPrice(marketYield3, bondDayCount, Compounding.Compounded, freq); |
|---|
| | 402 | if (Math.Abs(price - cachedPrice3) > tolerance) |
|---|
| | 403 | { |
|---|
| | 404 | Assert.Fail("failed to reproduce cached price:" |
|---|
| | 405 | + "\n calculated: " + price + "" |
|---|
| | 406 | + "\n expected: " + cachedPrice3 + "" |
|---|
| | 407 | + "\n error: " + (price - cachedPrice3)); |
|---|
| | 408 | } |
|---|
| | 409 | } |
|---|
| | 410 | [TestMethod()] |
|---|
| | 411 | public void testCachedZero() |
|---|
| | 412 | { |
|---|
| | 413 | Console.WriteLine("Testing zero-coupon bond prices against cached values..."); |
|---|
| | 414 | |
|---|
| | 415 | CommonVars vars = new CommonVars(); |
|---|
| | 416 | |
|---|
| | 417 | Date today = new Date(22, Month.November, 2004); |
|---|
| | 418 | Settings.setEvaluationDate(today); |
|---|
| | 419 | |
|---|
| | 420 | int settlementDays = 1; |
|---|
| | 421 | |
|---|
| | 422 | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); |
|---|
| | 423 | |
|---|
| | 424 | double tolerance = 1.0e-6; |
|---|
| | 425 | |
|---|
| | 426 | // plain |
|---|
| | 427 | ZeroCouponBond bond1 = new ZeroCouponBond(settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 428 | vars.faceAmount, new Date(30, Month.November, 2008), BusinessDayConvention.ModifiedFollowing, |
|---|
| | 429 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 430 | |
|---|
| | 431 | IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); |
|---|
| | 432 | bond1.setPricingEngine(bondEngine); |
|---|
| | 433 | |
|---|
| | 434 | double cachedPrice1 = 88.551726; |
|---|
| | 435 | |
|---|
| | 436 | double price = bond1.cleanPrice(); |
|---|
| | 437 | if (Math.Abs(price - cachedPrice1) > tolerance) |
|---|
| | 438 | { |
|---|
| | 439 | Console.WriteLine("failed to reproduce cached price:\n" |
|---|
| | 440 | + " calculated: " + price + "\n" |
|---|
| | 441 | + " expected: " + cachedPrice1 + "\n" |
|---|
| | 442 | + " error: " + (price - cachedPrice1)); |
|---|
| | 443 | } |
|---|
| | 444 | |
|---|
| | 445 | ZeroCouponBond bond2 = new ZeroCouponBond(settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 446 | vars.faceAmount, new Date(30, Month.November, 2007), BusinessDayConvention.ModifiedFollowing, |
|---|
| | 447 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 448 | |
|---|
| | 449 | bond2.setPricingEngine(bondEngine); |
|---|
| | 450 | |
|---|
| | 451 | double cachedPrice2 = 91.278949; |
|---|
| | 452 | |
|---|
| | 453 | price = bond2.cleanPrice(); |
|---|
| | 454 | if (Math.Abs(price - cachedPrice2) > tolerance) |
|---|
| | 455 | { |
|---|
| | 456 | Console.WriteLine("failed to reproduce cached price:\n" |
|---|
| | 457 | + " calculated: " + price + "\n" |
|---|
| | 458 | + " expected: " + cachedPrice2 + "\n" |
|---|
| | 459 | + " error: " + (price - cachedPrice2)); |
|---|
| | 460 | } |
|---|
| | 461 | |
|---|
| | 462 | ZeroCouponBond bond3 = new ZeroCouponBond(settlementDays, new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 463 | vars.faceAmount, new Date(30, Month.November, 2006), BusinessDayConvention.ModifiedFollowing, |
|---|
| | 464 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 465 | |
|---|
| | 466 | bond3.setPricingEngine(bondEngine); |
|---|
| | 467 | |
|---|
| | 468 | double cachedPrice3 = 94.098006; |
|---|
| | 469 | |
|---|
| | 470 | price = bond3.cleanPrice(); |
|---|
| | 471 | if (Math.Abs(price - cachedPrice3) > tolerance) |
|---|
| | 472 | { |
|---|
| | 473 | Console.WriteLine("failed to reproduce cached price:\n" |
|---|
| | 474 | + " calculated: " + price + "\n" |
|---|
| | 475 | + " expected: " + cachedPrice3 + "\n" |
|---|
| | 476 | + " error: " + (price - cachedPrice3)); |
|---|
| | 477 | } |
|---|
| | 478 | } |
|---|
| | 479 | [TestMethod()] |
|---|
| | 480 | public void testCachedFixed() |
|---|
| | 481 | { |
|---|
| | 482 | // "Testing fixed-coupon bond prices against cached values..."); |
|---|
| | 483 | |
|---|
| | 484 | CommonVars vars = new CommonVars(); |
|---|
| | 485 | |
|---|
| | 486 | Date today = new Date(22, Month.November, 2004); |
|---|
| | 487 | Settings.setEvaluationDate(today); |
|---|
| | 488 | |
|---|
| | 489 | int settlementDays = 1; |
|---|
| | 490 | |
|---|
| | 491 | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); |
|---|
| | 492 | |
|---|
| | 493 | double tolerance = 1.0e-6; |
|---|
| | 494 | |
|---|
| | 495 | // plain |
|---|
| | 496 | Schedule sch = new Schedule(new Date(30, Month.November, 2004), |
|---|
| | 497 | new Date(30, Month.November, 2008), new Period(Frequency.Semiannual), |
|---|
| | 498 | new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 499 | BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false); |
|---|
| | 500 | |
|---|
| | 501 | FixedRateBond bond1 = new FixedRateBond(settlementDays, vars.faceAmount, sch, new List<double>() { 0.02875 }, |
|---|
| | 502 | new ActualActual(ActualActual.Convention.ISMA), BusinessDayConvention.ModifiedFollowing, |
|---|
| | 503 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 504 | |
|---|
| | 505 | IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve); |
|---|
| | 506 | bond1.setPricingEngine(bondEngine); |
|---|
| | 507 | |
|---|
| | 508 | double cachedPrice1 = 99.298100; |
|---|
| | 509 | |
|---|
| | 510 | double price = bond1.cleanPrice(); |
|---|
| | 511 | if (Math.Abs(price - cachedPrice1) > tolerance) |
|---|
| | 512 | { |
|---|
| | 513 | Console.WriteLine("failed to reproduce cached price:\n" |
|---|
| | 514 | + " calculated: " + price + "\n" |
|---|
| | 515 | + " expected: " + cachedPrice1 + "\n" |
|---|
| | 516 | + " error: " + (price - cachedPrice1)); |
|---|
| | 517 | } |
|---|
| | 518 | |
|---|
| | 519 | // varying coupons |
|---|
| | 520 | InitializedList<double> couponRates = new InitializedList<double>(4); |
|---|
| | 521 | couponRates[0] = 0.02875; |
|---|
| | 522 | couponRates[1] = 0.03; |
|---|
| | 523 | couponRates[2] = 0.03125; |
|---|
| | 524 | couponRates[3] = 0.0325; |
|---|
| | 525 | |
|---|
| | 526 | FixedRateBond bond2 = new FixedRateBond(settlementDays, vars.faceAmount, sch, couponRates, |
|---|
| | 527 | new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 528 | BusinessDayConvention.ModifiedFollowing, |
|---|
| | 529 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 530 | |
|---|
| | 531 | bond2.setPricingEngine(bondEngine); |
|---|
| | 532 | |
|---|
| | 533 | double cachedPrice2 = 100.334149; |
|---|
| | 534 | |
|---|
| | 535 | price = bond2.cleanPrice(); |
|---|
| | 536 | if (Math.Abs(price - cachedPrice2) > tolerance) |
|---|
| | 537 | { |
|---|
| | 538 | Console.WriteLine("failed to reproduce cached price:\n" |
|---|
| | 539 | + " calculated: " + price + "\n" |
|---|
| | 540 | + " expected: " + cachedPrice2 + "\n" |
|---|
| | 541 | + " error: " + (price - cachedPrice2)); |
|---|
| | 542 | } |
|---|
| | 543 | |
|---|
| | 544 | // stub date |
|---|
| | 545 | Schedule sch3 = new Schedule(new Date(30, Month.November, 2004), |
|---|
| | 546 | new Date(30, Month.March, 2009), new Period(Frequency.Semiannual), |
|---|
| | 547 | new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 548 | BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false, |
|---|
| | 549 | null, new Date(30, Month.November, 2008)); |
|---|
| | 550 | |
|---|
| | 551 | FixedRateBond bond3 = new FixedRateBond(settlementDays, vars.faceAmount, sch3, |
|---|
| | 552 | couponRates, new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 553 | BusinessDayConvention.ModifiedFollowing, |
|---|
| | 554 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 555 | |
|---|
| | 556 | bond3.setPricingEngine(bondEngine); |
|---|
| | 557 | |
|---|
| | 558 | double cachedPrice3 = 100.382794; |
|---|
| | 559 | |
|---|
| | 560 | price = bond3.cleanPrice(); |
|---|
| | 561 | if (Math.Abs(price - cachedPrice3) > tolerance) |
|---|
| | 562 | { |
|---|
| | 563 | Assert.Fail("failed to reproduce cached price:\n" |
|---|
| | 564 | + " calculated: " + price + "\n" |
|---|
| | 565 | + " expected: " + cachedPrice3 + "\n" |
|---|
| | 566 | + " error: " + (price - cachedPrice3)); |
|---|
| | 567 | } |
|---|
| | 568 | } |
|---|
| | 569 | [TestMethod()] |
|---|
| | 570 | public void testCachedFloating() |
|---|
| | 571 | { |
|---|
| | 572 | // "Testing floating-rate bond prices against cached values..."); |
|---|
| | 573 | |
|---|
| | 574 | CommonVars vars = new CommonVars(); |
|---|
| | 575 | |
|---|
| | 576 | Date today = new Date(22, Month.November, 2004); |
|---|
| | 577 | Settings.setEvaluationDate(today); |
|---|
| | 578 | |
|---|
| | 579 | int settlementDays = 1; |
|---|
| | 580 | |
|---|
| | 581 | var riskFreeRate = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.025, new Actual360())); |
|---|
| | 582 | var discountCurve = new Handle<YieldTermStructure>(Utilities.flatRate(today, 0.03, new Actual360())); |
|---|
| | 583 | |
|---|
| | 584 | IborIndex index = new USDLibor(new Period(6, TimeUnit.Months), riskFreeRate); |
|---|
| | 585 | int fixingDays = 1; |
|---|
| | 586 | |
|---|
| | 587 | double tolerance = 1.0e-6; |
|---|
| | 588 | |
|---|
| | 589 | IborCouponPricer pricer = new BlackIborCouponPricer(new Handle<OptionletVolatilityStructure>()); |
|---|
| | 590 | |
|---|
| | 591 | // plain |
|---|
| | 592 | Schedule sch = new Schedule(new Date(30, Month.November, 2004), new Date(30, Month.November, 2008), |
|---|
| | 593 | new Period(Frequency.Semiannual), new UnitedStates(UnitedStates.Market.GovernmentBond), |
|---|
| | 594 | BusinessDayConvention.ModifiedFollowing, BusinessDayConvention.ModifiedFollowing, |
|---|
| | 595 | DateGeneration.Rule.Backward, false); |
|---|
| | 596 | |
|---|
| | 597 | FloatingRateBond bond1 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, |
|---|
| | 598 | index, new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 599 | BusinessDayConvention.ModifiedFollowing, fixingDays, |
|---|
| | 600 | new List<double>(), new List<double>(), |
|---|
| | 601 | new List<double>(), new List<double>(), |
|---|
| | 602 | false, |
|---|
| | 603 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 604 | |
|---|
| | 605 | IPricingEngine bondEngine = new DiscountingBondEngine(riskFreeRate); |
|---|
| | 606 | bond1.setPricingEngine(bondEngine); |
|---|
| | 607 | |
|---|
| | 608 | Utils.setCouponPricer(bond1.cashflows(), pricer); |
|---|
| | 609 | |
|---|
| | 610 | #if QL_USE_INDEXED_COUPON |
|---|
| | 611 | double cachedPrice1 = 99.874645; |
|---|
| | 612 | #else |
|---|
| | 613 | double cachedPrice1 = 99.874646; |
|---|
| | 614 | #endif |
|---|
| | 615 | |
|---|
| | 616 | |
|---|
| | 617 | double price = bond1.cleanPrice(); |
|---|
| | 618 | if (Math.Abs(price - cachedPrice1) > tolerance) |
|---|
| | 619 | { |
|---|
| | 620 | Assert.Fail("failed to reproduce cached price:\n" |
|---|
| | 621 | + " calculated: " + price + "\n" |
|---|
| | 622 | + " expected: " + cachedPrice1 + "\n" |
|---|
| | 623 | + " error: " + (price - cachedPrice1)); |
|---|
| | 624 | } |
|---|
| | 625 | |
|---|
| | 626 | // different risk-free and discount curve |
|---|
| | 627 | FloatingRateBond bond2 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, |
|---|
| | 628 | index, new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 629 | BusinessDayConvention.ModifiedFollowing, fixingDays, |
|---|
| | 630 | new List<double>(), new List<double>(), |
|---|
| | 631 | new List<double>(), new List<double>(), |
|---|
| | 632 | false, |
|---|
| | 633 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 634 | |
|---|
| | 635 | IPricingEngine bondEngine2 = new DiscountingBondEngine(discountCurve); |
|---|
| | 636 | bond2.setPricingEngine(bondEngine2); |
|---|
| | 637 | |
|---|
| | 638 | Utils.setCouponPricer(bond2.cashflows(), pricer); |
|---|
| | 639 | |
|---|
| | 640 | #if QL_USE_INDEXED_COUPON |
|---|
| | 641 | double cachedPrice2 = 97.955904; |
|---|
| | 642 | #else |
|---|
| | 643 | double cachedPrice2 = 97.955904; |
|---|
| | 644 | #endif |
|---|
| | 645 | |
|---|
| | 646 | price = bond2.cleanPrice(); |
|---|
| | 647 | if (Math.Abs(price - cachedPrice2) > tolerance) |
|---|
| | 648 | { |
|---|
| | 649 | Assert.Fail("failed to reproduce cached price:\n" |
|---|
| | 650 | + " calculated: " + price + "\n" |
|---|
| | 651 | + " expected: " + cachedPrice2 + "\n" |
|---|
| | 652 | + " error: " + (price - cachedPrice2)); |
|---|
| | 653 | } |
|---|
| | 654 | |
|---|
| | 655 | // varying spread |
|---|
| | 656 | InitializedList<double> spreads = new InitializedList<double>(4); |
|---|
| | 657 | spreads[0] = 0.001; |
|---|
| | 658 | spreads[1] = 0.0012; |
|---|
| | 659 | spreads[2] = 0.0014; |
|---|
| | 660 | spreads[3] = 0.0016; |
|---|
| | 661 | |
|---|
| | 662 | FloatingRateBond bond3 = new FloatingRateBond(settlementDays, vars.faceAmount, sch, |
|---|
| | 663 | index, new ActualActual(ActualActual.Convention.ISMA), |
|---|
| | 664 | BusinessDayConvention.ModifiedFollowing, fixingDays, |
|---|
| | 665 | new List<double>(), spreads, |
|---|
| | 666 | new List<double>(), new List<double>(), |
|---|
| | 667 | false, |
|---|
| | 668 | 100.0, new Date(30, Month.November, 2004)); |
|---|
| | 669 | |
|---|
| | 670 | bond3.setPricingEngine(bondEngine2); |
|---|
| | 671 | |
|---|