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); } }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackVolTermStructure obj) { return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; }
public void testAssetAtExpiryOrNothingAmericanValues() { // Testing American asset-(at-expiry)-or-nothing digital option DigitalOptionData[] values = { // type, strike, spot, q, r, t, vol, value, tol // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 7,8,11,12 new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 64.8426, 1e-04, true), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 77.7017, 1e-04, true), new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 40.1574, 1e-04, false), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 17.2983, 1e-04, false), // data from Haug VBA code results new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.01, 0.10, 0.5, 0.20, 65.5291, 1e-04, true), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.01, 0.10, 0.5, 0.20, 76.5951, 1e-04, true), // in the money options (guaranteed discounted payoff = forward * riskFreeDiscount // = spot * dividendDiscount) new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 105.0000, 1e-12, true), new DigitalOptionData(Option.Type.Put, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 95.0000, 1e-12, true), new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.01, 0.10, 0.5, 0.20, 105.0000 * Math.Exp(-0.005), 1e-12, true), new DigitalOptionData(Option.Type.Put, 100.00, 95.00, 0.01, 0.10, 0.5, 0.20, 95.0000 * Math.Exp(-0.005), 1e-12, true) }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.01); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.25); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new AssetOrNothingPayoff(values[i].type, values[i].strike); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise amExercise = new AmericanExercise(today, exDate, true); 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; if (values[i].knockin) { engine = new AnalyticDigitalAmericanEngine(stochProcess); } else { engine = new AnalyticDigitalAmericanKOEngine(stochProcess); } VanillaOption opt = new VanillaOption(payoff, amExercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, amExercise, 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 testCashOrNothingHaugValues() { // Testing cash-or-nothing barrier options against Haug's values BinaryOptionData[] values = { /* The data below are from * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 13,14,17,18,21,22,25,26 * Note: * q is the dividend rate, while the book gives b, the cost of carry (q=r-b) */ // barrierType, barrier, cash, type, strike, spot, q, r, t, vol, value, tol new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.9289, 1e-4), new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Call, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 6.2150, 1e-4), // following value is wrong in book. new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Call, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 5.8926, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Call, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 7.4519, 1e-4), // 17,18 new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Put, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.4314, 1e-4), new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Put, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 3.1454, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Put, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 5.3297, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Put, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.7704, 1e-4), // 21,22 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.8758, 1e-4), new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.9081, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Call, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Call, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0407, 1e-4), // 25,26 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0323, 1e-4), new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Put, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.0461, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Put, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.0054, 1e-4), // other values calculated with book vba new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Call, 102.00, 95.00, -0.14, 0.10, 0.5, 0.20, 8.6806, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Call, 102.00, 95.00, 0.03, 0.10, 0.5, 0.20, 5.3112, 1e-4), // degenerate conditions (barrier touched) new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Call, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 7.4926, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Call, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 11.1231, 1e-4), // 17,18 new BinaryOptionData(Barrier.Type.DownIn, 100.00, 15.00, Option.Type.Put, 102.00, 98.00, 0.00, 0.10, 0.5, 0.20, 7.1344, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 15.00, Option.Type.Put, 102.00, 101.00, 0.00, 0.10, 0.5, 0.20, 5.9299, 1e-4), // 21,22 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call, 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Call, 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), // 25,26 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put, 98.00, 99.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 15.00, Option.Type.Put, 98.00, 101.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.01); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.25); 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, values[i].cash); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise amExercise = new AmericanExercise(today, exDate, true); 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 AnalyticBinaryBarrierEngine(stochProcess); BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType, values[i].barrier, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, values[i].tol); } } }
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), // ATM option with very small volatility, reference value taken from R new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0021, 0.08032314), // ATM option with very small volatility, // reference value taken from Barone-Adesi and Whaley Approximation new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0001, 0.003860656), new AmericanOptionData(Option.Type.Call, 100, 99.99, 0.05, 0.05, 1.0, 0.0001, 0.00081), // ITM option with a very small volatility new AmericanOptionData(Option.Type.Call, 100, 110, 0.05, 0.05, 1.0, 0.0001, 10.0), new AmericanOptionData(Option.Type.Put, 110, 100, 0.05, 0.05, 1.0, 0.0001, 10.0), // ATM option with a very large volatility new AmericanOptionData(Option.Type.Put, 100, 110, 0.05, 0.05, 1.0, 10, 94.89543) }; 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 = 5.0e-5; 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 testCashAtHitOrNothingAmericanValues() { // Testing American cash-(at-hit)-or-nothing digital option DigitalOptionData[] values = { // type, strike, spot, q, r, t, vol, value, tol // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 1,2 new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 9.7264, 1e-4, true), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 11.6553, 1e-4, true), // the following cases are not taken from a reference paper or book // in the money options (guaranteed immediate payoff) new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 15.0000, 1e-16, true), new DigitalOptionData(Option.Type.Put, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 15.0000, 1e-16, true), // non null dividend (cross-tested with MC simulation) new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.20, 0.10, 0.5, 0.20, 12.2715, 1e-4, true), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.20, 0.10, 0.5, 0.20, 8.9109, 1e-4, true), new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.20, 0.10, 0.5, 0.20, 15.0000, 1e-16, true), new DigitalOptionData(Option.Type.Put, 100.00, 95.00, 0.20, 0.10, 0.5, 0.20, 15.0000, 1e-16, 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, 15.00); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise amExercise = 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 AnalyticDigitalAmericanEngine(stochProcess); VanillaOption opt = new VanillaOption(payoff, amExercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, amExercise, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, values[i].tol, values[i].knockin); } } }
//void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary<string,double> tolerance, // bool testGreeks = false) { void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary <string, double> tolerance, bool testGreeks) { //QL_TEST_START_TIMING Dictionary <string, double> calculated = new Dictionary <string, double>(), expected = new Dictionary <string, double>(); // test options Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] strikes = { 75.0, 100.0, 125.0 }; int[] lengths = { 1 }; // test data double[] underlyings = { 100.0 }; double[] qRates = { 0.00, 0.05 }; double[] rRates = { 0.01, 0.05, 0.15 }; double[] vols = { 0.11, 0.50, 1.20 }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote vol = new SimpleQuote(0.0); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); 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); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < strikes.Length; j++) { for (int k = 0; k < lengths.Length; k++) { Date exDate = today + lengths[k] * 360; Exercise exercise = new EuropeanExercise(exDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); // reference option VanillaOption refOption = makeOption(payoff, exercise, spot, qTS, rTS, volTS, EngineType.Analytic, 0, 0); // option to check VanillaOption option = makeOption(payoff, exercise, spot, qTS, rTS, volTS, engine, binomialSteps, samples); for (int l = 0; l < underlyings.Length; l++) { for (int m = 0; m < qRates.Length; m++) { for (int n = 0; n < rRates.Length; n++) { for (int p = 0; p < vols.Length; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); expected.Clear(); calculated.Clear(); // FLOATING_POINT_EXCEPTION expected.Add("value", refOption.NPV()); calculated.Add("value", option.NPV()); if (testGreeks && option.NPV() > spot.value() * 1.0e-5) { expected.Add("delta", refOption.delta()); expected.Add("gamma", refOption.gamma()); expected.Add("theta", refOption.theta()); calculated.Add("delta", option.delta()); calculated.Add("gamma", option.gamma()); calculated.Add("theta", option.theta()); } foreach (string greek in calculated.Keys) { double expct = expected[greek], calcl = calculated[greek], tol = tolerance[greek]; double error = Utilities.relativeError(expct, calcl, u); if (error > tol) { REPORT_FAILURE(greek, payoff, exercise, u, q, r, today, v, expct, calcl, error, tol); } } } } } } } } } }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackVolTermStructure obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }
GeneralizedBlackScholesProcess makeProcess(Quote u, YieldTermStructure q, YieldTermStructure r, BlackVolTermStructure vol) { return(new BlackScholesMertonProcess(new Handle <Quote>(u), new Handle <YieldTermStructure>(q), new Handle <YieldTermStructure>(r), new Handle <BlackVolTermStructure>(vol))); }
VanillaOption makeOption(StrikedTypePayoff payoff, Exercise exercise, Quote u, YieldTermStructure q, YieldTermStructure r, BlackVolTermStructure vol, EngineType engineType, int binomialSteps, int samples) { GeneralizedBlackScholesProcess stochProcess = makeProcess(u, q, r, vol); IPricingEngine engine; switch (engineType) { case EngineType.Analytic: engine = new AnalyticEuropeanEngine(stochProcess); break; case EngineType.JR: engine = new BinomialVanillaEngine <JarrowRudd>(stochProcess, binomialSteps); break; case EngineType.CRR: engine = new BinomialVanillaEngine <CoxRossRubinstein>(stochProcess, binomialSteps); break; case EngineType.EQP: engine = new BinomialVanillaEngine <AdditiveEQPBinomialTree>(stochProcess, binomialSteps); break; case EngineType.TGEO: engine = new BinomialVanillaEngine <Trigeorgis>(stochProcess, binomialSteps); break; case EngineType.TIAN: engine = new BinomialVanillaEngine <Tian>(stochProcess, binomialSteps); break; case EngineType.LR: engine = new BinomialVanillaEngine <LeisenReimer>(stochProcess, binomialSteps); break; case EngineType.JOSHI: engine = new BinomialVanillaEngine <Joshi4>(stochProcess, binomialSteps); break; case EngineType.FiniteDifferences: engine = new FDEuropeanEngine(stochProcess, binomialSteps, samples); break; case EngineType.Integral: engine = new IntegralEngine(stochProcess); break; //case EngineType.PseudoMonteCarlo: // engine = MakeMCEuropeanEngine<PseudoRandom>(stochProcess) // .withSteps(1) // .withSamples(samples) // .withSeed(42); // break; //case EngineType.QuasiMonteCarlo: // engine = MakeMCEuropeanEngine<LowDiscrepancy>(stochProcess) // .withSteps(1) // .withSamples(samples); // break; default: throw new ArgumentException("unknown engine type"); } VanillaOption option = new EuropeanOption(payoff, exercise); option.setPricingEngine(engine); return(option); }
public void testHaugValues() { // Testing cash-or-nothing double barrier options against Haug's values DoubleBinaryOptionData[] values = { /* The data below are from * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 181 * Note: book uses cost of carry b, instead of dividend rate q */ // barrierType, bar_lo, bar_hi, cash, spot, q, r, t, vol, value, tol new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 9.8716, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 8.9307, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 6.3272, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 1.9094, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 9.7961, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 7.2300, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 3.7100, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 0.4271, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 8.9054, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 3.6752, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 0.7960, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 0.0059, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 3.6323, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 0.0911, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 0.0002, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 0.2402, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 1.4076, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 3.8160, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0075, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 0.9910, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 2.8098, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 4.6612, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.2656, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 2.7954, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 4.4024, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 4.9266, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 2.6285, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 4.7523, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 4.9096, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 4.9675, 1e-4), // following values calculated with haug's VBA code new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0042, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 0.9450, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 3.5486, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 7.9663, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0797, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 2.6458, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 6.1658, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 9.4486, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.9704, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 6.2006, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 9.0798, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 9.8699, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 6.2434, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 9.7847, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 9.8756, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 9.8758, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0041, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 0.7080, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 2.1581, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 80.00, 120.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 4.2061, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.0723, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 1.6663, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 3.3930, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 85.00, 115.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 4.8679, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 0.7080, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 3.4424, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 4.7496, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 90.00, 110.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 5.0475, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.10, 3.6524, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.20, 5.1256, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.30, 5.0763, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 100.00, 0.02, 0.05, 0.25, 0.50, 5.0275, 1e-4), // degenerate cases new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 80.00, 0.02, 0.05, 0.25, 0.10, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockOut, 95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KnockIn, 95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 80.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KIKO, 95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 80.00, 0.02, 0.05, 0.25, 0.10, 0.0000, 1e-4), new DoubleBinaryOptionData(DoubleBarrier.Type.KOKI, 95.00, 105.00, 10.00, 110.00, 0.02, 0.05, 0.25, 0.10, 10.0000, 1e-4), }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.01); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.25); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new CashOrNothingPayoff(Option.Type.Call, 0, values[i].cash); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise exercise; if (values[i].barrierType == DoubleBarrier.Type.KIKO || values[i].barrierType == DoubleBarrier.Type.KOKI) { exercise = new AmericanExercise(today, exDate, true); } else { 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 AnalyticDoubleBarrierBinaryEngine(stochProcess); DoubleBarrierOption opt = new DoubleBarrierOption(values[i].barrierType, values[i].barrier_lo, values[i].barrier_hi, 0, payoff, exercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, exercise, values[i].barrierType, values[i].barrier_lo, values[i].barrier_hi, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, values[i].tol); } int steps = 500; // checking with binomial engine engine = new BinomialDoubleBarrierEngine( (d, end, step, strike) => new CoxRossRubinstein(d, end, step, strike), (args, process, grid) => new DiscretizedDoubleBarrierOption(args, process, grid), stochProcess, steps); opt.setPricingEngine(engine); calculated = opt.NPV(); expected = values[i].result; error = Math.Abs(calculated - expected); double tol = 0.22; if (error > tol) { REPORT_FAILURE("Binomial value", payoff, exercise, values[i].barrierType, values[i].barrier_lo, values[i].barrier_hi, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, tol); } } }
public void testKirkEngine() { // Testing Kirk approximation for spread options /* The example data below are from "complete guide to option * pricing formulas", Espen Gaarder Haug, p 60 * * Expected values of option theta were calculated using automatic * differentiation of the pricing function. The engine uses closed-form * formula */ Case[] cases = { new Case(28.0, 20.0, 7.0, 0.05, 0.29, 0.36, 0.42, 90, 2.1670, 3.0431), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5, 36, 4.7530, 25.5905), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.0, 36, 3.7970, 20.8841), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.5, 36, 2.5537, 14.7260), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, -0.5, 180, 10.7517, 10.0847), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.0, 180, 8.7020, 8.2619), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.20, 0.5, 180, 6.0257, 5.8661), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5, 36, 5.4275, 28.9013), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.0, 36, 4.3712, 23.7133), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.5, 36, 3.0086, 16.9864), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, -0.5, 180, 12.1941, 11.3603), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.0, 180, 9.9340, 9.3589), new Case(122.0, 120.0, 3.0, 0.10, 0.25, 0.20, 0.5, 180, 7.0067, 6.7463), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5, 36, 5.4061, 28.7963), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.0, 36, 4.3451, 23.5848), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.5, 36, 2.9723, 16.8060), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, -0.5, 180, 12.1483, 11.3200), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.0, 180, 9.8780, 9.3091), new Case(122.0, 120.0, 3.0, 0.10, 0.20, 0.25, 0.5, 180, 6.9284, 6.6761) }; for (int i = 0; i < cases.Length; ++i) { // First step: preparing the test values // Useful dates DayCounter dc = new Actual360(); Date today = Date.Today; Date exerciseDate = today + cases[i].length; // Futures values SimpleQuote F1 = new SimpleQuote(cases[i].F1); SimpleQuote F2 = new SimpleQuote(cases[i].F2); // Risk-free interest rate double riskFreeRate = cases[i].r; YieldTermStructure forwardRate = Utilities.flatRate(today, riskFreeRate, dc); // Correlation Quote rho = new SimpleQuote(cases[i].rho); // Volatilities double vol1 = cases[i].sigma1; double vol2 = cases[i].sigma2; BlackVolTermStructure volTS1 = Utilities.flatVol(today, vol1, dc); BlackVolTermStructure volTS2 = Utilities.flatVol(today, vol2, dc); // Black-Scholes Processes // The BlackProcess is the relevant class for futures contracts BlackProcess stochProcess1 = new BlackProcess(new Handle <Quote>(F1), new Handle <YieldTermStructure>(forwardRate), new Handle <BlackVolTermStructure>(volTS1)); BlackProcess stochProcess2 = new BlackProcess(new Handle <Quote>(F2), new Handle <YieldTermStructure>(forwardRate), new Handle <BlackVolTermStructure>(volTS2)); // Creating the pricing engine IPricingEngine engine = new KirkSpreadOptionEngine(stochProcess1, stochProcess2, new Handle <Quote>(rho)); // Finally, create the option: Option.Type type = Option.Type.Call; double strike = cases[i].X; PlainVanillaPayoff payoff = new PlainVanillaPayoff(type, strike); Exercise exercise = new EuropeanExercise(exerciseDate); SpreadOption option = new SpreadOption(payoff, exercise); option.setPricingEngine(engine); // And test the data double value = option.NPV(); double theta = option.theta(); double tolerance = 1e-4; if (Math.Abs(value - cases[i].value) > tolerance) { REPORT_FAILURE("value", payoff, exercise, cases[i].value, value, tolerance, today); } if (Math.Abs(theta - cases[i].theta) > tolerance) { REPORT_FAILURE("theta", payoff, exercise, cases[i].theta, theta, tolerance, today); } } }
public BlackVolTermStructure __deref__() { BlackVolTermStructure ret = new BlackVolTermStructure(NQuantLibcPINVOKE.BlackVolTermStructureHandle___deref__(swigCPtr), true); if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve(); return ret; }
public void testMonteCarloLookback() { double tolerance = 0.1; DayCounter dc = new Actual360(); Date today = Date.Today; double strike = 90; double t = 1; double t1 = 0.25; Date exDate = today + Convert.ToInt32(t * 360 + 0.5); Exercise exercise = new EuropeanExercise(exDate); 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); spot.setValue(100); qRate.setValue(0); rRate.setValue(0.06); vol.setValue(0.1); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); Option.Type[] types = new Option.Type[] { Option.Type.Call, Option.Type.Put }; for (int i = 0; i < types.Length; i++) { Option.Type type = types[i]; StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike); /** * Partial Fixed * **/ Date lookbackStart = today + Convert.ToInt32(t1 * 360 + 0.5); ContinuousPartialFixedLookbackOption partialFixedLookback = new ContinuousPartialFixedLookbackOption(lookbackStart, payoff, exercise); IPricingEngine engine = new AnalyticContinuousPartialFixedLookbackEngine(stochProcess); partialFixedLookback.setPricingEngine(engine); double analytical = partialFixedLookback.NPV(); IPricingEngine mcpartialfixedengine = new MakeMCLookbackEngine <ContinuousPartialFixedLookbackOption.Arguments, ContinuousPartialFixedLookbackOption.Results, PseudoRandom, Statistics>(stochProcess) .withSteps(2000) .withAntitheticVariate() .withSeed(1) .withAbsoluteTolerance(tolerance) .value(); partialFixedLookback.setPricingEngine(mcpartialfixedengine); double monteCarlo = partialFixedLookback.NPV(); double diff = Math.Abs(analytical - monteCarlo); if (diff > tolerance) { REPORT_FAILURE_MC("Partial Fixed", type, analytical, monteCarlo, tolerance); } /** * Fixed * **/ double minMax = 100; ContinuousFixedLookbackOption fixedLookback = new ContinuousFixedLookbackOption(minMax, payoff, exercise); IPricingEngine analyticalfixedengine = new AnalyticContinuousFixedLookbackEngine(stochProcess); fixedLookback.setPricingEngine(analyticalfixedengine); analytical = fixedLookback.NPV(); IPricingEngine mcfixedengine = new MakeMCLookbackEngine <ContinuousFixedLookbackOption.Arguments, ContinuousFixedLookbackOption.Results, PseudoRandom, Statistics>(stochProcess) .withSteps(2000) .withAntitheticVariate() .withSeed(1) .withAbsoluteTolerance(tolerance) .value(); fixedLookback.setPricingEngine(mcfixedengine); monteCarlo = fixedLookback.NPV(); diff = Math.Abs(analytical - monteCarlo); if (diff > tolerance) { REPORT_FAILURE_MC("Fixed", type, analytical, monteCarlo, tolerance); } /** * Partial Floating * **/ double lambda = 1; Date lookbackEnd = today + Convert.ToInt32(t1 * 360 + 0.5); FloatingTypePayoff floatingPayoff = new FloatingTypePayoff(type); ContinuousPartialFloatingLookbackOption partialFloating = new ContinuousPartialFloatingLookbackOption(minMax, lambda, lookbackEnd, floatingPayoff, exercise); IPricingEngine analyticalpartialFloatingengine = new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess); partialFloating.setPricingEngine(analyticalpartialFloatingengine); analytical = partialFloating.NPV(); IPricingEngine mcpartialfloatingengine = new MakeMCLookbackEngine <ContinuousPartialFloatingLookbackOption.Arguments, ContinuousPartialFloatingLookbackOption.Results, PseudoRandom, Statistics> (stochProcess) .withSteps(2000) .withAntitheticVariate() .withSeed(1) .withAbsoluteTolerance(tolerance) .value(); partialFloating.setPricingEngine(mcpartialfloatingengine); monteCarlo = partialFloating.NPV(); diff = Math.Abs(analytical - monteCarlo); if (diff > tolerance) { REPORT_FAILURE_MC("Partial Floating", type, analytical, monteCarlo, tolerance); } /** * Floating * **/ ContinuousFloatingLookbackOption floating = new ContinuousFloatingLookbackOption(minMax, floatingPayoff, exercise); IPricingEngine analyticalFloatingengine = new AnalyticContinuousFloatingLookbackEngine(stochProcess); floating.setPricingEngine(analyticalFloatingengine); analytical = floating.NPV(); IPricingEngine mcfloatingengine = new MakeMCLookbackEngine <ContinuousFloatingLookbackOption.Arguments, ContinuousFloatingLookbackOption.Results, PseudoRandom, Statistics> (stochProcess) .withSteps(2000) .withAntitheticVariate() .withSeed(1) .withAbsoluteTolerance(tolerance) .value(); floating.setPricingEngine(mcfloatingengine); monteCarlo = floating.NPV(); diff = Math.Abs(analytical - monteCarlo); if (diff > tolerance) { REPORT_FAILURE_MC("Floating", type, analytical, monteCarlo, tolerance); } } }
public RelinkableBlackVolTermStructureHandle(BlackVolTermStructure arg0) : this(NQuantLibcPINVOKE.new_RelinkableBlackVolTermStructureHandle__SWIG_0(BlackVolTermStructure.getCPtr(arg0)), true) { if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve(); }
public void testBSMOperatorConsistency() { //("Testing consistency of BSM operators..."); Vector grid = new Vector(10); double price = 20.0; double factor = 1.1; for (int i = 0; i < grid.size(); i++) { grid[i] = price; price *= factor; } double dx = Math.Log(factor); double r = 0.05; double q = 0.01; double sigma = 0.5; BSMOperator refer = new BSMOperator(grid.size(), dx, r, q, sigma); DayCounter dc = new Actual360(); Date today = Date.Today; Date exercise = today + new Period(2, TimeUnit.Years); double residualTime = dc.yearFraction(today, exercise); SimpleQuote spot = new SimpleQuote(0.0); YieldTermStructure qTS = Utilities.flatRate(today, q, dc); YieldTermStructure rTS = Utilities.flatRate(today, r, dc); BlackVolTermStructure volTS = Utilities.flatVol(today, sigma, dc); GeneralizedBlackScholesProcess stochProcess = new GeneralizedBlackScholesProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); BSMOperator op1 = new BSMOperator(grid, stochProcess, residualTime); PdeOperator <PdeBSM> op2 = new PdeOperator <PdeBSM>(grid, stochProcess, residualTime); double tolerance = 1.0e-6; Vector lderror = refer.lowerDiagonal() - op1.lowerDiagonal(); Vector derror = refer.diagonal() - op1.diagonal(); Vector uderror = refer.upperDiagonal() - op1.upperDiagonal(); for (int i = 2; i < grid.size() - 2; i++) { if (Math.Abs(lderror[i]) > tolerance || Math.Abs(derror[i]) > tolerance || Math.Abs(uderror[i]) > tolerance) { Assert.Fail("inconsistency between BSM operators:\n" + i + " row:\n" + "expected: " + refer.lowerDiagonal()[i] + ", " + refer.diagonal()[i] + ", " + refer.upperDiagonal()[i] + "\n" + "calculated: " + op1.lowerDiagonal()[i] + ", " + op1.diagonal()[i] + ", " + op1.upperDiagonal()[i]); } } lderror = refer.lowerDiagonal() - op2.lowerDiagonal(); derror = refer.diagonal() - op2.diagonal(); uderror = refer.upperDiagonal() - op2.upperDiagonal(); for (int i = 2; i < grid.size() - 2; i++) { if (Math.Abs(lderror[i]) > tolerance || Math.Abs(derror[i]) > tolerance || Math.Abs(uderror[i]) > tolerance) { Assert.Fail("inconsistency between BSM operators:\n" + i + " row:\n" + "expected: " + refer.lowerDiagonal()[i] + ", " + refer.diagonal()[i] + ", " + refer.upperDiagonal()[i] + "\n" + "calculated: " + op2.lowerDiagonal()[i] + ", " + op2.diagonal()[i] + ", " + op2.upperDiagonal()[i]); } } }
public void linkTo(BlackVolTermStructure arg0) { NQuantLibcPINVOKE.RelinkableBlackVolTermStructureHandle_linkTo(swigCPtr, BlackVolTermStructure.getCPtr(arg0)); if (NQuantLibcPINVOKE.SWIGPendingException.Pending) throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve(); }
public void testBaroneAdesiWhaleyValues() { // ("Testing Barone-Adesi and Whaley approximation for American options..."); /* The data below are from * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 24 * * The following values were replicated only up to the second digit * by the VB code provided by Haug, which was used as base for the * C++ implementation * */ AmericanOptionData[] values = { new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 0.0206), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8771), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 10.0089), new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 0.3159), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1280), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3919), new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 0.9495), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1679), new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 0.8208), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.8087), new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 2.7437), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8015), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 13.0170), new AmericanOptionData(Option.Type.Call, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 5.0063), new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5106), new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.5689), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.15, 10.0000), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15, 1.8770), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 0.0410), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.25, 10.2533), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25, 3.1277), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 0.4562), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.10, 0.35, 10.8787), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35, 4.3777), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 1.2402), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.15, 10.5595), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15, 4.0842), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 1.0822), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.25, 12.4419), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25, 6.8014), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 3.3226), new AmericanOptionData(Option.Type.Put, 100.00, 90.00, 0.10, 0.10, 0.50, 0.35, 14.6945), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35, 9.5104), new AmericanOptionData(Option.Type.Put, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 5.8823), new AmericanOptionData(Option.Type.Put, 100.00, 100.00, 0.00, 0.00, 0.50, 0.15, 4.22949) }; 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 BaroneAdesiWhaleyApproximationEngine(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 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 void testFdGreeks <Engine>() where Engine : IFDEngine, new() { using (SavedSettings backup = new SavedSettings()) { Dictionary <string, double> calculated = new Dictionary <string, double>(), expected = new Dictionary <string, double>(), tolerance = new Dictionary <string, double>(); tolerance.Add("delta", 7.0e-4); tolerance.Add("gamma", 2.0e-4); //tolerance["theta"] = 1.0e-4; Option.Type[] types = new Option.Type[] { Option.Type.Call, Option.Type.Put }; double[] strikes = { 50.0, 99.5, 100.0, 100.5, 150.0 }; double[] underlyings = { 100.0 }; double[] qRates = { 0.04, 0.05, 0.06 }; double[] rRates = { 0.01, 0.05, 0.15 }; int[] years = { 1, 2 }; double[] vols = { 0.11, 0.50, 1.20 }; Date today = Date.Today; Settings.setEvaluationDate(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); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < strikes.Length; j++) { for (int k = 0; k < years.Length; k++) { Date exDate = today + new Period(years[k], TimeUnit.Years); Exercise exercise = new AmericanExercise(today, exDate); StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new Engine().factory(stochProcess); VanillaOption option = new VanillaOption(payoff, exercise); option.setPricingEngine(engine); for (int l = 0; l < underlyings.Length; l++) { for (int m = 0; m < qRates.Length; m++) { for (int n = 0; n < rRates.Length; n++) { for (int p = 0; p < vols.Length; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); double value = option.NPV(); calculated.Add("delta", option.delta()); calculated.Add("gamma", option.gamma()); //calculated["theta"] = option.theta(); if (value > spot.value() * 1.0e-5) { // perturb spot and get delta and gamma double du = u * 1.0e-4; spot.setValue(u + du); double value_p = option.NPV(), delta_p = option.delta(); spot.setValue(u - du); double value_m = option.NPV(), delta_m = option.delta(); spot.setValue(u); expected.Add("delta", (value_p - value_m) / (2 * du)); expected.Add("gamma", (delta_p - delta_m) / (2 * du)); /* * // perturb date and get theta * Time dT = dc.yearFraction(today-1, today+1); * Settings::instance().setEvaluationDate(today-1); * value_m = option.NPV(); * Settings::instance().setEvaluationDate(today+1); * value_p = option.NPV(); * Settings::instance().setEvaluationDate(today); * expected["theta"] = (value_p - value_m)/dT; */ // compare foreach (string greek in calculated.Keys) { double expct = expected[greek], calcl = calculated[greek], tol = tolerance[greek]; double error = Utilities.relativeError(expct, calcl, u); if (error > tol) { REPORT_FAILURE(greek, payoff, exercise, u, q, r, today, v, expct, calcl, error, tol); } } } calculated.Clear(); expected.Clear(); } } } } } } } } }
public void testAnalyticContinuousFloatingLookback() { // Testing analytic continuous floating-strike lookback options LookbackOptionData[] values = { // data from "Option Pricing Formulas", Haug, 1998, pg.61-62 new LookbackOptionData(Option.Type.Call, 0, 100, 120.0, 0.06, 0.10, 0.50, 0.30, 0, 0, 25.3533, 1.0e-4), // data from "Connecting discrete and continuous path-dependent options", // Broadie, Glasserman & Kou, 1999, pg.70-74 new LookbackOptionData(Option.Type.Call, 0, 100, 100.0, 0.00, 0.05, 1.00, 0.30, 0, 0, 23.7884, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 100, 100.0, 0.00, 0.05, 0.20, 0.30, 0, 0, 10.7190, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 100, 110.0, 0.00, 0.05, 0.20, 0.30, 0, 0, 14.4597, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 15.3526, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 16.8468, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 120, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 21.0645, 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 + 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); FloatingTypePayoff payoff = new FloatingTypePayoff(values[i].type); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticContinuousFloatingLookbackEngine(stochProcess); ContinuousFloatingLookbackOption option = new ContinuousFloatingLookbackOption(values[i].minmax, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } } }
public void testCashAtExpiryOrNothingAmericanValues() { // Testing American cash-(at-expiry)-or-nothing digital option DigitalOptionData[] values = { // type, strike, spot, q, r, t, vol, value, tol // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 5,6,9,10 new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 9.3604, 1e-4, true), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 11.2223, 1e-4, true), new DigitalOptionData(Option.Type.Put, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 4.9081, 1e-4, false), new DigitalOptionData(Option.Type.Call, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 3.0461, 1e-4, false), // in the money options (guaranteed discounted payoff) new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20, 15.0000 * Math.Exp(-0.05), 1e-12, true), new DigitalOptionData(Option.Type.Put, 100.00, 95.00, 0.00, 0.10, 0.5, 0.20, 15.0000 * Math.Exp(-0.05), 1e-12, true), // out of bonds case new DigitalOptionData(Option.Type.Call, 2.37, 2.33, 0.07, 0.43, 0.19, 0.005, 0.0000, 1e-4, false), }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.01); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.25); 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, 15.0); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise amExercise = new AmericanExercise(today, exDate, true); 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; if (values[i].knockin) { engine = new AnalyticDigitalAmericanEngine(stochProcess); } else { engine = new AnalyticDigitalAmericanKOEngine(stochProcess); } VanillaOption opt = new VanillaOption(payoff, amExercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, amExercise, 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 testAnalyticContinuousFixedLookback() { // Testing analytic continuous fixed-strike lookback options LookbackOptionData[] values = { // data from "Option Pricing Formulas", Haug, 1998, pg.63-64 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 13.2687, 1.0e-4), new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 18.9263, 1.0e-4), new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 24.9857, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 8.5126, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 14.1702, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 20.2296, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 4.3908, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 9.8905, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 15.8512, 1.0e-4), new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 18.3241, 1.0e-4), new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 26.0731, 1.0e-4), new LookbackOptionData(Option.Type.Call, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 34.7116, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 13.8000, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 21.5489, 1.0e-4), new LookbackOptionData(Option.Type.Call, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 30.1874, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 9.5445, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 17.2965, 1.0e-4), new LookbackOptionData(Option.Type.Call, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 25.9002, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 0.6899, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 4.4448, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 8.9213, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 3.3917, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 8.3177, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 13.1579, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.10, 0, 0, 8.1478, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.20, 0, 0, 13.0739, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 0.50, 0.30, 0, 0, 17.9140, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 1.0534, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 6.2813, 1.0e-4), new LookbackOptionData(Option.Type.Put, 95, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 12.2376, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 3.8079, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 10.1294, 1.0e-4), new LookbackOptionData(Option.Type.Put, 100, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 16.3889, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.10, 0, 0, 8.3321, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.20, 0, 0, 14.6536, 1.0e-4), new LookbackOptionData(Option.Type.Put, 105, 100, 100.0, 0.00, 0.10, 1.00, 0.30, 0, 0, 20.9130, 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 + 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); 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)); IPricingEngine engine = new AnalyticContinuousFixedLookbackEngine(stochProcess); ContinuousFixedLookbackOption option = new ContinuousFixedLookbackOption(values[i].minmax, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } } }
public void testAssetOrNothingHaugValues() { // Testing asset-or-nothing barrier options against Haug's values BinaryOptionData[] values = { /* The data below are from * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 15,16,19,20,23,24,27,28 * Note: * q is the dividend rate, while the book gives b, the cost of carry (q=r-b) */ // barrierType, barrier, cash, type, strike, spot, q, r, t, vol, value, tol new BinaryOptionData(Barrier.Type.DownIn, 100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 37.2782, 1e-4), new BinaryOptionData(Barrier.Type.DownIn, 100.00, 0.00, Option.Type.Call, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 45.8530, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 0.00, Option.Type.Call, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 44.5294, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 0.00, Option.Type.Call, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 54.9262, 1e-4), // 19,20 new BinaryOptionData(Barrier.Type.DownIn, 100.00, 0.00, Option.Type.Put, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 27.5644, 1e-4), new BinaryOptionData(Barrier.Type.DownIn, 100.00, 0.00, Option.Type.Put, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 18.9896, 1e-4), // following value is wrong in book. new BinaryOptionData(Barrier.Type.UpIn, 100.00, 0.00, Option.Type.Put, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 33.1723, 1e-4), new BinaryOptionData(Barrier.Type.UpIn, 100.00, 0.00, Option.Type.Put, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 22.7755, 1e-4), // 23,24 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 39.9391, 1e-4), new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 40.1574, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 0.00, Option.Type.Call, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 0.00, Option.Type.Call, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 0.2676, 1e-4), // 27,28 new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.2183, 1e-4), new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put, 98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 0.0000, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 0.00, Option.Type.Put, 102.00, 95.00, 0.00, 0.10, 0.5, 0.20, 17.2983, 1e-4), new BinaryOptionData(Barrier.Type.UpOut, 100.00, 0.00, Option.Type.Put, 98.00, 95.00, 0.00, 0.10, 0.5, 0.20, 17.0306, 1e-4), }; DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.01); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.25); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); for (int i = 0; i < values.Length; i++) { StrikedTypePayoff payoff = new AssetOrNothingPayoff(values[i].type, values[i].strike); Date exDate = today + Convert.ToInt32(values[i].t * 360 + 0.5); Exercise amExercise = new AmericanExercise(today, exDate, true); 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 AnalyticBinaryBarrierEngine(stochProcess); BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise); opt.setPricingEngine(engine); double calculated = opt.NPV(); double error = Math.Abs(calculated - values[i].result); if (error > values[i].tol) { REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType, values[i].barrier, values[i].s, values[i].q, values[i].r, today, values[i].v, values[i].result, calculated, error, values[i].tol); } } }
public void testAnalyticContinuousPartialFloatingLookback() { // Testing analytic continuous partial floating-strike lookback options..."); LookbackOptionData[] values = { // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.146 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.25, 8.6524, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.5, 9.2128, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.75, 9.5567, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.25, 10.5751, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.5, 11.2601, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.75, 11.6804, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.25, 13.3402, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.5, 14.5121, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.75, 15.314, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.25, 16.3047, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.5, 17.737, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.75, 18.7171, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.25, 17.9831, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.5, 19.6618, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.75, 20.8493, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.25, 21.9793, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.5, 24.0311, 1.0e-4), new LookbackOptionData(Option.Type.Call, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.75, 25.4825, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.25, 2.7189, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.5, 3.4639, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.1, 1, 0.75, 4.1912, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.25, 3.3231, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.5, 4.2336, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.1, 1, 0.75, 5.1226, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.25, 7.9153, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.5, 9.5825, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.2, 1, 0.75, 11.0362, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.25, 9.6743, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.5, 11.7119, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.2, 1, 0.75, 13.4887, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.25, 13.4719, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.5, 16.1495, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 90, 90, 0, 0.06, 1, 0.3, 1, 0.75, 18.4071, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.25, 16.4657, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.5, 19.7383, 1.0e-4), new LookbackOptionData(Option.Type.Put, 0, 110, 110, 0, 0.06, 1, 0.3, 1, 0.75, 22.4976, 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 + 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); FloatingTypePayoff payoff = new FloatingTypePayoff(values[i].type); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess( new Handle <Quote>(spot), new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS), new Handle <BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticContinuousPartialFloatingLookbackEngine(stochProcess); Date lookbackEnd = today + Convert.ToInt32(values[i].t1 * 360 + 0.5); ContinuousPartialFloatingLookbackOption option = new ContinuousPartialFloatingLookbackOption( values[i].minmax, values[i].l, lookbackEnd, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_FLOATING("value", values[i].minmax, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } } }
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); } } }
public void testAnalyticContinuousPartialFixedLookback() { // Testing analytic continuous fixed-strike lookback options LookbackOptionData[] values = { // data from "Option Pricing Formulas, Second Edition", Haug, 2006, pg.148 //type, strike, minmax, s, q, r, t, v, l, t1, result, tol new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 20.2845, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.5, 19.6239, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75, 18.6244, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 4.0432, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.5, 3.958, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75, 3.7015, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 27.5385, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.5, 25.8126, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 23.4957, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 11.4895, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.5, 10.8995, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 9.8244, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 35.4578, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.5, 32.7172, 1.0e-4), new LookbackOptionData(Option.Type.Call, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 29.1473, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 19.725, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.5, 18.4025, 1.0e-4), new LookbackOptionData(Option.Type.Call, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 16.2976, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 0.4973, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.5, 0.4632, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75, 0.3863, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.25, 12.6978, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.5, 10.9492, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.1, 0, 0.75, 9.1555, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 4.5863, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.5, 4.1925, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 3.5831, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.25, 19.0255, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.5, 16.9433, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.2, 0, 0.75, 14.6505, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 9.9348, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.5, 9.1111, 1.0e-4), new LookbackOptionData(Option.Type.Put, 90, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 7.9267, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.25, 25.2112, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.5, 22.8217, 1.0e-4), new LookbackOptionData(Option.Type.Put, 110, 0, 100, 0, 0.06, 1, 0.3, 0, 0.75, 20.0566, 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 + 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); 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)); IPricingEngine engine = new AnalyticContinuousPartialFixedLookbackEngine(stochProcess); Date lookbackStart = today + Convert.ToInt32(values[i].t1 * 360 + 0.5); ContinuousPartialFixedLookbackOption option = new ContinuousPartialFixedLookbackOption(lookbackStart, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = values[i].result; double error = Math.Abs(calculated - expected); if (error > values[i].tol) { REPORT_FAILURE_FIXED("value", values[i].minmax, payoff, exercise, values[i].s, values[i].q, values[i].r, today, values[i].v, expected, calculated, error, values[i].tol); } } }
public RelinkableBlackVolTermStructureHandle(BlackVolTermStructure arg0) : this(NQuantLibcPINVOKE.new_RelinkableBlackVolTermStructureHandle__SWIG_0(BlackVolTermStructure.getCPtr(arg0)), true) { if (NQuantLibcPINVOKE.SWIGPendingException.Pending) { throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve(); } }
//! Detailed constructor public FXVolCurve(Date asof, FXVolatilityCurveSpec spec, Loader loader, CurveConfigurations curveConfigs, Dictionary <string, FXSpot> fxSpots, Dictionary <string, YieldCurve> yieldCurves) { try { FXVolatilityCurveConfig config = curveConfigs.FxVolCurveConfig(spec.CurveConfigID()); Utils.QL_REQUIRE(config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM || config.GetDimension() == FXVolatilityCurveConfig.Dimension.Smile, () => "Unkown FX curve building dimension"); bool isATM = config.GetDimension() == FXVolatilityCurveConfig.Dimension.ATM; // We loop over all market data, looking for quotes that match the configuration // every time we find a matching expiry we remove it from the list // we replicate this for all 3 types of quotes were applicable. int n = isATM ? 1 : 3; // [0] = ATM, [1] = RR, [2] = BF List <List <FXOptionQuote> > quotes = new List <List <FXOptionQuote> >(n); List <List <Period> > expiries = new InitializedList <List <Period> >(n, config.Expiries()); foreach (var md in loader.LoadQuotes(asof)) { // skip irrelevant data if (md.AsofDate() == asof && md.GetInstrumentType() == MarketDatum.InstrumentType.FX_OPTION) { FXOptionQuote q = md as FXOptionQuote; if (q.UnitCcy() == spec.UnitCcy() && q.Ccy() == spec.Ccy()) { int idx = 999999; if (q.Strike() == "ATM") { idx = 0; } else if (q.Strike() == "25RR") { idx = 1; } else if (q.Strike() == "25BF") { idx = 2; } // silently skip unknown strike strings if ((isATM && idx == 0) || (!isATM && idx <= 2)) { if (expiries[idx].Contains(q.Expiry())) //var it = std::find(expiries[idx].begin(), expiries[idx].end(), q->expiry()); //if (it != expiries[idx].end()) { // we have a hit quotes[idx].Add(q); // remove it from the list expiries[idx].Remove(q.Expiry()); } // check if we are done // for ATM we just check expiries[0], otherwise we check all 3 if (expiries[0].empty() && (isATM || (expiries[1].empty() && expiries[2].empty()))) { break; } } } } } // Check ATM first // Check that we have all the expiries we need //LOG("FXVolCurve: read " + quotes[0].Count + " ATM vols"); Utils.QL_REQUIRE(expiries[0].Count == 0, () => "No ATM quote found for spec " + spec + " with expiry " + expiries[0].First()); Utils.QL_REQUIRE(quotes[0].Count > 0, () => "No ATM quotes found for spec " + spec); // No check the rest if (!isATM) { //LOG("FXVolCurve: read " + quotes[1].Count + " RR and " + quotes[2].Count + " BF quotes"); Utils.QL_REQUIRE(expiries[1].Count == 0, () => "No RR quote found for spec " + spec + " with expiry " + expiries[1].First()); Utils.QL_REQUIRE(expiries[2].Count == 0, () => "No BF quote found for spec " + spec + " with expiry " + expiries[2].First()); } // daycounter used for interpolation in time. // TODO: push into conventions or config DayCounter dc = config.DayCounter(); Calendar cal = config.Calendar(); // sort all quotes for (int i = 0; i < n; i++) { // TODO!! //IComparer<FXOptionQuote> compare = //quotes[i] = quotes[i].Sort((a,b) => a.Expiry().CompareTo(b.Expiry())) } // build vol curve if (isATM && quotes[0].Count == 1) { _vol = new BlackConstantVol(asof, new Calendar(), quotes[0].First().Quote().link.value(), dc); } else { int numExpiries = quotes[0].Count; List <Date> dates = new List <Date>(numExpiries); List <List <double> > vols = new InitializedList <List <double> >(n, new List <double>(numExpiries)); // same as above: [0] = ATM, etc. for (int i = 0; i < numExpiries; i++) { dates[i] = asof + quotes[0][i].Expiry(); for (int idx = 0; idx < n; idx++) { vols[idx][i] = quotes[idx][i].Quote().link.value(); } } if (isATM) { // ATM _vol = new BlackVarianceCurve(asof, dates, vols[0], dc, false); } else { // Smile if (fxSpots.ContainsKey(config.FxSpotID()) && yieldCurves.ContainsKey(config.FxDomesticYieldCurveID()) && yieldCurves.ContainsKey(config.FxForeignYieldCurveID())) { var fxSpot = fxSpots[config.FxSpotID()]; // new Handle<Quote>(config.FxSpotID(), fxSpots); var domYTS = yieldCurves[config.FxDomesticYieldCurveID()]; var forYTS = yieldCurves[config.FxForeignYieldCurveID()]; // TODO!! //_vol = new QuantExt.FxBlackVannaVolgaVolatilitySurface(asof, dates, vols[0], vols[1], vols[2], dc, cal, fxSpot, domYTS, forYTS)); } else { Utils.QL_FAIL("FXVolCurve: Can't find spec " + spec); } } } _vol.enableExtrapolation(); } catch (Exception e) { Utils.QL_FAIL("fx vol curve building failed :" + e.Message); } }