示例#1
0
        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);
                }
            }
        }
示例#2
0
        public void testRegression()
        {
            // Testing fixed-coupon convertible bond in known regression case

            Date today    = new Date(23, Month.December, 2008);
            Date tomorrow = today + 1;

            Settings.Instance.setEvaluationDate(tomorrow);

            Handle <Quote> u = new Handle <Quote>(new SimpleQuote(2.9084382818797443));

            List <Date>   dates    = new InitializedList <Date>(25);
            List <double> forwards = new InitializedList <double>(25);

            dates[0]  = new Date(29, Month.December, 2008);  forwards[0] = 0.0025999342800;
            dates[1]  = new Date(5, Month.January, 2009);   forwards[1] = 0.0025999342800;
            dates[2]  = new Date(29, Month.January, 2009);   forwards[2] = 0.0053123275500;
            dates[3]  = new Date(27, Month.February, 2009);  forwards[3] = 0.0197049598721;
            dates[4]  = new Date(30, Month.March, 2009);     forwards[4] = 0.0220524845296;
            dates[5]  = new Date(29, Month.June, 2009);      forwards[5] = 0.0217076395643;
            dates[6]  = new Date(29, Month.December, 2009);  forwards[6] = 0.0230349627478;
            dates[7]  = new Date(29, Month.December, 2010);  forwards[7] = 0.0087631647476;
            dates[8]  = new Date(29, Month.December, 2011);  forwards[8] = 0.0219084299499;
            dates[9]  = new Date(31, Month.December, 2012);  forwards[9] = 0.0244798766219;
            dates[10] = new Date(30, Month.December, 2013);  forwards[10] = 0.0267885498456;
            dates[11] = new Date(29, Month.December, 2014);  forwards[11] = 0.0266922867562;
            dates[12] = new Date(29, Month.December, 2015);  forwards[12] = 0.0271052126386;
            dates[13] = new Date(29, Month.December, 2016);  forwards[13] = 0.0268829891648;
            dates[14] = new Date(29, Month.December, 2017);  forwards[14] = 0.0264594744498;
            dates[15] = new Date(31, Month.December, 2018);  forwards[15] = 0.0273450367424;
            dates[16] = new Date(30, Month.December, 2019);  forwards[16] = 0.0294852614749;
            dates[17] = new Date(29, Month.December, 2020);  forwards[17] = 0.0285556119719;
            dates[18] = new Date(29, Month.December, 2021);  forwards[18] = 0.0305557764659;
            dates[19] = new Date(29, Month.December, 2022);  forwards[19] = 0.0292244738422;
            dates[20] = new Date(29, Month.December, 2023);  forwards[20] = 0.0263917004194;
            dates[21] = new Date(29, Month.December, 2028);  forwards[21] = 0.0239626970243;
            dates[22] = new Date(29, Month.December, 2033);  forwards[22] = 0.0216417108090;
            dates[23] = new Date(29, Month.December, 2038);  forwards[23] = 0.0228343838422;
            dates[24] = new Date(31, Month.December, 2199);  forwards[24] = 0.0228343838422;

            Handle <YieldTermStructure> r = new Handle <YieldTermStructure>(new InterpolatedForwardCurve <BackwardFlat>(dates, forwards, new Actual360()));

            Handle <BlackVolTermStructure> sigma = new Handle <BlackVolTermStructure>(new BlackConstantVol(tomorrow, new NullCalendar(), 21.685235548092248,
                                                                                                           new Thirty360(Thirty360.Thirty360Convention.BondBasis)));

            BlackProcess process = new BlackProcess(u, r, sigma);

            Handle <Quote> spread = new Handle <Quote>(new SimpleQuote(0.11498700678012874));

            Date     issueDate    = new Date(23, Month.July, 2008);
            Date     maturityDate = new Date(1, Month.August, 2013);
            Calendar calendar     = new UnitedStates();
            Schedule schedule     = new MakeSchedule().from(issueDate)
                                    .to(maturityDate)
                                    .withTenor(new Period(6, TimeUnit.Months))
                                    .withCalendar(calendar)
                                    .withConvention(BusinessDayConvention.Unadjusted).value();
            int                 settlementDays  = 3;
            Exercise            exercise        = new EuropeanExercise(maturityDate);
            double              conversionRatio = 100.0 / 20.3175;
            List <double>       coupons         = new InitializedList <double>(schedule.size() - 1, 0.05);
            DayCounter          dayCounter      = new Thirty360(Thirty360.Thirty360Convention.BondBasis);
            CallabilitySchedule no_callability  = new CallabilitySchedule();
            DividendSchedule    no_dividends    = new DividendSchedule();
            double              redemption      = 100.0;

            ConvertibleFixedCouponBond bond = new ConvertibleFixedCouponBond(exercise, conversionRatio,
                                                                             no_dividends, no_callability,
                                                                             spread, issueDate, settlementDays,
                                                                             coupons, dayCounter,
                                                                             schedule, redemption);

            bond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein> (process, 600));

            try
            {
                double x = bond.NPV(); // should throw; if not, an INF was not detected.
                QAssert.Fail("INF result was not detected: " + x + " returned");
            }
            catch (Exception)
            {
                // as expected. Do nothing.

                // Note: we're expecting an Error we threw, not just any
                // exception.  If something else is thrown, then there's
                // another problem and the test must fail.
            }
        }
示例#3
0
        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);
                }
            }
        }
示例#4
0
        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);
                }
            }
        }
示例#5
0
        public void testVannaVolgaDoubleBarrierValues()
        {
            // Testing double-barrier FX options against Vanna/Volga values
            SavedSettings backup = new SavedSettings();

            DoubleBarrierFxOptionData[] values =
            {
                //                             BarrierType,                    barr.1, barr.2, rebate,         type,    strike,          s,         q,         r,  t, vol25Put,    volAtm,vol25Call,      vol,    result,   tol
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638,      0.14413, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088,      0.07456, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925,      0.02710, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463,      0.00569, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412,      0.00013, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638,      0.00017, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088,      0.00353, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925,      0.02221, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463,      0.06049, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412,      0.11103, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Call, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638,      0.14486, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Call, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088,      0.07534, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Call, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925,      0.02707, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Call, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463,      0.00536, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Call, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 4.14862e-005, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Put,  1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638,      0.00095, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Put,  1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088,      0.00437, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Put,  1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925,      0.02224, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Put,  1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463,      0.06021, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.1, 1.5, 0.0, Option.Type.Put,  1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412,      0.11100, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511,      0.19981, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890,      0.10389, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444,      0.03555, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197,      0.00634, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261,      0.00000, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511,      0.00000, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890,      0.00436, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444,      0.03173, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197,      0.09346, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261,      0.17704, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Call, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511,      0.20202, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Call, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890,      0.10521, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Call, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444,      0.03589, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Call, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197,      0.00601, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Call, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261,      0.00000, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Put,  1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511,      0.00153, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Put,  1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890,      0.00578, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Put,  1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444,      0.03218, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Put,  1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197,      0.09325, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockIn,  1.0, 1.6, 0.0, Option.Type.Put,  1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261,      0.17804, 1.0e-4)
            };

            DayCounter dc    = new Actual360();
            Date       today = new Date(05, Month.Mar, 2013);

            Settings.setEvaluationDate(today);

            SimpleQuote        spot      = new SimpleQuote(0.0);
            SimpleQuote        qRate     = new SimpleQuote(0.0);
            YieldTermStructure qTS       = Utilities.flatRate(today, qRate, dc);
            SimpleQuote        rRate     = new SimpleQuote(0.0);
            YieldTermStructure rTS       = Utilities.flatRate(today, rRate, dc);
            SimpleQuote        vol25Put  = new SimpleQuote(0.0);
            SimpleQuote        volAtm    = new SimpleQuote(0.0);
            SimpleQuote        vol25Call = new SimpleQuote(0.0);

            for (int i = 0; i < values.Length; i++)
            {
                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol25Put.setValue(values[i].vol25Put);
                volAtm.setValue(values[i].volAtm);
                vol25Call.setValue(values[i].vol25Call);

                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                Date     exDate   = today + (int)(values[i].t * 365 + 0.5);
                Exercise exercise = new EuropeanExercise(exDate);

                Handle <DeltaVolQuote> volAtmQuote = new Handle <DeltaVolQuote>(
                    new DeltaVolQuote(new Handle <Quote>(volAtm), DeltaVolQuote.DeltaType.Fwd, values[i].t,
                                      DeltaVolQuote.AtmType.AtmDeltaNeutral));

                //always delta neutral atm
                Handle <DeltaVolQuote> vol25PutQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(-0.25,
                                                                                                    new Handle <Quote>(vol25Put), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                Handle <DeltaVolQuote> vol25CallQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(0.25,
                                                                                                     new Handle <Quote>(vol25Call), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                DoubleBarrierOption doubleBarrierOption = new DoubleBarrierOption(values[i].barrierType,
                                                                                  values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise);

                double bsVanillaPrice = Utils.blackFormula(values[i].type, values[i].strike,
                                                           spot.value() * qTS.discount(values[i].t) / rTS.discount(values[i].t),
                                                           values[i].v * Math.Sqrt(values[i].t), rTS.discount(values[i].t));

                IPricingEngine vannaVolgaEngine;

                vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                     new Handle <Quote>(spot),
                                                                     new Handle <YieldTermStructure>(rTS),
                                                                     new Handle <YieldTermStructure>(qTS),
                                                                     (process, series) => new WulinYongDoubleBarrierEngine(process, series),
                                                                     true,
                                                                     bsVanillaPrice);
                doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                double calculated = doubleBarrierOption.NPV();
                double expected   = values[i].result;
                double error      = Math.Abs(calculated - expected);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                              values[i].barrier1, values[i].barrier2,
                                              values[i].rebate, payoff, exercise, values[i].s,
                                              values[i].q, values[i].r, today, values[i].vol25Put,
                                              values[i].volAtm, values[i].vol25Call, values[i].v,
                                              expected, calculated, error, values[i].tol);
                }

                vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                     new Handle <Quote> (spot),
                                                                     new Handle <YieldTermStructure> (rTS),
                                                                     new Handle <YieldTermStructure> (qTS),
                                                                     (process, series) => new AnalyticDoubleBarrierEngine(process, series),
                                                                     true,
                                                                     bsVanillaPrice);
                doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                calculated = doubleBarrierOption.NPV();
                expected   = values[i].result;
                error      = Math.Abs(calculated - expected);
                double maxtol = 5.0e-3; // different engines have somewhat different results
                if (error > maxtol)
                {
                    REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                              values[i].barrier1, values[i].barrier2,
                                              values[i].rebate, payoff, exercise, values[i].s,
                                              values[i].q, values[i].r, today, values[i].vol25Put,
                                              values[i].volAtm, values[i].vol25Call, values[i].v,
                                              expected, calculated, error, values[i].tol);
                }
            }
        }
示例#6
0
        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 testAnalyticHestonHullWhitePricing()
        {
            // Testing analytic Heston Hull-White option pricing
            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.Instance.setEvaluationDate(today);

            // construct a strange yield curve to check drifts and discounting
            // of the joint stochastic process

            List <Date>   dates = new List <Date>();
            List <double> times = new List <double>();
            List <double> rates = new List <double>(), divRates = new List <double>();

            for (int i = 0; i <= 40; ++i)
            {
                dates.Add(today + new Period(i, TimeUnit.Years));
                // FLOATING_POINT_EXCEPTION
                rates.Add(0.03 + 0.0001 * Math.Exp(Math.Sin(i / 4.0)));
                divRates.Add(0.02 + 0.0002 * Math.Exp(Math.Sin(i / 3.0)));
                times.Add(dc.yearFraction(today, dates.Last()));
            }

            Date           maturity         = today + new Period(5, TimeUnit.Years);
            Handle <Quote> s0               = new Handle <Quote>(new SimpleQuote(100));
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, rates, dc));
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, divRates, dc));

            HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, 0.08, 1.5, 0.0625, 0.5, -0.8);
            HestonModel   hestonModel   = new HestonModel(hestonProcess);

            HullWhiteForwardProcess hwFwdProcess = new HullWhiteForwardProcess(rTS, 0.01, 0.01);

            hwFwdProcess.setForwardMeasureTime(dc.yearFraction(today, maturity));
            HullWhite hullWhiteModel = new HullWhite(rTS, hwFwdProcess.a(), hwFwdProcess.sigma());

            double tol = 0.002;

            double[]      strike = { 80, 120 };
            Option.Type[] types  = { Option.Type.Put, Option.Type.Call };

            for (int i = 0; i < types.Length; ++i)
            {
                for (int j = 0; j < strike.Length; ++j)
                {
                    HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess,
                                                                                                 hwFwdProcess, 0.0, HybridHestonHullWhiteProcess.Discretization.Euler);

                    StrikedTypePayoff payoff   = new PlainVanillaPayoff(types[i], strike[j]);
                    Exercise          exercise = new EuropeanExercise(maturity);

                    VanillaOption optionHestonHW = new VanillaOption(payoff, exercise);
                    optionHestonHW.setPricingEngine(new MakeMCHestonHullWhiteEngine <PseudoRandom, Statistics>(jointProcess)
                                                    .withSteps(1)
                                                    .withAntitheticVariate()
                                                    .withControlVariate()
                                                    .withAbsoluteTolerance(tol)
                                                    .withSeed(42).getAsPricingEngine());

                    VanillaOption optionPureHeston = new VanillaOption(payoff, exercise);
                    optionPureHeston.setPricingEngine(new AnalyticHestonHullWhiteEngine(hestonModel, hullWhiteModel, 128));

                    double calculated = optionHestonHW.NPV();
                    double error      = optionHestonHW.errorEstimate();
                    double expected   = optionPureHeston.NPV();

                    if (Math.Abs(calculated - expected) > 3 * error &&
                        Math.Abs(calculated - expected) > tol)
                    {
                        QAssert.Fail("Failed to reproduce hw heston vanilla prices"
                                     + "\n   strike:     " + strike[j]
                                     + "\n   calculated: " + calculated
                                     + "\n   error:      " + error
                                     + "\n   expected:   " + expected);
                    }
                }
            }
        }
示例#8
0
        public void testFdEuropeanValues()
        {
            // Testing finite-difference dividend European option values...

            SavedSettings backup = new SavedSettings();

            double tolerance  = 1.0e-2;
            int    gridPoints = 300;
            int    timeSteps  = 40;

            Option.Type[] types       = { Option.Type.Call, Option.Type.Put };
            double[]      strikes     = { 50.0, 99.5, 100.0, 100.5, 150.0 };
            double[]      underlyings = { 100.0 };
            // Rate qRates[] = { 0.00, 0.10, 0.30 };
            // Analytic dividend may not be handling q correctly
            double[] qRates  = { 0.00 };
            double[] rRates  = { 0.01, 0.05, 0.15 };
            int[]    lengths = { 1, 2 };
            double[] vols    = { 0.05, 0.20, 0.40 };

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.setEvaluationDate(today);

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

            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 + new Period(lengths[k], TimeUnit.Years);
                        Exercise exercise = new EuropeanExercise(exDate);

                        List <Date>   dividendDates = new List <Date>();
                        List <double> dividends     = new List <double>();
                        for (Date d = today + new Period(3, TimeUnit.Months);
                             d < exercise.lastDate();
                             d += new Period(6, TimeUnit.Months))
                        {
                            dividendDates.Add(d);
                            dividends.Add(5.0);
                        }

                        StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]);

                        BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                               qTS, rTS, volTS);

                        IPricingEngine engine = new FDDividendEuropeanEngine(stochProcess, timeSteps, gridPoints);

                        IPricingEngine ref_engine = new AnalyticDividendEuropeanEngine(stochProcess);

                        DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);
                        option.setPricingEngine(engine);

                        DividendVanillaOption ref_option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);
                        ref_option.setPricingEngine(ref_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);
                                        // FLOATING_POINT_EXCEPTION
                                        double calculated = option.NPV();
                                        if (calculated > spot.value() * 1.0e-5)
                                        {
                                            double expected = ref_option.NPV();
                                            double error    = Math.Abs(calculated - expected);
                                            if (error > tolerance)
                                            {
                                                REPORT_FAILURE("value", payoff, exercise,
                                                               u, q, r, today, v,
                                                               expected, calculated,
                                                               error, tolerance);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public void testCompareBsmHWandHestonHW()
        {
            // Comparing European option pricing for a BSM process with one-factor Hull-White model
            DayCounter dc    = new Actual365Fixed();
            Date       today = Date.Today;

            Settings.Instance.setEvaluationDate(today);

            Handle <Quote> spot = new Handle <Quote>(new SimpleQuote(100.0));
            List <Date>    dates = new List <Date>();
            List <double>  rates = new List <double>(), divRates = new List <double>();

            for (int i = 0; i <= 40; ++i)
            {
                dates.Add(today + new Period(i, TimeUnit.Years));
                // FLOATING_POINT_EXCEPTION
                rates.Add(0.01 + 0.0002 * Math.Exp(Math.Sin(i / 4.0)));
                divRates.Add(0.02 + 0.0001 * Math.Exp(Math.Sin(i / 5.0)));
            }

            Handle <Quote> s0               = new Handle <Quote>(new SimpleQuote(100));
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(
                new InterpolatedZeroCurve <Linear>(dates, rates, dc));
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(
                new InterpolatedZeroCurve <Linear>(dates, divRates, dc));

            SimpleQuote vol = new SimpleQuote(0.25);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, vol, dc));

            BlackScholesMertonProcess bsmProcess = new BlackScholesMertonProcess(spot, qTS, rTS, volTS);

            HestonProcess hestonProcess = new HestonProcess(rTS, qTS, spot,
                                                            vol.value() * vol.value(), 1.0, vol.value() * vol.value(), 1e-4, 0.0);

            HestonModel hestonModel = new HestonModel(hestonProcess);

            HullWhite hullWhiteModel = new HullWhite(new Handle <YieldTermStructure>(rTS), 0.01, 0.01);

            IPricingEngine bsmhwEngine = new AnalyticBSMHullWhiteEngine(0.0, bsmProcess, hullWhiteModel);

            IPricingEngine hestonHwEngine = new AnalyticHestonHullWhiteEngine(hestonModel, hullWhiteModel, 128);

            double tol = 1e-5;

            double[]      strike   = { 0.25, 0.5, 0.75, 0.8, 0.9, 1.0, 1.1, 1.2, 1.5, 2.0, 4.0 };
            int[]         maturity = { 1, 2, 3, 5, 10, 15, 20, 25, 30 };
            Option.Type[] types    = { Option.Type.Put, Option.Type.Call };

            for (int i = 0; i < types.Length; ++i)
            {
                for (int j = 0; j < strike.Length; ++j)
                {
                    for (int l = 0; l < maturity.Length; ++l)
                    {
                        Date maturityDate = today + new Period(maturity[l], TimeUnit.Years);

                        Exercise exercise = new EuropeanExercise(maturityDate);

                        double fwd = strike[j] * spot.link.value()
                                     * qTS.link.discount(maturityDate) / rTS.link.discount(maturityDate);

                        StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], fwd);

                        EuropeanOption option = new EuropeanOption(payoff, exercise);

                        option.setPricingEngine(bsmhwEngine);
                        double calculated = option.NPV();

                        option.setPricingEngine(hestonHwEngine);
                        double expected = option.NPV();

                        if (Math.Abs(calculated - expected) > calculated * tol &&
                            Math.Abs(calculated - expected) > tol)
                        {
                            QAssert.Fail("Failed to reproduce npvs"
                                         + "\n    calculated: " + calculated
                                         + "\n    expected  : " + expected
                                         + "\n    strike    : " + strike[j]
                                         + "\n    maturity  : " + maturity[l]
                                         + "\n    type      : "
                                         + ((types[i] == QLCore.Option.Type.Put) ? "Put" : "Call"));
                        }
                    }
                }
            }
        }
        public void testBsmHullWhiteEngine()
        {
            // Testing European option pricing for a BSM process with one-factor Hull-White model
            DayCounter dc = new Actual365Fixed();

            Date today    = Date.Today;
            Date maturity = today + new Period(20, TimeUnit.Years);

            Settings.Instance.setEvaluationDate(today);

            Handle <Quote> spot             = new Handle <Quote>(new SimpleQuote(100.0));
            SimpleQuote    qRate            = new SimpleQuote(0.04);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0525);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.25);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, vol, dc));

            // FLOATING_POINT_EXCEPTION
            HullWhite hullWhiteModel = new HullWhite(new Handle <YieldTermStructure>(rTS), 0.00883, 0.00526);

            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(spot, qTS, rTS, volTS);

            Exercise exercise = new EuropeanExercise(maturity);

            double            fwd    = spot.link.value() * qTS.link.discount(maturity) / rTS.link.discount(maturity);
            StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, fwd);

            EuropeanOption option = new EuropeanOption(payoff, exercise);

            double tol = 1e-8;

            double[] corr        = { -0.75, -0.25, 0.0, 0.25, 0.75 };
            double[] expectedVol = { 0.217064577, 0.243995801, 0.256402830, 0.268236596, 0.290461343 };

            for (int i = 0; i < corr.Length; ++i)
            {
                IPricingEngine bsmhwEngine = new AnalyticBSMHullWhiteEngine(corr[i], stochProcess, hullWhiteModel);

                option.setPricingEngine(bsmhwEngine);
                double npv = option.NPV();

                Handle <BlackVolTermStructure> compVolTS = new Handle <BlackVolTermStructure>(
                    Utilities.flatVol(today, expectedVol[i], dc));

                BlackScholesMertonProcess bsProcess = new BlackScholesMertonProcess(spot, qTS, rTS, compVolTS);
                IPricingEngine            bsEngine  = new AnalyticEuropeanEngine(bsProcess);

                EuropeanOption comp = new EuropeanOption(payoff, exercise);
                comp.setPricingEngine(bsEngine);

                double impliedVol = comp.impliedVolatility(npv, bsProcess, 1e-10, 100);

                if (Math.Abs(impliedVol - expectedVol[i]) > tol)
                {
                    QAssert.Fail("Failed to reproduce implied volatility"
                                 + "\n    calculated: " + impliedVol
                                 + "\n    expected  : " + expectedVol[i]);
                }
                if (Math.Abs((comp.NPV() - npv) / npv) > tol)
                {
                    QAssert.Fail("Failed to reproduce NPV"
                                 + "\n    calculated: " + npv
                                 + "\n    expected  : " + comp.NPV());
                }
                if (Math.Abs(comp.delta() - option.delta()) > tol)
                {
                    QAssert.Fail("Failed to reproduce NPV"
                                 + "\n    calculated: " + npv
                                 + "\n    expected  : " + comp.NPV());
                }
                if (Math.Abs((comp.gamma() - option.gamma()) / npv) > tol)
                {
                    QAssert.Fail("Failed to reproduce NPV"
                                 + "\n    calculated: " + npv
                                 + "\n    expected  : " + comp.NPV());
                }
                if (Math.Abs((comp.theta() - option.theta()) / npv) > tol)
                {
                    QAssert.Fail("Failed to reproduce NPV"
                                 + "\n    calculated: " + npv
                                 + "\n    expected  : " + comp.NPV());
                }
                if (Math.Abs((comp.vega() - option.vega()) / npv) > tol)
                {
                    QAssert.Fail("Failed to reproduce NPV"
                                 + "\n    calculated: " + npv
                                 + "\n    expected  : " + comp.NPV());
                }
            }
        }
示例#11
0
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;

            Option.Type optionType      = Option.Type.Put;
            double      underlyingPrice = 36;
            double      strikePrice     = 40;
            double      dividendYield   = 0.0;
            double      riskFreeRate    = 0.06;
            double      volatility      = 0.2;

            Date todaysDate = new Date(17, Month.May, 1998);

            Settings.instance().setEvaluationDate(todaysDate);

            Date settlementDate = new Date(17, Month.May, 1998);
            Date maturityDate   = new Date(17, Month.May, 1999);

            Calendar calendar = new TARGET();

            DateVector exerciseDates = new DateVector(4);

            for (int i = 1; i <= 4; i++)
            {
                Period forwardPeriod = new Period(3 * i, TimeUnit.Months);
                Date   forwardDate   = settlementDate.Add(forwardPeriod);
                exerciseDates.Add(forwardDate);
            }

            EuropeanExercise europeanExercise =
                new EuropeanExercise(maturityDate);
            BermudanExercise bermudanExercise =
                new BermudanExercise(exerciseDates);
            AmericanExercise americanExercise =
                new AmericanExercise(settlementDate, maturityDate);

            // bootstrap the yield/dividend/vol curves and create a
            // BlackScholesMerton stochastic process
            DayCounter dayCounter = new Actual365Fixed();
            YieldTermStructureHandle flatRateTSH =
                new YieldTermStructureHandle(
                    new FlatForward(settlementDate, riskFreeRate,
                                    dayCounter));
            YieldTermStructureHandle flatDividendTSH =
                new YieldTermStructureHandle(
                    new FlatForward(settlementDate, dividendYield,
                                    dayCounter));
            BlackVolTermStructureHandle flatVolTSH =
                new BlackVolTermStructureHandle(
                    new BlackConstantVol(settlementDate, calendar,
                                         volatility, dayCounter));

            QuoteHandle underlyingQuoteH =
                new QuoteHandle(new SimpleQuote(underlyingPrice));
            BlackScholesMertonProcess stochasticProcess =
                new BlackScholesMertonProcess(underlyingQuoteH,
                                              flatDividendTSH,
                                              flatRateTSH,
                                              flatVolTSH);

            PlainVanillaPayoff payoff =
                new PlainVanillaPayoff(optionType, strikePrice);

            // options
            VanillaOption europeanOption =
                new VanillaOption(payoff, europeanExercise);
            VanillaOption bermudanOption =
                new VanillaOption(payoff, bermudanExercise);
            VanillaOption americanOption =
                new VanillaOption(payoff, americanExercise);

            // report the parameters we are using
            ReportParameters(optionType, underlyingPrice, strikePrice,
                             dividendYield, riskFreeRate,
                             volatility, maturityDate);

            // write out the column headings
            ReportHeadings();

            #region Analytic Formulas

            // Black-Scholes for European
            try {
                europeanOption.setPricingEngine(
                    new AnalyticEuropeanEngine(stochasticProcess));
                ReportResults("Black-Scholes",
                              europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Barone-Adesi and Whaley approximation for American
            try {
                americanOption.setPricingEngine(
                    new BaroneAdesiWhaleyEngine(stochasticProcess));
                ReportResults("Barone-Adesi/Whaley",
                              null, null, americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Bjerksund and Stensland approximation for American
            try {
                americanOption.setPricingEngine(
                    new BjerksundStenslandEngine(stochasticProcess));
                ReportResults("Bjerksund/Stensland",
                              null, null, americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Integral
            try {
                europeanOption.setPricingEngine(
                    new IntegralEngine(stochasticProcess));
                ReportResults("Integral",
                              europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            uint timeSteps = 801;

            // Finite differences
            try {
                europeanOption.setPricingEngine(
                    new FDEuropeanEngine(stochasticProcess,
                                         timeSteps, timeSteps - 1));
                bermudanOption.setPricingEngine(
                    new FDBermudanEngine(stochasticProcess,
                                         timeSteps, timeSteps - 1));
                americanOption.setPricingEngine(
                    new FDAmericanEngine(stochasticProcess,
                                         timeSteps, timeSteps - 1));
                ReportResults("Finite differences",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            //Variance Gamma
            try
            {
                VarianceGammaProcess vgProcess = new VarianceGammaProcess(underlyingQuoteH,
                                                                          flatDividendTSH,
                                                                          flatRateTSH,
                                                                          volatility, 0.01, 0.0
                                                                          );
                europeanOption.setPricingEngine(
                    new VarianceGammaEngine(vgProcess));
                ReportResults("Variance-Gamma",
                              europeanOption.NPV(), null, null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            #endregion Analytic Formulas

            #region Binomial Methods

            // Binomial Jarrow-Rudd
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "jarrowrudd", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "jarrowrudd", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "jarrowrudd", timeSteps));
                ReportResults("Binomial Jarrow-Rudd",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Cox-Ross-Rubinstein
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "coxrossrubinstein", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "coxrossrubinstein", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "coxrossrubinstein", timeSteps));
                ReportResults("Binomial Cox-Ross-Rubinstein",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Additive Equiprobabilities
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "eqp", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "eqp", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "eqp", timeSteps));
                ReportResults("Additive Equiprobabilities",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Trigeorgis
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "trigeorgis", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "trigeorgis", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "trigeorgis", timeSteps));
                ReportResults("Binomial Trigeorgis",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Tian
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "tian", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "tian", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "tian", timeSteps));
                ReportResults("Binomial Tian",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Leisen-Reimer
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "leisenreimer", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "leisenreimer", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "leisenreimer", timeSteps));
                ReportResults("Binomial Leisen-Reimer",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // Binomial Joshi
            try {
                europeanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "joshi4", timeSteps));
                bermudanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "joshi4", timeSteps));
                americanOption.setPricingEngine(
                    new BinomialVanillaEngine(stochasticProcess,
                                              "joshi4", timeSteps));
                ReportResults("Binomial Joshi",
                              europeanOption.NPV(),
                              bermudanOption.NPV(),
                              americanOption.NPV());
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            #endregion Binomial Methods

            #region Monte Carlo Methods

            // quantlib appears to use max numeric (int and real) values to test for 'null' (or rather 'default') values

            // MC (crude)
            try {
                string traits            = "pseudorandom";
                int    mcTimeSteps       = 1;
                int    timeStepsPerYear  = int.MaxValue;
                bool   brownianBridge    = false;
                bool   antitheticVariate = false;
                int    requiredSamples   = int.MaxValue;
                double requiredTolerance = 1e-2;
                int    maxSamples        = int.MaxValue;
                int    seed = 42;
                europeanOption.setPricingEngine(
                    new MCEuropeanEngine(stochasticProcess,
                                         traits, mcTimeSteps,
                                         timeStepsPerYear,
                                         brownianBridge,
                                         antitheticVariate,
                                         requiredSamples,
                                         requiredTolerance,
                                         maxSamples, seed));
                ReportResults("MC (crude)", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // MC (Sobol)
            try {
                string traits            = "lowdiscrepancy";
                int    mcTimeSteps       = 1;
                int    timeStepsPerYear  = int.MaxValue;
                bool   brownianBridge    = false;
                bool   antitheticVariate = false;
                int    requiredSamples   = 32768; // 2^15
                double requiredTolerance = 1e-2;  //double.MaxValue;
                int    maxSamples        = int.MaxValue;
                int    seed = 0;
                europeanOption.setPricingEngine(
                    new MCEuropeanEngine(stochasticProcess,
                                         traits, mcTimeSteps,
                                         timeStepsPerYear,
                                         brownianBridge,
                                         antitheticVariate,
                                         requiredSamples,
                                         requiredTolerance, maxSamples, seed));
                ReportResults("MC (Sobol)", europeanOption.NPV(), null, null);
            }
            catch (Exception e) {
                Console.WriteLine(e.ToString());
            }

            // MC (Longstaff Schwartz)

            /*
             * try {
             *  // MCAmericanEngine is not currently exposed in SWIG
             *  //americanOption.setPricingEngine(new MCAmericanEngine());
             *  ReportResults("MC (Longstaff Schwartz)", null, null, null);
             * }
             * catch (Exception e) {
             *  Console.WriteLine(e.ToString());
             * }
             */

            #endregion Monte Carlo Methods

            DateTime endTime = DateTime.Now;
            TimeSpan delta   = endTime - startTime;
            Console.WriteLine();
            Console.WriteLine("Run completed in {0} s", delta.TotalSeconds);
            Console.WriteLine();
        }
示例#12
0
        private void testOptionGreeks(ForwardVanillaEngine.GetOriginalEngine getEngine)
        {
            SavedSettings backup = new SavedSettings();

            Dictionary <String, double> calculated = new Dictionary <string, double>(),
                                        expected   = new Dictionary <string, double>(),
                                        tolerance  = new Dictionary <string, double>();

            tolerance["delta"]  = 1.0e-5;
            tolerance["gamma"]  = 1.0e-5;
            tolerance["theta"]  = 1.0e-5;
            tolerance["rho"]    = 1.0e-5;
            tolerance["divRho"] = 1.0e-5;
            tolerance["vega"]   = 1.0e-5;

            Option.Type[] types       = { Option.Type.Call, Option.Type.Put };
            double[]      moneyness   = { 0.9, 1.0, 1.1 };
            double[]      underlyings = { 100.0 };
            double[]      qRates      = { 0.04, 0.05, 0.06 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            int[]         lengths     = { 1, 2 };
            Frequency[]   frequencies = { Frequency.Semiannual, Frequency.Quarterly, };
            double[]      vols        = { 0.11, 0.50, 1.20 };

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.setEvaluationDate(today);

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

            BlackScholesMertonProcess process = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS);

            for (int i = 0; i < types.Length; i++)
            {
                for (int j = 0; j < moneyness.Length; j++)
                {
                    for (int k = 0; k < lengths.Length; k++)
                    {
                        for (int kk = 0; kk < frequencies.Length; kk++)
                        {
                            EuropeanExercise maturity = new EuropeanExercise(today + new Period(lengths[k], TimeUnit.Years));

                            PercentageStrikePayoff payoff = new PercentageStrikePayoff(types[i], moneyness[j]);

                            List <Date> reset = new List <Date>();
                            for (Date d = today + new Period(frequencies[kk]);
                                 d < maturity.lastDate();
                                 d += new Period(frequencies[kk]))
                            {
                                reset.Add(d);
                            }

                            IPricingEngine engine = getEngine(process);

                            CliquetOption option = new CliquetOption(payoff, maturity, reset);
                            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["delta"]  = option.delta();
                                            calculated["gamma"]  = option.gamma();
                                            calculated["theta"]  = option.theta();
                                            calculated["rho"]    = option.rho();
                                            calculated["divRho"] = option.dividendRho();
                                            calculated["vega"]   = option.vega();

                                            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["delta"] = (value_p - value_m) / (2 * du);
                                                expected["gamma"] = (delta_p - delta_m) / (2 * du);

                                                // perturb rates and get rho and dividend rho
                                                double dr = r * 1.0e-4;
                                                rRate.setValue(r + dr);
                                                value_p = option.NPV();
                                                rRate.setValue(r - dr);
                                                value_m = option.NPV();
                                                rRate.setValue(r);
                                                expected["rho"] = (value_p - value_m) / (2 * dr);

                                                double dq = q * 1.0e-4;
                                                qRate.setValue(q + dq);
                                                value_p = option.NPV();
                                                qRate.setValue(q - dq);
                                                value_m = option.NPV();
                                                qRate.setValue(q);
                                                expected["divRho"] = (value_p - value_m) / (2 * dq);

                                                // perturb volatility and get vega
                                                double dv = v * 1.0e-4;
                                                vol.setValue(v + dv);
                                                value_p = option.NPV();
                                                vol.setValue(v - dv);
                                                value_m = option.NPV();
                                                vol.setValue(v);
                                                expected["vega"] = (value_p - value_m) / (2 * dv);

                                                // perturb date and get theta
                                                double dT = dc.yearFraction(today - 1, today + 1);
                                                Settings.setEvaluationDate(today - 1);
                                                value_m = option.NPV();
                                                Settings.setEvaluationDate(today + 1);
                                                value_p = option.NPV();
                                                Settings.setEvaluationDate(today);
                                                expected["theta"] = (value_p - value_m) / dT;

                                                // compare
                                                foreach (var it in calculated)
                                                {
                                                    String greek = it.Key;
                                                    double expct = expected  [greek],
                                                           calcl = calculated[greek],
                                                           tol   = tolerance [greek];
                                                    double error = Utilities.relativeError(expct, calcl, u);
                                                    if (error > tol)
                                                    {
                                                        REPORT_FAILURE(greek, payoff, maturity,
                                                                       u, q, r, today, v,
                                                                       expct, calcl, error, tol);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(EuropeanExercise obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
示例#14
0
        static void Main(string[] args)
        {
            DateTime timer = DateTime.Now;

            // set up dates
            Calendar calendar       = new TARGET();
            Date     todaysDate     = new Date(15, Month.May, 1998);
            Date     settlementDate = new Date(17, Month.May, 1998);

            Settings.setEvaluationDate(todaysDate);

            // our options
            Option.Type type          = Option.Type.Put;
            double      underlying    = 36;
            double      strike        = 40;
            double      dividendYield = 0.00;
            double      riskFreeRate  = 0.06;
            double      volatility    = 0.20;
            Date        maturity      = new Date(17, Month.May, 1999);
            DayCounter  dayCounter    = new Actual365Fixed();

            Console.WriteLine("Option type = " + type);
            Console.WriteLine("Maturity = " + maturity);
            Console.WriteLine("Underlying price = " + underlying);
            Console.WriteLine("Strike = " + strike);
            Console.WriteLine("Risk-free interest rate = {0:0.000000%}", riskFreeRate);
            Console.WriteLine("Dividend yield = {0:0.000000%}", dividendYield);
            Console.WriteLine("Volatility = {0:0.000000%}", volatility);
            Console.Write("\n");

            string method;

            Console.Write("\n");

            // write column headings
            int[] widths = new int[] { 35, 14, 14, 14 };
            Console.Write("{0,-" + widths[0] + "}", "Method");
            Console.Write("{0,-" + widths[1] + "}", "European");
            Console.Write("{0,-" + widths[2] + "}", "Bermudan");
            Console.WriteLine("{0,-" + widths[3] + "}", "American");

            List <Date> exerciseDates = new List <Date>();;

            for (int i = 1; i <= 4; i++)
            {
                exerciseDates.Add(settlementDate + new Period(3 * i, TimeUnit.Months));
            }

            Exercise europeanExercise = new EuropeanExercise(maturity);
            Exercise bermudanExercise = new BermudanExercise(exerciseDates);
            Exercise americanExercise = new AmericanExercise(settlementDate, maturity);

            Handle <Quote> underlyingH = new Handle <Quote>(new SimpleQuote(underlying));

            // bootstrap the yield/dividend/vol curves
            var flatTermStructure    = new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter));
            var flatDividendTS       = new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter));
            var flatVolTS            = new Handle <BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, volatility, dayCounter));
            StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);
            var bsmProcess           = new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS);

            // options
            VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise);
            VanillaOption bermudanOption = new VanillaOption(payoff, bermudanExercise);
            VanillaOption americanOption = new VanillaOption(payoff, americanExercise);


            // Analytic formulas:

            // Black-Scholes for European
            method = "Black-Scholes";
            europeanOption.setPricingEngine(new AnalyticEuropeanEngine(bsmProcess));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + "}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + "}", "N/A");


            // Barone-Adesi and Whaley approximation for American
            method = "Barone-Adesi/Whaley";
            americanOption.setPricingEngine(new BaroneAdesiWhaleyApproximationEngine(bsmProcess));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + "}", "N/A");
            Console.Write("{0,-" + widths[2] + "}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());


            // Bjerksund and Stensland approximation for American
            method = "Bjerksund/Stensland";
            americanOption.setPricingEngine(new BjerksundStenslandApproximationEngine(bsmProcess));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + "}", "N/A");
            Console.Write("{0,-" + widths[2] + "}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Integral
            method = "Integral";
            europeanOption.setPricingEngine(new IntegralEngine(bsmProcess));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + "}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + "}", "N/A");


            // Finite differences
            int timeSteps = 801;

            method = "Finite differences";
            europeanOption.setPricingEngine(new FDEuropeanEngine(bsmProcess, timeSteps, timeSteps - 1));
            bermudanOption.setPricingEngine(new FDBermudanEngine(bsmProcess, timeSteps, timeSteps - 1));
            americanOption.setPricingEngine(new FDAmericanEngine(bsmProcess, timeSteps, timeSteps - 1));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Jarrow-Rudd
            method = "Binomial Jarrow-Rudd";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <JarrowRudd>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <JarrowRudd>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <JarrowRudd>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());


            method = "Binomial Cox-Ross-Rubinstein";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <CoxRossRubinstein>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <CoxRossRubinstein>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <CoxRossRubinstein>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Additive equiprobabilities
            method = "Additive equiprobabilities";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <AdditiveEQPBinomialTree>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <AdditiveEQPBinomialTree>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <AdditiveEQPBinomialTree>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Binomial Trigeorgis
            method = "Binomial Trigeorgis";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <Trigeorgis>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <Trigeorgis>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <Trigeorgis>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Binomial Tian
            method = "Binomial Tian";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <Tian>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <Tian>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <Tian>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Binomial Leisen-Reimer
            method = "Binomial Leisen-Reimer";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <LeisenReimer>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <LeisenReimer>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <LeisenReimer>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // Binomial method: Binomial Joshi
            method = "Binomial Joshi";
            europeanOption.setPricingEngine(new BinomialVanillaEngine <Joshi4>(bsmProcess, timeSteps));
            bermudanOption.setPricingEngine(new BinomialVanillaEngine <Joshi4>(bsmProcess, timeSteps));
            americanOption.setPricingEngine(new BinomialVanillaEngine <Joshi4>(bsmProcess, timeSteps));

            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", bermudanOption.NPV());
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());


            // Monte Carlo Method: MC (crude)
            timeSteps = 1;
            method    = "MC (crude)";
            ulong          mcSeed    = 42;
            IPricingEngine mcengine1 = new MakeMCEuropeanEngine <PseudoRandom>(bsmProcess)
                                       .withSteps(timeSteps)
                                       .withAbsoluteTolerance(0.02)
                                       .withSeed(mcSeed)
                                       .value();

            europeanOption.setPricingEngine(mcengine1);
            // Real errorEstimate = europeanOption.errorEstimate();
            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", "N/A");


            // Monte Carlo Method: QMC (Sobol)
            method = "QMC (Sobol)";
            int nSamples = 32768;  // 2^15

            IPricingEngine mcengine2 = new MakeMCEuropeanEngine <LowDiscrepancy>(bsmProcess)
                                       .withSteps(timeSteps)
                                       .withSamples(nSamples)
                                       .value();

            europeanOption.setPricingEngine(mcengine2);
            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", europeanOption.NPV());
            Console.Write("{0,-" + widths[2] + ":0.000000}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", "N/A");

            // Monte Carlo Method: MC (Longstaff Schwartz)
            method = "MC (Longstaff Schwartz)";
            IPricingEngine mcengine3 = new MakeMCAmericanEngine <PseudoRandom>(bsmProcess)
                                       .withSteps(100)
                                       .withAntitheticVariate()
                                       .withCalibrationSamples(4096)
                                       .withAbsoluteTolerance(0.02)
                                       .withSeed(mcSeed)
                                       .value();

            americanOption.setPricingEngine(mcengine3);
            Console.Write("{0,-" + widths[0] + "}", method);
            Console.Write("{0,-" + widths[1] + ":0.000000}", "N/A");
            Console.Write("{0,-" + widths[2] + ":0.000000}", "N/A");
            Console.WriteLine("{0,-" + widths[3] + ":0.000000}", americanOption.NPV());

            // End test
            Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer);
            Console.WriteLine();

            Console.Write("Press any key to continue ...");
            Console.ReadKey();
        }
        public void testDiscretizationError()
        {
            // Testing the discretization error of the Heston Hull-White process
            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.Instance.setEvaluationDate(today);

            // construct a strange yield curve to check drifts and discounting
            // of the joint stochastic process

            List <Date>   dates = new List <Date>();
            List <double> times = new List <double>();
            List <double> rates = new List <double>(), divRates = new List <double>();

            for (int i = 0; i <= 31; ++i)
            {
                dates.Add(today + new Period(i, TimeUnit.Years));
                // FLOATING_POINT_EXCEPTION
                rates.Add(0.04 + 0.0001 * Math.Exp(Math.Sin(i)));
                divRates.Add(0.04 + 0.0001 * Math.Exp(Math.Sin(i)));
                times.Add(dc.yearFraction(today, dates.Last()));
            }

            Date   maturity = today + new Period(10, TimeUnit.Years);
            double v        = 0.25;

            Handle <Quote> s0  = new Handle <Quote>(new SimpleQuote(100));
            SimpleQuote    vol = new SimpleQuote(v);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, vol, dc));
            Handle <YieldTermStructure>    rTS   = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, rates, dc));
            Handle <YieldTermStructure>    qTS   = new Handle <YieldTermStructure>(new InterpolatedZeroCurve <Linear>(dates, divRates, dc));

            BlackScholesMertonProcess bsmProcess = new BlackScholesMertonProcess(s0, qTS, rTS, volTS);

            HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, v * v, 1, v * v, 1e-6, -0.4);

            HullWhiteForwardProcess hwProcess = new HullWhiteForwardProcess(rTS, 0.01, 0.01);

            hwProcess.setForwardMeasureTime(20.1472222222222222);

            double tol = 0.05;

            double[] corr   = { -0.85, 0.5 };
            double[] strike = { 50, 100, 125 };

            for (int i = 0; i < corr.Length; ++i)
            {
                for (int j = 0; j < strike.Length; ++j)
                {
                    StrikedTypePayoff payoff   = new PlainVanillaPayoff(Option.Type.Put, strike[j]);
                    Exercise          exercise = new EuropeanExercise(maturity);

                    VanillaOption optionBsmHW = new VanillaOption(payoff, exercise);
                    HullWhite     hwModel     = new HullWhite(rTS, hwProcess.a(), hwProcess.sigma());
                    optionBsmHW.setPricingEngine(new AnalyticBSMHullWhiteEngine(corr[i], bsmProcess, hwModel));

                    double expected = optionBsmHW.NPV();

                    VanillaOption optionHestonHW = new VanillaOption(payoff, exercise);
                    HybridHestonHullWhiteProcess jointProcess = new HybridHestonHullWhiteProcess(hestonProcess,
                                                                                                 hwProcess, corr[i]);
                    optionHestonHW.setPricingEngine(
                        new MakeMCHestonHullWhiteEngine <PseudoRandom, Statistics>(jointProcess)
                        .withSteps(1)
                        .withAntitheticVariate()
                        .withAbsoluteTolerance(tol)
                        .withSeed(42).getAsPricingEngine());

                    double calculated = optionHestonHW.NPV();
                    double error      = optionHestonHW.errorEstimate();

                    if ((Math.Abs(calculated - expected) > 3 * error &&
                         Math.Abs(calculated - expected) > 1e-5))
                    {
                        QAssert.Fail("Failed to reproduce discretization error"
                                     + "\n   corr:       " + corr[i]
                                     + "\n   strike:     " + strike[j]
                                     + "\n   calculated: " + calculated
                                     + "\n   error:      " + error
                                     + "\n   expected:   " + expected);
                    }
                }
            }
        }
示例#16
0
        public void testEuropeanGreeks()
        {
            // Testing dividend European option greeks...

            SavedSettings backup = new SavedSettings();

            Dictionary <string, double> calculated = new Dictionary <string, double>(),
                                        expected   = new Dictionary <string, double>(),
                                        tolerance  = new Dictionary <string, double>();

            tolerance["delta"] = 1.0e-5;
            tolerance["gamma"] = 1.0e-5;
            tolerance["theta"] = 1.0e-5;
            tolerance["rho"]   = 1.0e-5;
            tolerance["vega"]  = 1.0e-5;

            Option.Type[] types       = { 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.00, 0.10, 0.30 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            int[]         lengths     = { 1, 2 };
            double[]      vols        = { 0.05, 0.20, 0.40 };

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.setEvaluationDate(today);

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

            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 + new Period(lengths[k], TimeUnit.Years);
                        Exercise exercise = new EuropeanExercise(exDate);

                        List <Date>   dividendDates = new List <Date>();
                        List <double> dividends     = new List <double>();
                        for (Date d = today + new Period(3, TimeUnit.Months);
                             d < exercise.lastDate();
                             d += new Period(6, TimeUnit.Months))
                        {
                            dividendDates.Add(d);
                            dividends.Add(5.0);
                        }

                        StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]);

                        BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                               qTS, rTS, volTS);

                        IPricingEngine engine = new AnalyticDividendEuropeanEngine(stochProcess);

                        DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates,
                                                                                 dividends);
                        option.setPricingEngine(engine);

                        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["delta"] = option.delta();
                                        calculated["gamma"] = option.gamma();
                                        calculated["theta"] = option.theta();
                                        calculated["rho"]   = option.rho();
                                        calculated["vega"]  = option.vega();

                                        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["delta"] = (value_p - value_m) / (2 * du);
                                            expected["gamma"] = (delta_p - delta_m) / (2 * du);

                                            // perturb risk-free rate and get rho
                                            double dr = r * 1.0e-4;
                                            rRate.setValue(r + dr);
                                            value_p = option.NPV();
                                            rRate.setValue(r - dr);
                                            value_m = option.NPV();
                                            rRate.setValue(r);
                                            expected["rho"] = (value_p - value_m) / (2 * dr);

                                            // perturb volatility and get vega
                                            double dv = v * 1.0e-4;
                                            vol.setValue(v + dv);
                                            value_p = option.NPV();
                                            vol.setValue(v - dv);
                                            value_m = option.NPV();
                                            vol.setValue(v);
                                            expected["vega"] = (value_p - value_m) / (2 * dv);

                                            // perturb date and get theta
                                            double dT = dc.yearFraction(today - 1, today + 1);
                                            Settings.setEvaluationDate(today - 1);
                                            value_m = option.NPV();
                                            Settings.setEvaluationDate(today + 1);
                                            value_p = option.NPV();
                                            Settings.setEvaluationDate(today);
                                            expected["theta"] = (value_p - value_m) / dT;

                                            // compare
                                            foreach (KeyValuePair <string, double> it in calculated)
                                            {
                                                string greek = it.Key;
                                                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);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        public void testH1HWPricingEngine()
        {
            /*
             * Example taken from Lech Aleksander Grzelak,
             * Equity and Foreign Exchange Hybrid Models for Pricing Long-Maturity
             * Financial Derivatives,
             * http://repository.tudelft.nl/assets/uuid:a8e1a007-bd89-481a-aee3-0e22f15ade6b/PhDThesis_main.pdf
             */
            Date today = new Date(15, Month.July, 2012);

            Settings.Instance.setEvaluationDate(today);
            Date       exerciseDate = new Date(13, Month.July, 2022);
            DayCounter dc           = new Actual365Fixed();

            Exercise exercise = new EuropeanExercise(exerciseDate);

            Handle <Quote> s0 = new Handle <Quote>(new SimpleQuote(100.0));

            double r       = 0.02;
            double q       = 0.00;
            double v0      = 0.05;
            double theta   = 0.05;
            double kappa_v = 0.3;

            double[] sigma_v = { 0.3, 0.6 };
            double   rho_sv  = -0.30;
            double   rho_sr  = 0.6;
            double   kappa_r = 0.01;
            double   sigma_r = 0.01;

            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, r, dc));
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, q, dc));

            Handle <BlackVolTermStructure> flatVolTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, 0.20, dc));
            GeneralizedBlackScholesProcess bsProcess = new GeneralizedBlackScholesProcess(s0, qTS, rTS, flatVolTS);

            HullWhiteProcess hwProcess      = new HullWhiteProcess(rTS, kappa_r, sigma_r);
            HullWhite        hullWhiteModel = new HullWhite(new Handle <YieldTermStructure>(rTS), kappa_r, sigma_r);

            double tol = 0.0001;

            double[]   strikes  = { 40, 80, 100, 120, 180 };
            double[][] expected =
            {
                new double[]  { 0.267503, 0.235742, 0.228223, 0.223461, 0.217855 },
                new double[]  { 0.263626, 0.211625, 0.199907, 0.193502, 0.190025 }
            };

            for (int j = 0; j < sigma_v.Length; ++j)
            {
                HestonProcess hestonProcess = new HestonProcess(rTS, qTS, s0, v0, kappa_v, theta, sigma_v[j], rho_sv);
                HestonModel   hestonModel   = new HestonModel(hestonProcess);

                for (int i = 0; i < strikes.Length; ++i)
                {
                    StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, strikes[i]);

                    VanillaOption option = new VanillaOption(payoff, exercise);

                    IPricingEngine analyticH1HWEngine = new AnalyticH1HWEngine(hestonModel, hullWhiteModel, rho_sr, 144);
                    option.setPricingEngine(analyticH1HWEngine);
                    double impliedH1HW = option.impliedVolatility(option.NPV(), bsProcess);

                    if (Math.Abs(expected[j][i] - impliedH1HW) > tol)
                    {
                        QAssert.Fail("Failed to reproduce H1HW implied volatility"
                                     + "\n   expected       : " + expected[j][i]
                                     + "\n   calculated     : " + impliedH1HW
                                     + "\n   tol            : " + tol
                                     + "\n   strike         : " + strikes[i]
                                     + "\n   sigma          : " + sigma_v[j]);
                    }
                }
            }
        }
示例#18
0
        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);
                }
            }
        }
示例#19
0
        public void testCashAtHitOrNothingAmericanGreeks()
        {
            // Testing American cash-(at-hit)-or-nothing digital option greeks

            using (SavedSettings backup = new SavedSettings())
            {
                SortedDictionary <string, double> calculated = new SortedDictionary <string, double>();
                SortedDictionary <string, double> expected   = new SortedDictionary <string, double>();
                SortedDictionary <string, double> tolerance  = new SortedDictionary <string, double>(); // std::map<std::string,Real> calculated, expected, tolerance;

                tolerance["delta"] = 5.0e-5;
                tolerance["gamma"] = 5.0e-5;
                tolerance["rho"]   = 5.0e-5;

                Option.Type[] types       = { QLNet.Option.Type.Call, QLNet.Option.Type.Put };
                double[]      strikes     = { 50.0, 99.5, 100.5, 150.0 };
                double        cashPayoff  = 100.0;
                double[]      underlyings = { 100 };
                double[]      qRates      = { 0.04, 0.05, 0.06 };
                double[]      rRates      = { 0.01, 0.05, 0.15 };
                double[]      vols        = { 0.11, 0.5, 1.2 };

                DayCounter dc    = new Actual360();
                Date       today = Date.Today;
                Settings.setEvaluationDate(today);

                SimpleQuote spot  = new SimpleQuote(0.0);
                SimpleQuote qRate = new SimpleQuote(0.0);
                Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
                SimpleQuote rRate = new SimpleQuote(0.0);
                Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
                SimpleQuote vol = new SimpleQuote(0.0);
                Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

                // there is no cycling on different residual times
                Date       exDate     = today + 360;
                Exercise   exercise   = new EuropeanExercise(exDate);
                Exercise   amExercise = new AmericanExercise(today, exDate, false);
                Exercise[] exercises  = { exercise, amExercise };

                BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS);

                IPricingEngine euroEngine = new AnalyticEuropeanEngine(stochProcess);

                IPricingEngine amEngine = new AnalyticDigitalAmericanEngine(stochProcess);

                IPricingEngine[] engines = { euroEngine, amEngine };

                bool knockin = true;
                for (int j = 0; j < engines.Length; j++)
                {
                    for (int i1 = 0; i1 < types.Length; i1++)
                    {
                        for (int i6 = 0; i6 < strikes.Length; i6++)
                        {
                            StrikedTypePayoff payoff = new CashOrNothingPayoff(types[i1], strikes[i6], cashPayoff);

                            VanillaOption opt = new VanillaOption(payoff, exercises[j]);
                            opt.setPricingEngine(engines[j]);

                            for (int i2 = 0; i2 < underlyings.Length; i2++)
                            {
                                for (int i4 = 0; i4 < qRates.Length; i4++)
                                {
                                    for (int i3 = 0; i3 < rRates.Length; i3++)
                                    {
                                        for (int i7 = 0; i7 < vols.Length; i7++)
                                        {
                                            // test data
                                            double u = underlyings[i2];
                                            double q = qRates[i4];
                                            double r = rRates[i3];
                                            double v = vols[i7];
                                            spot.setValue(u);
                                            qRate.setValue(q);
                                            rRate.setValue(r);
                                            vol.setValue(v);

                                            // theta, dividend rho and vega are not available for
                                            // digital option with american exercise. Greeks of
                                            // digital options with european payoff are tested
                                            // in the europeanoption.cpp test
                                            double value = opt.NPV();
                                            calculated["delta"] = opt.delta();
                                            calculated["gamma"] = opt.gamma();
                                            calculated["rho"]   = opt.rho();

                                            if (value > 1.0e-6)
                                            {
                                                // perturb spot and get delta and gamma
                                                double du = u * 1.0e-4;
                                                spot.setValue(u + du);
                                                double value_p = opt.NPV(),
                                                       delta_p = opt.delta();
                                                spot.setValue(u - du);
                                                double value_m = opt.NPV(),
                                                       delta_m = opt.delta();
                                                spot.setValue(u);
                                                expected["delta"] = (value_p - value_m) / (2 * du);
                                                expected["gamma"] = (delta_p - delta_m) / (2 * du);

                                                // perturb rates and get rho and dividend rho
                                                double dr = r * 1.0e-4;
                                                rRate.setValue(r + dr);
                                                value_p = opt.NPV();
                                                rRate.setValue(r - dr);
                                                value_m = opt.NPV();
                                                rRate.setValue(r);
                                                expected["rho"] = (value_p - value_m) / (2 * dr);

                                                // check
                                                //std::map<std::string,Real>::iterator it;
                                                foreach (var it in calculated)
                                                {
                                                    string greek = it.Key;
                                                    double expct = expected  [greek],
                                                           calcl = calculated[greek],
                                                           tol   = tolerance [greek];
                                                    double error = Utilities.relativeError(expct, calcl, value);
                                                    if (error > tol)
                                                    {
                                                        REPORT_FAILURE(greek, payoff, exercise,
                                                                       u, q, r, today, v,
                                                                       expct, calcl, error, tol, knockin);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
示例#20
0
        public void testSwaptionPricing()
        {
            // Testing forward swap and swaption pricing
            const int size  = 10;
            const int steps = 8 * size;

#if QL_USE_INDEXED_COUPON
            const double tolerance = 1e-6;
#else
            const double tolerance = 1e-12;
#endif

            List <Date>   dates = new List <Date>();
            List <double> rates = new List <double>();
            dates.Add(new Date(4, 9, 2005));
            dates.Add(new Date(4, 9, 2011));
            rates.Add(0.04);
            rates.Add(0.08);

            IborIndex index = makeIndex(dates, rates);

            LiborForwardModelProcess process = new LiborForwardModelProcess(size, index);

            LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.5);

            LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(process.fixingTimes(),
                                                                                 0.291, 1.483, 0.116, 0.00001);

            // set-up pricing engine
            process.setCovarParam((LfmCovarianceParameterization)
                                  new LfmCovarianceProxy(volaModel, corrModel));

            // set-up a small Monte-Carlo simulation to price swations
            List <double> tmp = process.fixingTimes();

            TimeGrid grid = new TimeGrid(tmp, tmp.Count, steps);

            List <int> location = new List <int>();
            for (int i = 0; i < tmp.Count; ++i)
            {
                location.Add(grid.index(tmp[i]));
            }

            ulong     seed     = 42;
            const int nrTrails = 5000;
            LowDiscrepancy.icInstance = new InverseCumulativeNormal();

            IRNG rsg = (InverseCumulativeRsg <RandomSequenceGenerator <MersenneTwisterUniformRng>
                                              , InverseCumulativeNormal>)
                       new PseudoRandom().make_sequence_generator(process.factors() * (grid.size() - 1), seed);



            MultiPathGenerator <IRNG> generator = new MultiPathGenerator <IRNG>(process,
                                                                                grid,
                                                                                rsg, false);

            LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel);

            Calendar              calendar   = index.fixingCalendar();
            DayCounter            dayCounter = index.forwardingTermStructure().link.dayCounter();
            BusinessDayConvention convention = index.businessDayConvention();

            Date settlement = index.forwardingTermStructure().link.referenceDate();

            SwaptionVolatilityMatrix m = liborModel.getSwaptionVolatilityMatrix();

            for (int i = 1; i < size; ++i)
            {
                for (int j = 1; j <= size - i; ++j)
                {
                    Date fwdStart    = settlement + new Period(6 * i, TimeUnit.Months);
                    Date fwdMaturity = fwdStart + new Period(6 * j, TimeUnit.Months);

                    Schedule schedule = new Schedule(fwdStart, fwdMaturity, index.tenor(), calendar,
                                                     convention, convention, DateGeneration.Rule.Forward, false);

                    double      swapRate    = 0.0404;
                    VanillaSwap forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0,
                                                              schedule, swapRate, dayCounter,
                                                              schedule, index, 0.0, index.dayCounter());
                    forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure()));

                    // check forward pricing first
                    double expected   = forwardSwap.fairRate();
                    double calculated = liborModel.S_0(i - 1, i + j - 1);

                    if (Math.Abs(expected - calculated) > tolerance)
                    {
                        QAssert.Fail("Failed to reproduce fair forward swap rate"
                                     + "\n    calculated: " + calculated
                                     + "\n    expected:   " + expected);
                    }

                    swapRate    = forwardSwap.fairRate();
                    forwardSwap =
                        new VanillaSwap(VanillaSwap.Type.Receiver, 1.0,
                                        schedule, swapRate, dayCounter,
                                        schedule, index, 0.0, index.dayCounter());
                    forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure()));

                    if (i == j && i <= size / 2)
                    {
                        IPricingEngine engine =
                            new LfmSwaptionEngine(liborModel, index.forwardingTermStructure());
                        Exercise exercise =
                            new EuropeanExercise(process.fixingDates()[i]);

                        Swaption swaption =
                            new Swaption(forwardSwap, exercise);
                        swaption.setPricingEngine(engine);

                        GeneralStatistics stat = new GeneralStatistics();

                        for (int n = 0; n < nrTrails; ++n)
                        {
                            Sample <IPath> path = (n % 2 != 0) ? generator.antithetic()
                                          : generator.next();
                            MultiPath value = path.value as MultiPath;
                            Utils.QL_REQUIRE(value != null, () => "Invalid Path");
                            //Sample<MultiPath> path = generator.next();
                            List <double> rates_ = new InitializedList <double>(size);
                            for (int k = 0; k < process.size(); ++k)
                            {
                                rates_[k] = value[k][location[i]];
                            }
                            List <double> dis = process.discountBond(rates_);

                            double npv = 0.0;
                            for (int k = i; k < i + j; ++k)
                            {
                                npv += (swapRate - rates_[k])
                                       * (process.accrualEndTimes()[k]
                                          - process.accrualStartTimes()[k]) * dis[k];
                            }
                            stat.add(Math.Max(npv, 0.0));
                        }

                        if (Math.Abs(swaption.NPV() - stat.mean())
                            > stat.errorEstimate() * 2.35)
                        {
                            QAssert.Fail("Failed to reproduce swaption npv"
                                         + "\n    calculated: " + stat.mean()
                                         + "\n    expected:   " + swaption.NPV());
                        }
                    }
                }
            }
        }
示例#21
0
        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);
                }
            }
        }
示例#22
0
        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);
            }
        }
        //class Swaption {
        //        [System.Xml.Serialization.XmlElementAttribute("americanExercise", typeof(AmericanExercise))]
        //        [System.Xml.Serialization.XmlElementAttribute("bermudaExercise", typeof(BermudaExercise))]
        //        [System.Xml.Serialization.XmlElementAttribute("europeanExercise", typeof(EuropeanExercise))]
        //        public Exercise Item {

        public static void SwaptionSetEuropeanExercise(Swaption swaption, EuropeanExercise europeanExercise)
        {
            swaption.Item = europeanExercise;
        }
示例#24
0
        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);
                }
            }
        }
示例#25
0
        //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);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
示例#26
0
        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);
                }
            }
        }
示例#27
0
        // Reference pg. 253 - Hull - Options, Futures, and Other Derivatives 5th ed
        // Exercise 12.8
        // Doesn't quite work.  Need to deal with date conventions
        void testEuropeanKnownValue()
        {
            // Testing dividend European option values with known value...

            SavedSettings backup = new SavedSettings();

            double tolerance = 1.0e-2;
            double expected  = 3.67;

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.setEvaluationDate(today);

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

            Date     exDate   = today + new Period(6, TimeUnit.Months);
            Exercise exercise = new EuropeanExercise(exDate);

            List <Date>   dividendDates = new List <Date>();
            List <double> dividends     = new List <double>();

            dividendDates.Add(today + new Period(2, TimeUnit.Months));
            dividends.Add(0.50);
            dividendDates.Add(today + new Period(5, TimeUnit.Months));
            dividends.Add(0.50);

            StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 40.0);

            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                   qTS, rTS, volTS);

            IPricingEngine engine = new AnalyticDividendEuropeanEngine(stochProcess);

            DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);

            option.setPricingEngine(engine);

            double u = 40.0;
            double q = 0.0, r = 0.09;
            double v = 0.30;

            spot.setValue(u);
            qRate.setValue(q);
            rRate.setValue(r);
            vol.setValue(v);

            double calculated = option.NPV();
            double error      = Math.Abs(calculated - expected);

            if (error > tolerance)
            {
                REPORT_FAILURE("value start limit",
                               payoff, exercise,
                               u, q, r, today, v,
                               expected, calculated,
                               error, tolerance);
            }
        }
示例#28
0
        public void testBond()
        {
            /* when deeply out-of-the-money, the value of the convertible bond
             * should equal that of the underlying plain-vanilla bond. */

            // Testing out-of-the-money convertible bonds against vanilla bonds

            CommonVars vars = new CommonVars();

            vars.conversionRatio = 1.0e-16;

            Exercise euExercise = new EuropeanExercise(vars.maturityDate);
            Exercise amExercise = new AmericanExercise(vars.issueDate, vars.maturityDate);

            int            timeSteps = 1001;
            IPricingEngine engine    = new BinomialConvertibleEngine <CoxRossRubinstein>(vars.process, timeSteps);

            Handle <YieldTermStructure> discountCurve = new Handle <YieldTermStructure>(new ForwardSpreadedTermStructure(vars.riskFreeRate, vars.creditSpread));

            // zero-coupon

            Schedule schedule = new MakeSchedule().from(vars.issueDate)
                                .to(vars.maturityDate)
                                .withFrequency(Frequency.Once)
                                .withCalendar(vars.calendar)
                                .backwards().value();

            ConvertibleZeroCouponBond euZero = new ConvertibleZeroCouponBond(euExercise, vars.conversionRatio,
                                                                             vars.no_dividends, vars.no_callability,
                                                                             vars.creditSpread,
                                                                             vars.issueDate, vars.settlementDays,
                                                                             vars.dayCounter, schedule,
                                                                             vars.redemption);

            euZero.setPricingEngine(engine);

            ConvertibleZeroCouponBond amZero = new ConvertibleZeroCouponBond(amExercise, vars.conversionRatio,
                                                                             vars.no_dividends, vars.no_callability,
                                                                             vars.creditSpread,
                                                                             vars.issueDate, vars.settlementDays,
                                                                             vars.dayCounter, schedule,
                                                                             vars.redemption);

            amZero.setPricingEngine(engine);

            ZeroCouponBond zero = new ZeroCouponBond(vars.settlementDays, vars.calendar,
                                                     100.0, vars.maturityDate,
                                                     BusinessDayConvention.Following, vars.redemption, vars.issueDate);

            IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve);

            zero.setPricingEngine(bondEngine);

            double tolerance = 1.0e-2 * (vars.faceAmount / 100.0);

            double error = Math.Abs(euZero.NPV() - zero.settlementValue());

            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce zero-coupon bond price:"
                             + "\n    calculated: " + euZero.NPV()
                             + "\n    expected:   " + zero.settlementValue()
                             + "\n    error:      " + error);
            }

            error = Math.Abs(amZero.NPV() - zero.settlementValue());
            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce zero-coupon bond price:"
                             + "\n    calculated: " + amZero.NPV()
                             + "\n    expected:   " + zero.settlementValue()
                             + "\n    error:      " + error);
            }

            // coupon

            List <double> coupons = new InitializedList <double>(1, 0.05);

            schedule = new MakeSchedule().from(vars.issueDate)
                       .to(vars.maturityDate)
                       .withFrequency(vars.frequency)
                       .withCalendar(vars.calendar)
                       .backwards().value();

            ConvertibleFixedCouponBond euFixed = new ConvertibleFixedCouponBond(euExercise, vars.conversionRatio,
                                                                                vars.no_dividends, vars.no_callability,
                                                                                vars.creditSpread,
                                                                                vars.issueDate, vars.settlementDays,
                                                                                coupons, vars.dayCounter,
                                                                                schedule, vars.redemption);

            euFixed.setPricingEngine(engine);

            ConvertibleFixedCouponBond amFixed = new ConvertibleFixedCouponBond(amExercise, vars.conversionRatio,
                                                                                vars.no_dividends, vars.no_callability,
                                                                                vars.creditSpread,
                                                                                vars.issueDate, vars.settlementDays,
                                                                                coupons, vars.dayCounter,
                                                                                schedule, vars.redemption);

            amFixed.setPricingEngine(engine);

            FixedRateBond fixedBond = new FixedRateBond(vars.settlementDays, vars.faceAmount, schedule,
                                                        coupons, vars.dayCounter, BusinessDayConvention.Following,
                                                        vars.redemption, vars.issueDate);

            fixedBond.setPricingEngine(bondEngine);

            tolerance = 2.0e-2 * (vars.faceAmount / 100.0);

            error = Math.Abs(euFixed.NPV() - fixedBond.settlementValue());
            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce fixed-coupon bond price:"
                             + "\n    calculated: " + euFixed.NPV()
                             + "\n    expected:   " + fixedBond.settlementValue()
                             + "\n    error:      " + error);
            }

            error = Math.Abs(amFixed.NPV() - fixedBond.settlementValue());
            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce fixed-coupon bond price:"
                             + "\n    calculated: " + amFixed.NPV()
                             + "\n    expected:   " + fixedBond.settlementValue()
                             + "\n    error:      " + error);
            }

            // floating-rate

            IborIndex     index      = new Euribor1Y(discountCurve);
            int           fixingDays = 2;
            List <double> gearings   = new InitializedList <double>(1, 1.0);
            List <double> spreads    = new List <double>();

            ConvertibleFloatingRateBond euFloating = new ConvertibleFloatingRateBond(euExercise, vars.conversionRatio,
                                                                                     vars.no_dividends, vars.no_callability,
                                                                                     vars.creditSpread,
                                                                                     vars.issueDate, vars.settlementDays,
                                                                                     index, fixingDays, spreads,
                                                                                     vars.dayCounter, schedule,
                                                                                     vars.redemption);

            euFloating.setPricingEngine(engine);

            ConvertibleFloatingRateBond amFloating = new ConvertibleFloatingRateBond(amExercise, vars.conversionRatio,
                                                                                     vars.no_dividends, vars.no_callability,
                                                                                     vars.creditSpread,
                                                                                     vars.issueDate, vars.settlementDays,
                                                                                     index, fixingDays, spreads,
                                                                                     vars.dayCounter, schedule,
                                                                                     vars.redemption);

            amFloating.setPricingEngine(engine);

            IborCouponPricer pricer = new BlackIborCouponPricer(new Handle <OptionletVolatilityStructure>());

            Schedule floatSchedule = new Schedule(vars.issueDate, vars.maturityDate,
                                                  new Period(vars.frequency),
                                                  vars.calendar, BusinessDayConvention.Following, BusinessDayConvention.Following,
                                                  DateGeneration.Rule.Backward, false);

            FloatingRateBond floating = new FloatingRateBond(vars.settlementDays, vars.faceAmount, floatSchedule,
                                                             index, vars.dayCounter, BusinessDayConvention.Following, fixingDays,
                                                             gearings, spreads,
                                                             new List <double?>(), new List <double?>(),
                                                             false,
                                                             vars.redemption, vars.issueDate);

            floating.setPricingEngine(bondEngine);
            Utils.setCouponPricer(floating.cashflows(), pricer);

            tolerance = 2.0e-2 * (vars.faceAmount / 100.0);

            error = Math.Abs(euFloating.NPV() - floating.settlementValue());
            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce floating-rate bond price:"
                             + "\n    calculated: " + euFloating.NPV()
                             + "\n    expected:   " + floating.settlementValue()
                             + "\n    error:      " + error);
            }

            error = Math.Abs(amFloating.NPV() - floating.settlementValue());
            if (error > tolerance)
            {
                QAssert.Fail("failed to reproduce floating-rate bond price:"
                             + "\n    calculated: " + amFloating.NPV()
                             + "\n    expected:   " + floating.settlementValue()
                             + "\n    error:      " + error);
            }
        }
示例#29
0
        public void testEuropeanStartLimit()
        {
            // Testing dividend European option with a dividend on today's date...

            SavedSettings backup = new SavedSettings();

            double tolerance     = 1.0e-5;
            double dividendValue = 10.0;

            Option.Type[] types       = { 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.00, 0.10, 0.30 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            int[]         lengths     = { 1, 2 };
            double[]      vols        = { 0.05, 0.20, 0.70 };

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.setEvaluationDate(today);

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc));

            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 + new Period(lengths[k], TimeUnit.Years);
                        Exercise exercise = new EuropeanExercise(exDate);

                        List <Date>   dividendDates = new List <Date>();
                        List <double> dividends     = new List <double>();
                        dividendDates.Add(today);
                        dividends.Add(dividendValue);

                        StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]);

                        BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                               qTS, rTS, volTS);

                        IPricingEngine engine = new AnalyticDividendEuropeanEngine(stochProcess);

                        IPricingEngine ref_engine = new AnalyticEuropeanEngine(stochProcess);

                        DividendVanillaOption option = new DividendVanillaOption(payoff, exercise, dividendDates, dividends);
                        option.setPricingEngine(engine);

                        VanillaOption ref_option = new VanillaOption(payoff, exercise);
                        ref_option.setPricingEngine(ref_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 calculated = option.NPV();
                                        spot.setValue(u - dividendValue);
                                        double expected = ref_option.NPV();
                                        double error    = Math.Abs(calculated - expected);
                                        if (error > tolerance)
                                        {
                                            REPORT_FAILURE("value", payoff, exercise,
                                                           u, q, r, today, v,
                                                           expected, calculated,
                                                           error, tolerance);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
示例#30
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(EuropeanExercise obj) {
   return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
 }
示例#31
0
        public void testValues()
        {
            // Testing forward option values...

            /* The data below are from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998
             */
            ForwardOptionData[] values =
            {
                //  type, moneyness, spot,  div, rate,start,   t,  vol, result, tol
                // "Option pricing formulas", pag. 37
                new ForwardOptionData(Option.Type.Call, 1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 4.4064, 1.0e-4),
                // "Option pricing formulas", VBA code
                new ForwardOptionData(Option.Type.Put,  1.1, 60.0, 0.04, 0.08, 0.25, 1.0, 0.30, 8.2971, 1.0e-4)
            };

            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            SimpleQuote spot  = new SimpleQuote(0.0);
            SimpleQuote qRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, qRate, dc));
            SimpleQuote rRate = new SimpleQuote(0.0);
            Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(today, rRate, dc));
            SimpleQuote vol = new SimpleQuote(0.0);
            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(today, vol, dc));

            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                   new Handle <YieldTermStructure>(qTS), new Handle <YieldTermStructure>(rTS),
                                                                                   new Handle <BlackVolTermStructure>(volTS));

            IPricingEngine engine = new ForwardVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process)); // AnalyticEuropeanEngine

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, 0.0);
                Date     exDate          = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise exercise        = new EuropeanExercise(exDate);
                Date     reset           = today + Convert.ToInt32(values[i].start * 360 + 0.5);

                spot.setValue(values[i].s);
                qRate.setValue(values[i].q);
                rRate.setValue(values[i].r);
                vol.setValue(values[i].v);

                ForwardVanillaOption option = new ForwardVanillaOption(values[i].moneyness, reset, payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                double tolerance  = 1e-4;
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s,
                                   values[i].q, values[i].r, today,
                                   values[i].v, values[i].moneyness, reset,
                                   values[i].result, calculated,
                                   error, tolerance);
                }
            }
        }