public void testEuroTwoValues() { // Testing two-asset European basket options... /* * Data from: * Excel spreadsheet www.maths.ox.ac.uk/~firth/computing/excel.shtml * and * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 56-58 * European two asset max basket options */ BasketOptionTwoData[] values = { // basketType, optionType, strike, s1, s2, q1, q2, r, t, v1, v2, rho, result, tol // data from http://www.maths.ox.ac.uk/~firth/computing/excel.shtml new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90, 10.898, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70, 8.483, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50, 6.844, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 5.531, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10, 4.413, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.70, 0.00, 4.981, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.30, 0.00, 4.159, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.10, 0.00, 2.597, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.50, 0.10, 0.50, 4.030, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90, 17.565, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70, 19.980, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50, 21.619, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 22.932, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10, 24.049, 1.1e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 80.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 16.508, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 80.0, 80.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 8.049, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 80.0, 120.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 30.141, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 100.0, 120.0, 120.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 42.889, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90, 11.369, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70, 12.856, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50, 13.890, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 14.741, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10, 15.485, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 0.50, 0.30, 0.30, 0.10, 11.893, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 0.25, 0.30, 0.30, 0.10, 8.881, 1.0e-3), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 2.00, 0.30, 0.30, 0.10, 19.268, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.90, 7.339, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.70, 5.853, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.50, 4.818, 1.0e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.30, 3.967, 1.1e-3), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 100.0, 100.0, 100.0, 0.00, 0.00, 0.05, 1.00, 0.30, 0.30, 0.10, 3.223, 1.0e-3), // basketType, optionType, strike, s1, s2, q1, q2, r, t, v1, v2, rho, result, tol // data from "Option pricing formulas" VB code + spreadsheet new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63, 4.8177, 1.0e-4), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63, 11.6323, 1.0e-4), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63, 2.0376, 1.0e-4), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 98.0, 100.0, 105.0, 0.00, 0.00, 0.05, 0.50, 0.11, 0.16, 0.63, 0.5731, 1.0e-4), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Call, 98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63, 2.9340, 1.0e-4), new BasketOptionTwoData(BasketType.MinBasket, Option.Type.Put, 98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63, 3.5224, 1.0e-4), // data from "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 58 new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Call, 98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63, 8.0701, 1.0e-4), new BasketOptionTwoData(BasketType.MaxBasket, Option.Type.Put, 98.0, 100.0, 105.0, 0.06, 0.09, 0.05, 0.50, 0.11, 0.16, 0.63, 1.2181, 1.0e-4), /* "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 59-60 * Kirk approx. for a european spread option on two futures*/ new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.20, -0.5, 4.7530, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.20, 0.0, 3.7970, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.20, 0.5, 2.5537, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.25, 0.20, -0.5, 5.4275, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.25, 0.20, 0.0, 4.3712, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.25, 0.20, 0.5, 3.0086, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.25, -0.5, 5.4061, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.25, 0.0, 4.3451, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.1, 0.20, 0.25, 0.5, 2.9723, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.20, -0.5, 10.7517, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.20, 0.0, 8.7020, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.20, 0.5, 6.0257, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.25, 0.20, -0.5, 12.1941, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.25, 0.20, 0.0, 9.9340, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.25, 0.20, 0.5, 7.0067, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.25, -0.5, 12.1483, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.25, 0.0, 9.8780, 1.0e-3), new BasketOptionTwoData(BasketType.SpreadBasket, Option.Type.Call, 3.0, 122.0, 120.0, 0.0, 0.0, 0.10, 0.5, 0.20, 0.25, 0.5, 6.9284, 1.0e-3) }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot1 = new SimpleQuote(0.0); SimpleQuote spot2 = new SimpleQuote(0.0); SimpleQuote qRate1 = new SimpleQuote(0.0); YieldTermStructure qTS1 = Utilities.flatRate(today, qRate1, dc); SimpleQuote qRate2 = new SimpleQuote(0.0); YieldTermStructure qTS2 = Utilities.flatRate(today, qRate2, dc); SimpleQuote rRate = new SimpleQuote(0.0); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol1 = new SimpleQuote(0.0); BlackVolTermStructure volTS1 = Utilities.flatVol(today, vol1, dc); SimpleQuote vol2 = new SimpleQuote(0.0); BlackVolTermStructure volTS2 = Utilities.flatVol(today, vol2, dc); //double mcRelativeErrorTolerance = 0.01; //double fdRelativeErrorTolerance = 0.01; for (int i = 0; i < values.Length; i++) { PlainVanillaPayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike); Date exDate = today + (int)(values[i].t * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); spot1.setValue(values[i].s1); spot2.setValue(values[i].s2); qRate1.setValue(values[i].q1); qRate2.setValue(values[i].q2); rRate.setValue(values[i].r); vol1.setValue(values[i].v1); vol2.setValue(values[i].v2); IPricingEngine analyticEngine = null; GeneralizedBlackScholesProcess p1 = null, p2 = null; switch (values[i].basketType) { case BasketType.MaxBasket: case BasketType.MinBasket: p1 = new BlackScholesMertonProcess(new Handle <Quote>(spot1), new Handle <YieldTermStructure>(qTS1), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS1)); p2 = new BlackScholesMertonProcess(new Handle <Quote>(spot2), new Handle <YieldTermStructure>(qTS2), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS2)); analyticEngine = new StulzEngine(p1, p2, values[i].rho); break; case BasketType.SpreadBasket: p1 = new BlackProcess(new Handle <Quote>(spot1), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS1)); p2 = new BlackProcess(new Handle <Quote>(spot2), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS2)); analyticEngine = new KirkEngine((BlackProcess)p1, (BlackProcess)p2, values[i].rho); break; default: Utils.QL_FAIL("unknown basket type"); break; } List <StochasticProcess1D> procs = new List <StochasticProcess1D> { p1, p2 }; Matrix correlationMatrix = new Matrix(2, 2, values[i].rho); for (int j = 0; j < 2; j++) { correlationMatrix[j, j] = 1.0; } StochasticProcessArray process = new StochasticProcessArray(procs, correlationMatrix); //IPricingEngine mcEngine = MakeMCEuropeanBasketEngine<PseudoRandom, Statistics>(process) // .withStepsPerYear(1) // .withSamples(10000) // .withSeed(42); //IPricingEngine fdEngine = new Fd2dBlackScholesVanillaEngine(p1, p2, values[i].rho, 50, 50, 15); BasketOption basketOption = new BasketOption(basketTypeToPayoff(values[i].basketType, payoff), exercise); // analytic engine basketOption.setPricingEngine(analyticEngine); double calculated = basketOption.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_2("value", values[i].basketType, payoff, exercise, values[i].s1, values[i].s2, values[i].q1, values[i].q2, values[i].r, today, values[i].v1, values[i].v2, values[i].rho, values[i].result, calculated, error, values[i].tol); } // // fd engine // basketOption.setPricingEngine(fdEngine); // calculated = basketOption.NPV(); // double relError = relativeError(calculated, expected, expected); // if (relError > mcRelativeErrorTolerance ) // { // REPORT_FAILURE_2("FD value", values[i].basketType, payoff, // exercise, values[i].s1, values[i].s2, // values[i].q1, values[i].q2, values[i].r, // today, values[i].v1, values[i].v2, values[i].rho, // values[i].result, calculated, relError, // fdRelativeErrorTolerance); // } //// mc engine //basketOption.setPricingEngine(mcEngine); //calculated = basketOption.NPV(); //relError = relativeError(calculated, expected, values[i].s1); //if (relError > mcRelativeErrorTolerance ) //{ // REPORT_FAILURE_2("MC value", values[i].basketType, payoff, // exercise, values[i].s1, values[i].s2, // values[i].q1, values[i].q2, values[i].r, // today, values[i].v1, values[i].v2, values[i].rho, // values[i].result, calculated, relError, // mcRelativeErrorTolerance); //} } }
public static object eqInstGetOptionGreeks( [ExcelArgument(Description = "id of option ")] string ObjectId, [ExcelArgument(Description = "Greek type ")] string gtype, [ExcelArgument(Description = "Option type (VANILLA or MULTIASSET)")] string otype, [ExcelArgument(Description = "trigger ")] object trigger) { if (ExcelUtil.CallFromWizard()) { return(""); } string callerAddress = ""; callerAddress = ExcelUtil.getActiveCellAddress(); try { Xl.Range rng = ExcelUtil.getActiveCellRange(); if (ExcelUtil.isNull(gtype)) { gtype = "NPV"; } if (ExcelUtil.isNull(otype)) { otype = "VANILLA"; } if (otype == "VANILLA") { VanillaOption option = OHRepository.Instance.getObject <VanillaOption>(ObjectId); switch (gtype.ToUpper()) { case "NPV": return(option.NPV()); case "DELTA": return(option.delta()); case "GAMMA": return(option.gamma()); case "VEGA": return(option.vega()); case "THETA": return(option.theta()); case "RHO": return(option.rho()); default: return(0); } } else if (otype == "MULTIASSET") { BasketOption option = OHRepository.Instance.getObject <BasketOption>(ObjectId); switch (gtype.ToUpper()) { case "NPV": return(option.NPV()); case "DELTA": return(option.delta()); case "GAMMA": return(option.gamma()); case "VEGA": return(option.vega()); case "THETA": return(option.theta()); case "RHO": return(option.rho()); default: return(0); } } else { return("Unknown option type"); } } catch (Exception e) { ExcelUtil.logError(callerAddress, System.Reflection.MethodInfo.GetCurrentMethod().Name.ToString(), e.Message); return("#EQ_ERR!"); } }