void REPORT_FAILURE_FLOATING(string greekName, double minmax, FloatingTypePayoff payoff, Exercise exercise, double s, double q, double r, Date today, double v, double expected, double calculated, double error, double tolerance) { QAssert.Fail(exercise.GetType() + " " + payoff.optionType() + " lookback option with " + payoff + " payoff:\n" + " underlying value " + s + "\n" + " dividend yield: " + q + "\n" + " risk-free rate: " + r + "\n" + " reference date: " + today + "\n" + " maturity: " + exercise.lastDate() + "\n" + " volatility: " + v + "\n\n" + " expected " + greekName + ": " + expected + "\n" + " calculated " + greekName + ": " + calculated + "\n" + " error: " + error + "\n" + " tolerance: " + tolerance); }
public override void validate() { base.validate(); EuropeanExercise europeanExercise = exercise as EuropeanExercise; Utils.QL_REQUIRE(lookbackPeriodEnd <= europeanExercise.lastDate(), () => "lookback start date must be earlier than exercise date"); FloatingTypePayoff floatingTypePayoff = payoff as FloatingTypePayoff; if (floatingTypePayoff.optionType() == Option.Type.Call) { Utils.QL_REQUIRE(lambda >= 1.0, () => "lambda should be greater than or equal to 1 for calls"); } if (floatingTypePayoff.optionType() == Option.Type.Put) { Utils.QL_REQUIRE(lambda <= 1.0, () => "lambda should be smaller than or equal to 1 for puts"); } }
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 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 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); } } }