public static flatRate ( Date today, |
||
today | Date | |
forward | ||
dc | DayCounter | |
return | QLNet.YieldTermStructure |
// setup public CommonVars() { calendar = new TARGET(); today = calendar.adjust(Date.Today); Settings.Instance.setEvaluationDate(today); dayCounter = new Actual360(); frequency = Frequency.Annual; settlementDays = 3; issueDate = calendar.advance(today, 2, TimeUnit.Days); maturityDate = calendar.advance(issueDate, 10, TimeUnit.Years); // reset to avoid inconsistencies as the schedule is backwards issueDate = calendar.advance(maturityDate, -10, TimeUnit.Years); underlying.linkTo(new SimpleQuote(50.0)); dividendYield.linkTo(Utilities.flatRate(today, 0.02, dayCounter)); riskFreeRate.linkTo(Utilities.flatRate(today, 0.05, dayCounter)); volatility.linkTo(Utilities.flatVol(today, 0.15, dayCounter)); process = new BlackScholesMertonProcess(underlying, dividendYield, riskFreeRate, volatility); creditSpread.linkTo(new SimpleQuote(0.005)); // it fails with 1000000 // faceAmount = 1000000.0; faceAmount = 100.0; redemption = 100.0; conversionRatio = redemption / underlying.link.value(); }
// Reference pg. 253 - Hull - Options, Futures, and Other Derivatives 5th ed // Exercise 12.8 // Doesn't quite work. Need to deal with date conventions private void testEuropeanKnownValue() { // Testing dividend European option values with known value... using (SavedSettings backup = new SavedSettings()) { double tolerance = 1.0e-2; double expected = 3.67; DayCounter dc = new Actual360(); Date today = Date.Today; Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.0); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc)); SimpleQuote vol = new SimpleQuote(0.0); Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc)); Date exDate = today + new Period(6, TimeUnit.Months); Exercise exercise = new EuropeanExercise(exDate); List <Date> dividendDates = new List <Date>(); List <double> dividends = new List <double>(); dividendDates.Add(today + new Period(2, TimeUnit.Months)); dividends.Add(0.50); dividendDates.Add(today + new Period(5, TimeUnit.Months)); dividends.Add(0.50); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 40.0); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS); IPricingEngine engine = new AnalyticDividendEuropeanEngine(stochProcess); DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends); option.setPricingEngine(engine); double u = 40.0; double q = 0.0, r = 0.09; double v = 0.30; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); double calculated = option.NPV(); double error = Math.Abs(calculated - expected); if (error > tolerance) { REPORT_FAILURE("value start limit", payoff, exercise, u, q, r, today, v, expected, calculated, error, tolerance); } } }
public void testCachedValue() { // Testing vanilla-swap calculation against cached value CommonVars vars = new CommonVars(); vars.today = new Date(17, Month.June, 2002); Settings.setEvaluationDate(vars.today); vars.settlement = vars.calendar.advance(vars.today, vars.settlementDays, TimeUnit.Days); vars.termStructure.linkTo(Utilities.flatRate(vars.settlement, 0.05, new Actual365Fixed())); VanillaSwap swap = vars.makeSwap(10, 0.06, 0.001); #if QL_USE_INDEXED_COUPON double cachedNPV = -5.872342992212; #else double cachedNPV = -5.872863313209; #endif if (Math.Abs(swap.NPV() - cachedNPV) > 1.0e-11) { QAssert.Fail("failed to reproduce cached swap value:\n" + " calculated: " + swap.NPV() + "\n" + " expected: " + cachedNPV); } }
public void testPerformanceValues() { // Testing forward performance option values... /* The data below are the performance equivalent of the * forward options tested above and taken from * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 */ ForwardOptionData[] values = { // type, moneyness, spot, div, rate,start, maturity, vol, result, tol new ForwardOptionData(Option.Type.Call, 1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 4.4064 / 60 * Math.Exp(-0.04 * 0.25), 1.0e-4), new ForwardOptionData(Option.Type.Put, 1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 8.2971 / 60 * Math.Exp(-0.04 * 0.25), 1.0e-4) }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.0); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, rRate, dc)); SimpleQuote vol = new SimpleQuote(0.0); Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, vol, dc)); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new ForwardPerformanceVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process)); // AnalyticEuropeanEngine for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, 0.0); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); Date reset = today + Convert.ToInt32(values[i].start * 360 + 0.5); spot.setValue(values[i].s); qRate.setValue(values[i].q); rRate.setValue(values[i].r); vol.setValue(values[i].v); ForwardVanillaOption option = new ForwardVanillaOption(values[i].moneyness, reset, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double error = Math.Abs(calculated - values[i].result); double tolerance = 1e-4; if (error > tolerance) { REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].moneyness, reset, values[i].result, calculated, error, tolerance); } } }
public void testCachedValue() { //"Testing swaption value against cached value..."); CommonVars vars = new CommonVars(); vars.today = new Date(13, 3, 2002); vars.settlement = new Date(15, 3, 2002); Settings.setEvaluationDate(vars.today); vars.termStructure.linkTo(Utilities.flatRate(vars.settlement, 0.05, new Actual365Fixed())); Date exerciseDate = vars.calendar.advance(vars.settlement, new Period(5, TimeUnit.Years)); Date startDate = vars.calendar.advance(exerciseDate, vars.settlementDays, TimeUnit.Days); VanillaSwap swap = new MakeVanillaSwap(new Period(10, TimeUnit.Years), vars.index, 0.06) .withEffectiveDate(startDate); Swaption swaption = vars.makeSwaption(swap, exerciseDate, 0.20); //#if QL_USE_INDEXED_COUPON double cachedNPV = 0.036418158579; //#else // double cachedNPV = 0.036421429684; //#endif // FLOATING_POINT_EXCEPTION if (Math.Abs(swaption.NPV() - cachedNPV) > 1.0e-12) { Assert.Fail("failed to reproduce cached swaption value:\n" + //QL_FIXED + std::setprecision(12) + "\ncalculated: " + swaption.NPV() + "\nexpected: " + cachedNPV); } }
public void testPathGenerator() { //"Testing 1-D path generation against cached values..."); //SavedSettings backup; Settings.setEvaluationDate(new Date(26, 4, 2005)); Handle <Quote> x0 = new Handle <Quote> (new SimpleQuote(100.0)); Handle <YieldTermStructure> r = new Handle <YieldTermStructure> (Utilities.flatRate(0.05, new Actual360())); Handle <YieldTermStructure> q = new Handle <YieldTermStructure> (Utilities.flatRate(0.02, new Actual360())); Handle <BlackVolTermStructure> sigma = new Handle <BlackVolTermStructure>(Utilities.flatVol(0.20, new Actual360())); // commented values must be used when Halley's correction is enabled testSingle(new BlackScholesMertonProcess(x0, q, r, sigma), "Black-Scholes", false, 26.13784357783, 467.2928561411); // 26.13784357783, 467.2928562519); //Error make the borwnian bridge test first testSingle(new BlackScholesMertonProcess(x0, q, r, sigma), "Black-Scholes", true, 60.28215549393, 202.6143139999); // 60.28215551021, 202.6143139437); testSingle(new GeometricBrownianMotionProcess(100.0, 0.03, 0.20), "geometric Brownian", false, 27.62223714065, 483.6026514084); // 27.62223714065, 483.602651493); testSingle(new OrnsteinUhlenbeckProcess(0.1, 0.20), "Ornstein-Uhlenbeck", false, -0.8372003433557, 0.8372003433557); testSingle(new SquareRootProcess(0.1, 0.1, 0.20, 10.0), "square-root", false, 1.70608664108, 6.024200546031); }
public void testBjerksundStenslandValues() { // ("Testing Bjerksund and Stensland approximation for American options..."); AmericanOptionData[] values = new AmericanOptionData[] { // type, strike, spot, q, r, t, vol, value, tol // from "Option pricing formulas", Haug, McGraw-Hill 1998, pag 27 new AmericanOptionData(Option.Type.Call, 40.00, 42.00, 0.08, 0.04, 0.75, 0.35, 5.2704), // from "Option pricing formulas", Haug, McGraw-Hill 1998, VBA code new AmericanOptionData(Option.Type.Put, 40.00, 36.00, 0.00, 0.06, 1.00, 0.20, 4.4531) }; Date today = Date.Today; DayCounter dc = new Actual360(); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); double tolerance = 3.0e-3; for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise exercise = new AmericanExercise(today, exDate); spot.setValue(values[i].s); qRate.setValue(values[i].q); rRate.setValue(values[i].r); vol.setValue(values[i].v); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new BjerksundStenslandApproximationEngine(stochProcess); VanillaOption option = new VanillaOption(payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > tolerance) { REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, tolerance); } } }
public void testCashOrNothingEuropeanValues() { // Testing European cash-or-nothing digital option DigitalOptionData[] values = { // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 88 // type, strike, spot, q, r, t, vol, value, tol new DigitalOptionData(Option.Type.Put, 80.00, 100.0, 0.06, 0.06, 0.75, 0.35, 2.6710, 1e-4, true) }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new CashOrNothingPayoff(values[i].type, values[i].strike, 10.0); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); spot.setValue(values[i].s); qRate.setValue(values[i].q); rRate.setValue(values[i].r); vol.setValue(values[i].v); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticEuropeanEngine(stochProcess); VanillaOption opt = new VanillaOption(payoff, exercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, values[i].tol, values[i].knockin); } } }
public void testFdmHestonEuropeanWithDividends() { //Testing FDM with European option with dividends in Heston model... using (SavedSettings backup = new SavedSettings()) { Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100.0)); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.05, new Actual365Fixed())); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, new Actual365Fixed())); HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, 0.04, 2.5, 0.04, 0.66, -0.8); Settings.Instance.setEvaluationDate(new Date(28, 3, 2004)); Date exerciseDate = new Date(28, 3, 2005); Exercise exercise = new AmericanExercise(exerciseDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, 100); List <double> dividends = new InitializedList <double>(1, 5); List <Date> dividendDates = new InitializedList <Date>(1, new Date(28, 9, 2004)); DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends); IPricingEngine engine = new FdHestonVanillaEngine(new HestonModel(hestonProcess), 50, 100, 50); option.setPricingEngine(engine); double tol = 0.01; double gammaTol = 0.001; double npvExpected = 7.365075; double deltaExpected = -0.396678; double gammaExpected = 0.027681; if (Math.Abs(option.NPV() - npvExpected) > tol) { QAssert.Fail("Failed to reproduce expected npv" + "\n calculated: " + option.NPV() + "\n expected: " + npvExpected + "\n tolerance: " + tol); } if (Math.Abs(option.delta() - deltaExpected) > tol) { QAssert.Fail("Failed to reproduce expected delta" + "\n calculated: " + option.delta() + "\n expected: " + deltaExpected + "\n tolerance: " + tol); } if (Math.Abs(option.gamma() - gammaExpected) > gammaTol) { QAssert.Fail("Failed to reproduce expected gamma" + "\n calculated: " + option.gamma() + "\n expected: " + gammaExpected + "\n tolerance: " + tol); } } }
public void testValues() { // Testing Cliquet option values Date today = Date.Today; DayCounter dc = new Actual360(); SimpleQuote spot = new SimpleQuote(60.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.08); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.30); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); BlackScholesMertonProcess process = new BlackScholesMertonProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticCliquetEngine(process); List <Date> reset = new List <Date>(); reset.Add(today + 90); Date maturity = today + 360; Option.Type type = Option.Type.Call; double moneyness = 1.1; PercentageStrikePayoff payoff = new PercentageStrikePayoff(type, moneyness); EuropeanExercise exercise = new EuropeanExercise(maturity); CliquetOption option = new CliquetOption(payoff, exercise, reset); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = 4.4064; // Haug, p.37 double error = Math.Abs(calculated - expected); double tolerance = 1e-4; if (error > tolerance) { REPORT_FAILURE("value", payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, error, tolerance); } }
public void testFdmHestonBarrier() { //Testing FDM with barrier option for Heston model vs Black-Scholes model... using (SavedSettings backup = new SavedSettings()) { Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100.0)); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.05, new Actual365Fixed())); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, new Actual365Fixed())); HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, 0.04, 2.5, 0.04, 0.66, -0.8); Settings.Instance.setEvaluationDate(new Date(28, 3, 2004)); Date exerciseDate = new Date(28, 3, 2005); Exercise exercise = new EuropeanExercise(exerciseDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 100); BarrierOption barrierOption = new BarrierOption(Barrier.Type.UpOut, 135, 0.0, payoff, exercise); barrierOption.setPricingEngine(new FdHestonBarrierEngine(new HestonModel(hestonProcess), 50, 400, 100)); double tol = 0.01; double npvExpected = 9.1530; double deltaExpected = 0.5218; double gammaExpected = -0.0354; if (Math.Abs(barrierOption.NPV() - npvExpected) > tol) { QAssert.Fail("Failed to reproduce expected npv" + "\n calculated: " + barrierOption.NPV() + "\n expected: " + npvExpected + "\n tolerance: " + tol); } if (Math.Abs(barrierOption.delta() - deltaExpected) > tol) { QAssert.Fail("Failed to reproduce expected delta" + "\n calculated: " + barrierOption.delta() + "\n expected: " + deltaExpected + "\n tolerance: " + tol); } if (Math.Abs(barrierOption.gamma() - gammaExpected) > tol) { QAssert.Fail("Failed to reproduce expected gamma" + "\n calculated: " + barrierOption.gamma() + "\n expected: " + gammaExpected + "\n tolerance: " + tol); } } }
void testFdDegenerate <Engine>(Date today, Exercise exercise) where Engine : IFDEngine, new() { DayCounter dc = new Actual360(); SimpleQuote spot = new SimpleQuote(54.625); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.052706, dc)); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, dc)); Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(0.282922, dc)); BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS); int timeSteps = 300; int gridPoints = 300; IPricingEngine engine = new Engine().factory(process, timeSteps, gridPoints); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 55.0); double tolerance = 3.0e-3; List <double> dividends = new List <double>(); List <Date> dividendDates = new List <Date>(); DividendVanillaOption option1 = new DividendVanillaOption(payoff, exercise, dividendDates, dividends); option1.setPricingEngine(engine); // FLOATING_POINT_EXCEPTION double refValue = option1.NPV(); for (int i = 0; i <= 6; i++) { dividends.Add(0.0); dividendDates.Add(today + i); DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends); option.setPricingEngine(engine); double value = option.NPV(); if (Math.Abs(refValue - value) > tolerance) { Assert.Fail("NPV changed by null dividend :\n" + " previous value: " + value + "\n" + " current value: " + refValue + "\n" + " change: " + (value - refValue)); } } }
public void testFdValues() { //("Testing finite-difference engine for American options..."); Date today = Date.Today; DayCounter dc = new Actual360(); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); double tolerance = 8.0e-2; for (int i = 0; i < juValues.Length; i++) { StrikedTypePayoff payoff = new PlainVanillaPayoff(juValues[i].type, juValues[i].strike); Date exDate = today + Convert.ToInt32(juValues[i].t * 360 + 0.5); Exercise exercise = new AmericanExercise(today, exDate); spot.setValue(juValues[i].s); qRate.setValue(juValues[i].q); rRate.setValue(juValues[i].r); vol.setValue(juValues[i].v); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new FDAmericanEngine(stochProcess, 100, 100); VanillaOption option = new VanillaOption(payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double error = Math.Abs(calculated - juValues[i].result); if (error > tolerance) { REPORT_FAILURE("value", payoff, exercise, juValues[i].s, juValues[i].q, juValues[i].r, today, juValues[i].v, juValues[i].result, calculated, error, tolerance); } } }
public void testInitialisation() { //"Testing caplet LMM process initialisation..." //SavedSettings backup; DayCounter dayCounter = new Actual360(); RelinkableHandle <YieldTermStructure> termStructure = new RelinkableHandle <YieldTermStructure>();; termStructure.linkTo(Utilities.flatRate(Date.Today, 0.04, dayCounter)); IborIndex index = new Euribor6M(termStructure); OptionletVolatilityStructure capletVol = new ConstantOptionletVolatility( termStructure.currentLink().referenceDate(), termStructure.currentLink().calendar(), BusinessDayConvention.Following, 0.2, termStructure.currentLink().dayCounter()); Calendar calendar = index.fixingCalendar(); for (int daysOffset = 0; daysOffset < 1825 /* 5 year*/; daysOffset += 8) { Date todaysDate = calendar.adjust(Date.Today + daysOffset); Settings.setEvaluationDate(todaysDate); Date settlementDate = calendar.advance(todaysDate, index.fixingDays(), TimeUnit.Days); termStructure.linkTo(Utilities.flatRate(settlementDate, 0.04, dayCounter)); LiborForwardModelProcess process = new LiborForwardModelProcess(60, index); List <double> fixings = process.fixingTimes(); for (int i = 1; i < fixings.Count - 1; ++i) { int ileft = process.nextIndexReset(fixings[i] - 0.000001); int iright = process.nextIndexReset(fixings[i] + 0.000001); int ii = process.nextIndexReset(fixings[i]); if ((ileft != i) || (iright != i + 1) || (ii != i + 1)) { Assert.Fail("Failed to next index resets"); } } } }
public void testAccessViolation() { // Testing dynamic cast of coupon in Black pricer... SavedSettings backup = new SavedSettings(); Date todaysDate = new Date(7, Month.April, 2010); Date settlementDate = new Date(9, Month.April, 2010); Settings.setEvaluationDate(todaysDate); Calendar calendar = new TARGET(); Handle <YieldTermStructure> rhTermStructure = new Handle <YieldTermStructure>( Utilities.flatRate(settlementDate, 0.04875825, new Actual365Fixed())); double volatility = 0.10; Handle <OptionletVolatilityStructure> vol = new Handle <OptionletVolatilityStructure>( new ConstantOptionletVolatility(2, calendar, BusinessDayConvention.ModifiedFollowing, volatility, new Actual365Fixed())); IborIndex index3m = new USDLibor(new Period(3, TimeUnit.Months), rhTermStructure); Date payDate = new Date(20, Month.December, 2013); Date startDate = new Date(20, Month.September, 2013); Date endDate = new Date(20, Month.December, 2013); double spread = 0.0115; IborCouponPricer pricer = new BlackIborCouponPricer(vol); FloatingRateCoupon coupon = new FloatingRateCoupon(100, payDate, startDate, endDate, 2, index3m, 1.0, spread / 100); coupon.setPricer(pricer); try { // this caused an access violation in version 1.0 coupon.amount(); } catch (Exception) { // ok; proper exception thrown } }
public CommonVars() { settlementDays = 2; nominal = 1000000.0; fixedConvention = BusinessDayConvention.Unadjusted; fixedFrequency = Frequency.Annual; fixedDayCount = new Thirty360(); index = new Euribor6M(termStructure); floatingConvention = index.businessDayConvention(); floatingTenor = index.tenor(); calendar = index.fixingCalendar(); today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); settlement = calendar.advance(today, settlementDays, TimeUnit.Days); termStructure.linkTo(Utilities.flatRate(settlement, 0.05, new Actual365Fixed())); }
public void testFdmHestonIkonenToivanen() { //Testing FDM Heston for Ikonen and Toivanen tests... /* check prices of american puts as given in: * From Efficient numerical methods for pricing American options under * stochastic volatility, Samuli Ikonen, Jari Toivanen, * http://users.jyu.fi/~tene/papers/reportB12-05.pdf */ using (SavedSettings backup = new SavedSettings()) { Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.10, new Actual360())); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(0.0, new Actual360())); Settings.Instance.setEvaluationDate(new Date(28, 3, 2004)); Date exerciseDate = new Date(26, 6, 2004); Exercise exercise = new AmericanExercise(exerciseDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, 10); VanillaOption option = new VanillaOption(payoff, exercise); double[] strikes = new double[] { 8, 9, 10, 11, 12 }; double[] expected = new double[] { 2.00000, 1.10763, 0.520038, 0.213681, 0.082046 }; double tol = 0.001; for (int i = 0; i < strikes.Length; ++i) { Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(strikes[i])); HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, 0.0625, 5, 0.16, 0.9, 0.1); IPricingEngine engine = new FdHestonVanillaEngine(new HestonModel(hestonProcess), 100, 400); option.setPricingEngine(engine); double calculated = option.NPV(); if (Math.Abs(calculated - expected[i]) > tol) { QAssert.Fail("Failed to reproduce expected npv" + "\n strike: " + strikes[i] + "\n calculated: " + calculated + "\n expected: " + expected[i] + "\n tolerance: " + tol); } } } }
// setup public CommonVars() { termStructure = new RelinkableHandle <YieldTermStructure>(); backup = new SavedSettings(); length = 20; //years volatility = 0.20; nominal = 100.0; nominals = new InitializedList <double>(length, nominal); frequency = Frequency.Annual; index = new Euribor1Y(termStructure); calendar = index.fixingCalendar(); convention = BusinessDayConvention.ModifiedFollowing; today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); settlementDays = 2; fixingDays = 2; settlement = calendar.advance(today, settlementDays, TimeUnit.Days); startDate = settlement; termStructure.linkTo(Utilities.flatRate(settlement, 0.05, new ActualActual(ActualActual.Convention.ISDA))); }
// setup public CommonVars() { nominals = new List <double>() { 100 }; frequency = Frequency.Semiannual; index = (IborIndex) new Euribor6M(termStructure); calendar = index.fixingCalendar(); convention = BusinessDayConvention.ModifiedFollowing; Date today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); int settlementDays = 2; fixingDays = 2; settlement = calendar.advance(today, settlementDays, TimeUnit.Days); termStructure.linkTo(Utilities.flatRate(settlement, 0.05, new ActualActual(ActualActual.Convention.ISDA))); }
public CommonVars() { type = VanillaSwap.Type.Payer; settlementDays = 2; nominal = 100.0; fixedConvention = BusinessDayConvention.Unadjusted; floatingConvention = BusinessDayConvention.ModifiedFollowing; fixedFrequency = Frequency.Annual; floatingFrequency = Frequency.Semiannual; fixedDayCount = new Thirty360(); index = new Euribor(new Period(floatingFrequency), termStructure); calendar = index.fixingCalendar(); today = calendar.adjust(Date.Today); Settings.setEvaluationDate(today); settlement = calendar.advance(today, settlementDays, TimeUnit.Days); termStructure.linkTo(Utilities.flatRate(settlement, 0.05, new Actual365Fixed())); }
public CommonVars() { Settings.setEvaluationDate(new Date(16, Month.September, 2015)); conventions.setConventions(); // ATM swaptionvolmatrix atm.setMarketData(); atmVolMatrix = new RelinkableHandle <SwaptionVolatilityStructure>( new SwaptionVolatilityMatrix(conventions.calendar, conventions.optionBdc, atm.tenors.options, atm.tenors.swaps, atm.volsHandle, conventions.dayCounter)); // Swaptionvolcube cube.setMarketData(); termStructure.linkTo(Utilities.flatRate(0.05, new Actual365Fixed())); swapIndexBase = new EuriborSwapIsdaFixA(new Period(2, TimeUnit.Years), termStructure); shortSwapIndexBase = new EuriborSwapIsdaFixA(new Period(1, TimeUnit.Years), termStructure); vegaWeighedSmileFit = false; }
// setup public CommonVars() { startYears = 1; length = 5; type = VanillaSwap.Type.Payer; nominal = 1000.0; settlementDays = 2; fixedConvention = BusinessDayConvention.Unadjusted; floatingConvention = BusinessDayConvention.ModifiedFollowing; fixedFrequency = Frequency.Annual; floatingFrequency = Frequency.Semiannual; fixedDayCount = new Thirty360(); termStructure = new RelinkableHandle <YieldTermStructure>(); termStructure.linkTo(Utilities.flatRate(new Date(19, Month.February, 2002), 0.04875825, new Actual365Fixed())); index = new Euribor6M(termStructure); calendar = index.fixingCalendar(); today = calendar.adjust(Date.Today); settlement = calendar.advance(today, settlementDays, TimeUnit.Days); }
public CommonVars() { type = OvernightIndexedSwap.Type.Payer; settlementDays = 2; nominal = 100.0; fixedEoniaConvention = BusinessDayConvention.ModifiedFollowing; floatingEoniaConvention = BusinessDayConvention.ModifiedFollowing; fixedEoniaPeriod = new Period(1, TimeUnit.Years); floatingEoniaPeriod = new Period(1, TimeUnit.Years); fixedEoniaDayCount = new Actual360(); eoniaIndex = new Eonia(eoniaTermStructure); fixedSwapConvention = BusinessDayConvention.ModifiedFollowing; fixedSwapFrequency = Frequency.Annual; fixedSwapDayCount = new Thirty360(); swapIndex = (IborIndex) new Euribor3M(swapTermStructure); calendar = eoniaIndex.fixingCalendar(); today = new Date(5, Month.February, 2009); //today = calendar.adjust(Date::todaysDate()); Settings.setEvaluationDate(today); settlement = calendar.advance(today, new Period(settlementDays, TimeUnit.Days), BusinessDayConvention.Following); eoniaTermStructure.linkTo(Utilities.flatRate(settlement, 0.05, new Actual365Fixed())); }
public void testCachedValue() { CommonVars vars = new CommonVars(); Date cachedToday = new Date(14, Month.March, 2002), cachedSettlement = new Date(18, Month.March, 2002); Settings.setEvaluationDate(cachedToday); vars.termStructure.linkTo(Utilities.flatRate(cachedSettlement, 0.05, new Actual360())); Date startDate = vars.termStructure.link.referenceDate(); List <CashFlow> leg = vars.makeLeg(startDate, 20); Instrument cap = vars.makeCapFloor(CapFloorType.Cap, leg, 0.07, 0.20); Instrument floor = vars.makeCapFloor(CapFloorType.Floor, leg, 0.03, 0.20); // par coupon price double cachedCapNPV = 6.87570026732, cachedFloorNPV = 2.65812927959; // index fixing price //Real cachedCapNPV = 6.87630307745, // cachedFloorNPV = 2.65796764715; // test Black cap price against cached value if (Math.Abs(cap.NPV() - cachedCapNPV) > 1.0e-11) { QAssert.Fail("failed to reproduce cached cap value:\n" + " calculated: " + cap.NPV() + "\n" + " expected: " + cachedCapNPV); } // test Black floor price against cached value if (Math.Abs(floor.NPV() - cachedFloorNPV) > 1.0e-11) { QAssert.Fail("failed to reproduce cached floor value:\n" + " calculated: " + floor.NPV() + "\n" + " expected: " + cachedFloorNPV); } }
public void testCachedValue() { // Testing Eonia-swap calculation against cached value... CommonVars vars = new CommonVars(); Settings.setEvaluationDate(vars.today); vars.settlement = vars.calendar.advance(vars.today, vars.settlementDays, TimeUnit.Days); double flat = 0.05; vars.eoniaTermStructure.linkTo(Utilities.flatRate(vars.settlement, flat, new Actual360())); double fixedRate = Math.Exp(flat) - 1; OvernightIndexedSwap swap = vars.makeSwap(new Period(1, TimeUnit.Years), fixedRate, 0.0); double cachedNPV = 0.001730450147; double tolerance = 1.0e-11; if (Math.Abs(swap.NPV() - cachedNPV) > tolerance) { QAssert.Fail("\nfailed to reproduce cached swap value:" + "\ncalculated: " + swap.NPV() + "\n expected: " + cachedNPV + "\n tolerance:" + tolerance); } }
// setup public CommonVars() { backup = new SavedSettings(); Calendar calendar = new TARGET(); Date referenceDate = calendar.adjust(Date.Today); Settings.Instance.setEvaluationDate(referenceDate); termStructure = new RelinkableHandle <YieldTermStructure>(); termStructure.linkTo(Utilities.flatRate(referenceDate, 0.05, new Actual365Fixed())); // ATM Volatility structure List <Period> atmOptionTenors = new List <Period>(); atmOptionTenors.Add(new Period(1, TimeUnit.Months)); atmOptionTenors.Add(new Period(6, TimeUnit.Months)); atmOptionTenors.Add(new Period(1, TimeUnit.Years)); atmOptionTenors.Add(new Period(5, TimeUnit.Years)); atmOptionTenors.Add(new Period(10, TimeUnit.Years)); atmOptionTenors.Add(new Period(30, TimeUnit.Years)); List <Period> atmSwapTenors = new List <Period>(); atmSwapTenors.Add(new Period(1, TimeUnit.Years)); atmSwapTenors.Add(new Period(5, TimeUnit.Years)); atmSwapTenors.Add(new Period(10, TimeUnit.Years)); atmSwapTenors.Add(new Period(30, TimeUnit.Years)); Matrix m = new Matrix(atmOptionTenors.Count, atmSwapTenors.Count); m[0, 0] = 0.1300; m[0, 1] = 0.1560; m[0, 2] = 0.1390; m[0, 3] = 0.1220; m[1, 0] = 0.1440; m[1, 1] = 0.1580; m[1, 2] = 0.1460; m[1, 3] = 0.1260; m[2, 0] = 0.1600; m[2, 1] = 0.1590; m[2, 2] = 0.1470; m[2, 3] = 0.1290; m[3, 0] = 0.1640; m[3, 1] = 0.1470; m[3, 2] = 0.1370; m[3, 3] = 0.1220; m[4, 0] = 0.1400; m[4, 1] = 0.1300; m[4, 2] = 0.1250; m[4, 3] = 0.1100; m[5, 0] = 0.1130; m[5, 1] = 0.1090; m[5, 2] = 0.1070; m[5, 3] = 0.0930; atmVol = new Handle <SwaptionVolatilityStructure>( new SwaptionVolatilityMatrix(calendar, BusinessDayConvention.Following, atmOptionTenors, atmSwapTenors, m, new Actual365Fixed())); // Vol cubes List <Period> optionTenors = new List <Period>(); optionTenors.Add(new Period(1, TimeUnit.Years)); optionTenors.Add(new Period(10, TimeUnit.Years)); optionTenors.Add(new Period(30, TimeUnit.Years)); List <Period> swapTenors = new List <Period>(); swapTenors.Add(new Period(2, TimeUnit.Years)); swapTenors.Add(new Period(10, TimeUnit.Years)); swapTenors.Add(new Period(30, TimeUnit.Years)); List <double> strikeSpreads = new List <double>(); strikeSpreads.Add(-0.020); strikeSpreads.Add(-0.005); strikeSpreads.Add(+0.000); strikeSpreads.Add(+0.005); strikeSpreads.Add(+0.020); int nRows = optionTenors.Count * swapTenors.Count; int nCols = strikeSpreads.Count; Matrix volSpreadsMatrix = new Matrix(nRows, nCols); volSpreadsMatrix[0, 0] = 0.0599; volSpreadsMatrix[0, 1] = 0.0049; volSpreadsMatrix[0, 2] = 0.0000; volSpreadsMatrix[0, 3] = -0.0001; volSpreadsMatrix[0, 4] = 0.0127; volSpreadsMatrix[1, 0] = 0.0729; volSpreadsMatrix[1, 1] = 0.0086; volSpreadsMatrix[1, 2] = 0.0000; volSpreadsMatrix[1, 3] = -0.0024; volSpreadsMatrix[1, 4] = 0.0098; volSpreadsMatrix[2, 0] = 0.0738; volSpreadsMatrix[2, 1] = 0.0102; volSpreadsMatrix[2, 2] = 0.0000; volSpreadsMatrix[2, 3] = -0.0039; volSpreadsMatrix[2, 4] = 0.0065; volSpreadsMatrix[3, 0] = 0.0465; volSpreadsMatrix[3, 1] = 0.0063; volSpreadsMatrix[3, 2] = 0.0000; volSpreadsMatrix[3, 3] = -0.0032; volSpreadsMatrix[3, 4] = -0.0010; volSpreadsMatrix[4, 0] = 0.0558; volSpreadsMatrix[4, 1] = 0.0084; volSpreadsMatrix[4, 2] = 0.0000; volSpreadsMatrix[4, 3] = -0.0050; volSpreadsMatrix[4, 4] = -0.0057; volSpreadsMatrix[5, 0] = 0.0576; volSpreadsMatrix[5, 1] = 0.0083; volSpreadsMatrix[5, 2] = 0.0000; volSpreadsMatrix[5, 3] = -0.0043; volSpreadsMatrix[5, 4] = -0.0014; volSpreadsMatrix[6, 0] = 0.0437; volSpreadsMatrix[6, 1] = 0.0059; volSpreadsMatrix[6, 2] = 0.0000; volSpreadsMatrix[6, 3] = -0.0030; volSpreadsMatrix[6, 4] = -0.0006; volSpreadsMatrix[7, 0] = 0.0533; volSpreadsMatrix[7, 1] = 0.0078; volSpreadsMatrix[7, 2] = 0.0000; volSpreadsMatrix[7, 3] = -0.0045; volSpreadsMatrix[7, 4] = -0.0046; volSpreadsMatrix[8, 0] = 0.0545; volSpreadsMatrix[8, 1] = 0.0079; volSpreadsMatrix[8, 2] = 0.0000; volSpreadsMatrix[8, 3] = -0.0042; volSpreadsMatrix[8, 4] = -0.0020; List <List <Handle <Quote> > > volSpreads = new InitializedList <List <Handle <Quote> > >(nRows); for (int i = 0; i < nRows; ++i) { volSpreads[i] = new InitializedList <Handle <Quote> >(nCols); for (int j = 0; j < nCols; ++j) { volSpreads[i][j] = new Handle <Quote>(new SimpleQuote(volSpreadsMatrix[i, j])); } } iborIndex = new Euribor6M(termStructure); SwapIndex swapIndexBase = new EuriborSwapIsdaFixA(new Period(10, TimeUnit.Years), termStructure); SwapIndex shortSwapIndexBase = new EuriborSwapIsdaFixA(new Period(2, TimeUnit.Years), termStructure); bool vegaWeightedSmileFit = false; SabrVolCube2 = new Handle <SwaptionVolatilityStructure>( new SwaptionVolCube2(atmVol, optionTenors, swapTenors, strikeSpreads, volSpreads, swapIndexBase, shortSwapIndexBase, vegaWeightedSmileFit)); SabrVolCube2.link.enableExtrapolation(); List <List <Handle <Quote> > > guess = new InitializedList <List <Handle <Quote> > >(nRows); for (int i = 0; i < nRows; ++i) { guess[i] = new InitializedList <Handle <Quote> >(4); guess[i][0] = new Handle <Quote>(new SimpleQuote(0.2)); guess[i][1] = new Handle <Quote>(new SimpleQuote(0.5)); guess[i][2] = new Handle <Quote>(new SimpleQuote(0.4)); guess[i][3] = new Handle <Quote>(new SimpleQuote(0.0)); } List <bool> isParameterFixed = new InitializedList <bool>(4, false); isParameterFixed[1] = true; // FIXME bool isAtmCalibrated = false; SabrVolCube1 = new Handle <SwaptionVolatilityStructure>( new SwaptionVolCube1x(atmVol, optionTenors, swapTenors, strikeSpreads, volSpreads, swapIndexBase, shortSwapIndexBase, vegaWeightedSmileFit, guess, isParameterFixed, isAtmCalibrated)); SabrVolCube1.link.enableExtrapolation(); yieldCurveModels = new List <GFunctionFactory.YieldCurveModel>(); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.Standard); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.ExactYield); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.ParallelShifts); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.NonParallelShifts); yieldCurveModels.Add(GFunctionFactory.YieldCurveModel.NonParallelShifts); // for linear tsr model Handle <Quote> zeroMeanRev = new Handle <Quote>(new SimpleQuote(0.0)); numericalPricers = new List <CmsCouponPricer>(); analyticPricers = new List <CmsCouponPricer>(); for (int j = 0; j < yieldCurveModels.Count; ++j) { if (j < yieldCurveModels.Count - 1) { numericalPricers.Add(new NumericHaganPricer(atmVol, yieldCurveModels[j], zeroMeanRev)); } else { numericalPricers.Add(new LinearTsrPricer(atmVol, zeroMeanRev)); } analyticPricers.Add(new AnalyticHaganPricer(atmVol, yieldCurveModels[j], zeroMeanRev)); } }
public void testCrankNicolsonWithDamping() { SavedSettings backup = new SavedSettings(); DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); YieldTermStructure qTS = Utilities.flatRate(today, 0.06, dc); YieldTermStructure rTS = Utilities.flatRate(today, 0.06, dc); BlackVolTermStructure volTS = Utilities.flatVol(today, 0.35, dc); StrikedTypePayoff payoff = new CashOrNothingPayoff(Option.Type.Put, 100, 10.0); double maturity = 0.75; Date exDate = today + Convert.ToInt32(maturity * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticEuropeanEngine(process); VanillaOption opt = new VanillaOption(payoff, exercise); opt.setPricingEngine(engine); double expectedPV = opt.NPV(); double expectedGamma = opt.gamma(); // fd pricing using implicit damping steps and Crank Nicolson int csSteps = 25, dampingSteps = 3, xGrid = 400; List <int> dim = new InitializedList <int>(1, xGrid); FdmLinearOpLayout layout = new FdmLinearOpLayout(dim); Fdm1dMesher equityMesher = new FdmBlackScholesMesher( dim[0], process, maturity, payoff.strike(), null, null, 0.0001, 1.5, new Pair <double?, double?>(payoff.strike(), 0.01)); FdmMesher mesher = new FdmMesherComposite(equityMesher); FdmBlackScholesOp map = new FdmBlackScholesOp(mesher, process, payoff.strike()); FdmInnerValueCalculator calculator = new FdmLogInnerValue(payoff, mesher, 0); object rhs = new Vector(layout.size()); Vector x = new Vector(layout.size()); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { (rhs as Vector)[iter.index()] = calculator.avgInnerValue(iter, maturity); x[iter.index()] = mesher.location(iter, 0); } FdmBackwardSolver solver = new FdmBackwardSolver(map, new FdmBoundaryConditionSet(), new FdmStepConditionComposite(), new FdmSchemeDesc().Douglas()); solver.rollback(ref rhs, maturity, 0.0, csSteps, dampingSteps); MonotonicCubicNaturalSpline spline = new MonotonicCubicNaturalSpline(x, x.Count, rhs as Vector); double s = spot.value(); double calculatedPV = spline.value(Math.Log(s)); double calculatedGamma = (spline.secondDerivative(Math.Log(s)) - spline.derivative(Math.Log(s))) / (s * s); double relTol = 2e-3; if (Math.Abs(calculatedPV - expectedPV) > relTol * expectedPV) { QAssert.Fail("Error calculating the PV of the digital option" + "\n rel. tolerance: " + relTol + "\n expected: " + expectedPV + "\n calculated: " + calculatedPV); } if (Math.Abs(calculatedGamma - expectedGamma) > relTol * expectedGamma) { QAssert.Fail("Error calculating the Gamma of the digital option" + "\n rel. tolerance: " + relTol + "\n expected: " + expectedGamma + "\n calculated: " + calculatedGamma); } }
public void testVannaVolgaDoubleBarrierValues() { // Testing double-barrier FX options against Vanna/Volga values SavedSettings backup = new SavedSettings(); DoubleBarrierFxOptionData[] values = { // BarrierType, barr.1, barr.2, rebate, type, strike, s, q, r, t, vol25Put, volAtm,vol25Call, vol, result, tol new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.14413, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.07456, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02710, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.00569, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.00013, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.00017, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.00353, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02221, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.06049, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.11103, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.19981, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.10389, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03555, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.00634, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.00000, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.00000, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.00436, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03173, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.09346, 1.0e-4), new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.17704, 1.0e-4), }; DayCounter dc = new Actual360(); Date today = new Date(05, Month.Mar, 2013); Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol25Put = new SimpleQuote(0.0); SimpleQuote volAtm = new SimpleQuote(0.0); SimpleQuote vol25Call = new SimpleQuote(0.0); for (int i = 0; i < values.Length; i++) { for (int j = 0; j <= 1; j++) { DoubleBarrier.Type barrierType = (DoubleBarrier.Type)j; spot.setValue(values[i].s); qRate.setValue(values[i].q); rRate.setValue(values[i].r); vol25Put.setValue(values[i].vol25Put); volAtm.setValue(values[i].volAtm); vol25Call.setValue(values[i].vol25Call); StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); Date exDate = today + (int)(values[i].t * 365 + 0.5); Exercise exercise = new EuropeanExercise(exDate); Handle <DeltaVolQuote> volAtmQuote = new Handle <DeltaVolQuote>( new DeltaVolQuote(new Handle <Quote>(volAtm), DeltaVolQuote.DeltaType.Fwd, values[i].t, DeltaVolQuote.AtmType.AtmDeltaNeutral)); //always delta neutral atm Handle <DeltaVolQuote> vol25PutQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(-0.25, new Handle <Quote>(vol25Put), values[i].t, DeltaVolQuote.DeltaType.Fwd)); Handle <DeltaVolQuote> vol25CallQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(0.25, new Handle <Quote>(vol25Call), values[i].t, DeltaVolQuote.DeltaType.Fwd)); DoubleBarrierOption doubleBarrierOption = new DoubleBarrierOption(barrierType, values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise); double bsVanillaPrice = Utils.blackFormula(values[i].type, values[i].strike, spot.value() * qTS.discount(values[i].t) / rTS.discount(values[i].t), values[i].v * Math.Sqrt(values[i].t), rTS.discount(values[i].t)); IPricingEngine vannaVolgaEngine; vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote, new Handle <Quote>(spot), new Handle <YieldTermStructure>(rTS), new Handle <YieldTermStructure>(qTS), (process, series) => new WulinYongDoubleBarrierEngine(process, series), true, bsVanillaPrice); doubleBarrierOption.setPricingEngine(vannaVolgaEngine); double expected = 0; if (barrierType == DoubleBarrier.Type.KnockOut) { expected = values[i].result; } else if (barrierType == DoubleBarrier.Type.KnockIn) { expected = (bsVanillaPrice - values[i].result); } double calculated = doubleBarrierOption.NPV(); double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType, values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].vol25Put, values[i].volAtm, values[i].vol25Call, values[i].v, expected, calculated, error, values[i].tol); } vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote, new Handle <Quote>(spot), new Handle <YieldTermStructure>(rTS), new Handle <YieldTermStructure>(qTS), (process, series) => new AnalyticDoubleBarrierEngine(process, series), true, bsVanillaPrice); doubleBarrierOption.setPricingEngine(vannaVolgaEngine); calculated = doubleBarrierOption.NPV(); error = Math.Abs(calculated - expected); double maxtol = 5.0e-3; // different engines have somewhat different results if (error > maxtol) { REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType, values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].vol25Put, values[i].volAtm, values[i].vol25Call, values[i].v, expected, calculated, error, values[i].tol); } } } }
public void testMultiPathGenerator() { //("Testing n-D path generation against cached values..."); //SavedSettings backup; Settings.setEvaluationDate(new Date(26, 4, 2005)); Handle <Quote> x0 = new Handle <Quote> (new SimpleQuote(100.0)); Handle <YieldTermStructure> r = new Handle <YieldTermStructure> (Utilities.flatRate(0.05, new Actual360())); Handle <YieldTermStructure> q = new Handle <YieldTermStructure> (Utilities.flatRate(0.02, new Actual360())); Handle <BlackVolTermStructure> sigma = new Handle <BlackVolTermStructure> (Utilities.flatVol(0.20, new Actual360())); Matrix correlation = new Matrix(3, 3); correlation[0, 0] = 1.0; correlation[0, 1] = 0.9; correlation[0, 2] = 0.7; correlation[1, 0] = 0.9; correlation[1, 1] = 1.0; correlation[1, 2] = 0.4; correlation[2, 0] = 0.7; correlation[2, 1] = 0.4; correlation[2, 2] = 1.0; List <StochasticProcess1D> processes = new List <StochasticProcess1D>(3); StochasticProcess process; processes.Add(new BlackScholesMertonProcess(x0, q, r, sigma)); processes.Add(new BlackScholesMertonProcess(x0, q, r, sigma)); processes.Add(new BlackScholesMertonProcess(x0, q, r, sigma)); process = new StochasticProcessArray(processes, correlation); // commented values must be used when Halley's correction is enabled double[] result1 = { 188.2235868185, 270.6713069569, 113.0431145652 }; // Real result1[] = { // 188.2235869273, // 270.6713071508, // 113.0431145652 }; double[] result1a = { 64.89105742957, 45.12494404804, 108.0475146914 }; // Real result1a[] = { // 64.89105739157, // 45.12494401537, // 108.0475146914 }; testMultiple(process, "Black-Scholes", result1, result1a); processes[0] = new GeometricBrownianMotionProcess(100.0, 0.03, 0.20); processes[1] = new GeometricBrownianMotionProcess(100.0, 0.03, 0.20); processes[2] = new GeometricBrownianMotionProcess(100.0, 0.03, 0.20); process = new StochasticProcessArray(processes, correlation); double[] result2 = { 174.8266131680, 237.2692443633, 119.1168555440 }; // Real result2[] = { // 174.8266132344, // 237.2692444869, // 119.1168555605 }; double[] result2a = { 57.69082393020, 38.50016862915, 116.4056510107 }; // Real result2a[] = { // 57.69082387657, // 38.50016858691, // 116.4056510107 }; testMultiple(process, "geometric Brownian", result2, result2a); processes[0] = new OrnsteinUhlenbeckProcess(0.1, 0.20); processes[1] = new OrnsteinUhlenbeckProcess(0.1, 0.20); processes[2] = new OrnsteinUhlenbeckProcess(0.1, 0.20); process = new StochasticProcessArray(processes, correlation); double[] result3 = { 0.2942058437284, 0.5525006418386, 0.02650931054575 }; double[] result3a = { -0.2942058437284, -0.5525006418386, -0.02650931054575 }; testMultiple(process, "Ornstein-Uhlenbeck", result3, result3a); processes[0] = new SquareRootProcess(0.1, 0.1, 0.20, 10.0); processes[1] = new SquareRootProcess(0.1, 0.1, 0.20, 10.0); processes[2] = new SquareRootProcess(0.1, 0.1, 0.20, 10.0); process = new StochasticProcessArray(processes, correlation); double[] result4 = { 4.279510844897, 4.943783503533, 3.590930385958 }; double[] result4a = { 2.763967737724, 2.226487196647, 3.503859264341 }; testMultiple(process, "square-root", result4, result4a); }
public void testEuropeanHaugValues() { // Testing double barrier european options against Haug's values Exercise.Type european = Exercise.Type.European; NewBarrierOptionData[] values = { /* The data below are from * "The complete guide to option pricing formulas 2nd Ed",E.G. Haug, McGraw-Hill, p.156 and following. * * Note: * The book uses b instead of q (q=r-b) */ // BarrierType, barr.lo, barr.hi, type, exercise,strk, s, q, r, t, v, result, tol new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3515, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 6.1644, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 7.0373, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 6.9853, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 7.9336, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 6.5088, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3505, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 5.8500, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 5.7726, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 6.8082, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 6.3383, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 4.3841, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 4.3139, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 4.8293, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 3.7765, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 5.9697, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 4.0004, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 2.2563, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 3.7516, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 2.6387, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 1.4903, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 3.5805, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 1.5098, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.5635, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.2055, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 0.3098, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 0.0477, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 0.5537, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 0.0441, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.0011, 1.0e-4), // BarrierType, barr.lo, barr.hi, type, exercise,strk, s, q, r, t, v, result, tol new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.8825, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 3.7855, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 5.7191, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 2.1374, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 4.7033, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 50.0, 150.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 7.1683, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.8825, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 3.7845, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 5.6060, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 2.1374, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 4.6236, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 60.0, 140.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 6.1062, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.8825, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 3.7014, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 4.6472, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 2.1325, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 3.8944, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 70.0, 130.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 3.5868, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 1.8600, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 2.6866, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 2.0719, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 1.8883, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 1.7851, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 80.0, 120.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.8244, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 0.9473, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 0.3449, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 0.0578, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 0.4555, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 0.0491, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockOut, 90.0, 110.0, Option.Type.Put, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 0.0013, 1.0e-4), // BarrierType, barr.lo, barr.hi, type, strk, s, q, r, t, v, result, tol new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 0.0000, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 0.0900, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 1.1537, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 0.0292, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 1.6487, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 50.0, 150.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 5.7321, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 0.0010, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 0.4045, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 2.4184, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 0.2062, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 3.2439, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 60.0, 140.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 7.8569, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 0.0376, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 1.4252, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 4.4145, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 1.0447, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 5.5818, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 70.0, 130.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 9.9846, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 0.5999, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 3.6158, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 6.7007, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 3.4340, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 8.0724, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 80.0, 120.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 11.6774, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.15, 3.1460, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.25, 5.9447, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.25, 0.35, 8.1432, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.15, 6.4608, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.25, 9.5382, 1.0e-4), new NewBarrierOptionData(DoubleBarrier.Type.KnockIn, 90.0, 110.0, Option.Type.Call, european, 100, 100.0, 0.0, 0.1, 0.50, 0.35, 12.2398, 1.0e-4), }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); for (int i = 0; i < values.Length; i++) { Date exDate = today + (int)(values[i].t * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); spot.setValue(values[i].s); qRate.setValue(values[i].q); rRate.setValue(values[i].r); vol.setValue(values[i].v); StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); DoubleBarrierOption opt = new DoubleBarrierOption(values[i].barrierType, values[i].barrierlo, values[i].barrierhi, 0, // no rebate payoff, exercise); // Ikeda/Kunitomo engine IPricingEngine engine = new AnalyticDoubleBarrierEngine(stochProcess); opt.setPricingEngine(engine); double calculated = opt.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE("Ikeda/Kunitomo value", values[i].barrierType, values[i].barrierlo, values[i].barrierhi, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } // Wulin Suo/Yong Wang engine engine = new WulinYongDoubleBarrierEngine(stochProcess); opt.setPricingEngine(engine); calculated = opt.NPV(); expected = values[i].result; error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE("Wulin/Yong value", values[i].barrierType, values[i].barrierlo, values[i].barrierhi, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } } }