Example #1
0
        public void testGreeksInitialization()
        {
            // Testing forward option greeks initialization
            DayCounter    dc     = new Actual360();
            SavedSettings backup = new SavedSettings();
            Date          today  = Date.Today;

            Settings.setEvaluationDate(today);

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

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

            IPricingEngine    engine   = new ForwardVanillaEngine(stochProcess, process => new TestBinomialEngine(process));
            Date              exDate   = today + new Period(1, TimeUnit.Years);
            Exercise          exercise = new EuropeanExercise(exDate);
            Date              reset    = today + new Period(6, TimeUnit.Months);
            StrikedTypePayoff payoff   = new PlainVanillaPayoff(Option.Type.Call, 0.0);

            ForwardVanillaOption option = new ForwardVanillaOption(0.9, reset, payoff, exercise);

            option.setPricingEngine(engine);

            IPricingEngine ctrlengine = new TestBinomialEngine(stochProcess);
            VanillaOption  ctrloption = new VanillaOption(payoff, exercise);

            ctrloption.setPricingEngine(ctrlengine);

            double?delta = 0;

            try
            {
                delta = ctrloption.delta();
            }
            catch (Exception)
            {
                // if normal option can't calculate delta,
                // nor should forward
                try
                {
                    delta = option.delta();
                }
                catch (Exception)
                {
                    delta = null;
                }
                Utils.QL_REQUIRE(delta == null, () => "Forward delta invalid");
            }

            double?rho = 0;

            try
            {
                rho = ctrloption.rho();
            }
            catch (Exception)
            {
                // if normal option can't calculate rho,
                // nor should forward
                try
                {
                    rho = option.rho();
                }
                catch (Exception)
                {
                    rho = null;
                }
                Utils.QL_REQUIRE(rho == null, () => "Forward rho invalid");
            }

            double?divRho = 0;

            try
            {
                divRho = ctrloption.dividendRho();
            }
            catch (Exception)
            {
                // if normal option can't calculate divRho,
                // nor should forward
                try
                {
                    divRho = option.dividendRho();
                }
                catch (Exception)
                {
                    divRho = null;
                }
                Utils.QL_REQUIRE(divRho == null, () => "Forward dividendRho invalid");
            }

            double?vega = 0;

            try
            {
                vega = ctrloption.vega();
            }
            catch (Exception)
            {
                // if normal option can't calculate vega,
                // nor should forward
                try
                {
                    vega = option.vega();
                }
                catch (Exception)
                {
                    vega = null;
                }
                Utils.QL_REQUIRE(vega == null, () => "Forward vega invalid");
            }
        }
Example #2
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);
                }
            }
        }
Example #3
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);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #4
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackScholesMertonProcess obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
        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.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());
                }
            }
        }
Example #6
0
        public void testAssetOrNothingHaugValues()
        {
            // Testing asset-or-nothing barrier options against Haug's values

            BinaryOptionData[] values =
            {
                /* The data below are from
                 * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 15,16,19,20,23,24,27,28
                 * Note:
                 * q is the dividend rate, while the book gives b, the cost of carry (q=r-b)
                 */
                //    barrierType, barrier,  cash,         type, strike,   spot,    q,    r,   t,  vol,   value, tol
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 37.2782, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Call,  98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 45.8530, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Call, 102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 44.5294, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Call,  98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 54.9262, 1e-4),
                // 19,20
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Put,  102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 27.5644, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 0.00, Option.Type.Put,   98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 18.9896, 1e-4),
                // following value is wrong in book.
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Put,  102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 33.1723, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 0.00, Option.Type.Put,   98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 22.7755, 1e-4),
                // 23,24
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call, 102.00, 105.00, 0.00, 0.10, 0.5, 0.20, 39.9391, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Call,  98.00, 105.00, 0.00, 0.10, 0.5, 0.20, 40.1574, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Call, 102.00,  95.00, 0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Call,  98.00,  95.00, 0.00, 0.10, 0.5, 0.20,  0.2676, 1e-4),
                // 27,28
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put,  102.00, 105.00, 0.00, 0.10, 0.5, 0.20,  0.2183, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 0.00, Option.Type.Put,   98.00, 105.00, 0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Put,  102.00,  95.00, 0.00, 0.10, 0.5, 0.20, 17.2983, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 0.00, Option.Type.Put,   98.00,  95.00, 0.00, 0.10, 0.5, 0.20, 17.0306, 1e-4),
            };

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

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

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new AssetOrNothingPayoff(values[i].type, values[i].strike);
                Date     exDate          = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise      = new AmericanExercise(today, exDate, true);

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

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

                IPricingEngine engine = new AnalyticBinaryBarrierEngine(stochProcess);

                BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise);

                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType,
                                   values[i].barrier, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol);
                }
            }
        }
        public void testEuropeanStartLimit()
        {
            // Testing dividend European option with a dividend on today's date...
            using (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.Instance.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);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Evaluates the specified option contract to compute a theoretical price, IV and greeks
        /// </summary>
        /// <param name="security">The option security object</param>
        /// <param name="slice">The current data slice. This can be used to access other information
        /// available to the algorithm</param>
        /// <param name="contract">The option contract to evaluate</param>
        /// <returns>An instance of <see cref="OptionPriceModelResult"/> containing the theoretical
        /// price of the specified option contract</returns>
        public OptionPriceModelResult Evaluate(Security security, Slice slice, OptionContract contract)
        {
            try
            {
                // setting up option pricing parameters
                var calendar       = new UnitedStates();
                var dayCounter     = new Actual365Fixed();
                var optionSecurity = (Option)security;

                var settlementDate       = contract.Time.Date.AddDays(Option.DefaultSettlementDays);
                var maturityDate         = contract.Expiry.Date.AddDays(Option.DefaultSettlementDays);
                var underlyingQuoteValue = new SimpleQuote((double)optionSecurity.Underlying.Price);

                var dividendYieldValue = new SimpleQuote(_dividendYieldEstimator.Estimate(security, slice, contract));
                var dividendYield      = new Handle <YieldTermStructure>(new FlatForward(0, calendar, dividendYieldValue, dayCounter));

                var riskFreeRateValue = new SimpleQuote(_riskFreeRateEstimator.Estimate(security, slice, contract));
                var riskFreeRate      = new Handle <YieldTermStructure>(new FlatForward(0, calendar, riskFreeRateValue, dayCounter));

                var underlyingVolValue = new SimpleQuote(_underlyingVolEstimator.Estimate(security, slice, contract));
                var underlyingVol      = new Handle <BlackVolTermStructure>(new BlackConstantVol(0, calendar, new Handle <Quote>(underlyingVolValue), dayCounter));

                // preparing stochastic process and payoff functions
                var stochasticProcess = new BlackScholesMertonProcess(new Handle <Quote>(underlyingQuoteValue), dividendYield, riskFreeRate, underlyingVol);
                var payoff            = new PlainVanillaPayoff(contract.Right == OptionRight.Call ? QLNet.Option.Type.Call : QLNet.Option.Type.Put, (double)contract.Strike);

                // creating option QL object
                var option = contract.Symbol.ID.OptionStyle == OptionStyle.American ?
                             new VanillaOption(payoff, new AmericanExercise(settlementDate, maturityDate)) :
                             new VanillaOption(payoff, new EuropeanExercise(maturityDate));

                Settings.setEvaluationDate(settlementDate);

                // preparing pricing engine QL object
                option.setPricingEngine(_pricingEngineFunc(contract.Symbol, stochasticProcess));

                // running calculations
                var npv = EvaluateOption(option);

                // function extracts QL greeks catching exception if greek is not generated by the pricing engine and reevaluates option to get numerical estimate of the seisitivity
                Func <Func <double>, Func <double>, decimal> tryGetGreekOrReevaluate = (greek, reevalFunc) =>
                {
                    try
                    {
                        return((decimal)greek());
                    }
                    catch (Exception)
                    {
                        return(EnableGreekApproximation ? (decimal)reevalFunc() : 0.0m);
                    }
                };

                // function extracts QL greeks catching exception if greek is not generated by the pricing engine
                Func <Func <double>, decimal> tryGetGreek = greek => tryGetGreekOrReevaluate(greek, () => 0.0);

                // function extracts QL IV catching exception if IV is not generated by the pricing engine
                Func <decimal> tryGetImpliedVol = () =>
                {
                    try
                    {
                        return((decimal)option.impliedVolatility((double)optionSecurity.Price, stochasticProcess));
                    }
                    catch (Exception err)
                    {
                        Log.Debug("tryGetImpliedVol() error: " + err.Message);
                        return(0m);
                    }
                };

                Func <Tuple <decimal, decimal> > evalDeltaGamma = () =>
                {
                    try
                    {
                        return(Tuple.Create((decimal)option.delta(), (decimal)option.gamma()));
                    }
                    catch (Exception)
                    {
                        if (EnableGreekApproximation)
                        {
                            var step    = 0.01;
                            var initial = underlyingQuoteValue.value();
                            underlyingQuoteValue.setValue(initial - step);
                            var npvMinus = EvaluateOption(option);
                            underlyingQuoteValue.setValue(initial + step);
                            var npvPlus = EvaluateOption(option);
                            underlyingQuoteValue.setValue(initial);

                            return(Tuple.Create((decimal)((npvPlus - npvMinus) / (2 * step)),
                                                (decimal)((npvPlus - 2 * npv + npvMinus) / (step * step))));
                        }
                        else
                        {
                            return(Tuple.Create(0.0m, 0.0m));
                        }
                    }
                };

                Func <double> reevalVega = () =>
                {
                    var step    = 0.001;
                    var initial = underlyingVolValue.value();
                    underlyingVolValue.setValue(initial + step);
                    var npvPlus = EvaluateOption(option);
                    underlyingVolValue.setValue(initial);

                    return((npvPlus - npv) / step);
                };

                Func <double> reevalTheta = () =>
                {
                    var step = 1.0 / 365.0;

                    Settings.setEvaluationDate(settlementDate.AddDays(-1));
                    var npvMinus = EvaluateOption(option);
                    Settings.setEvaluationDate(settlementDate);

                    return((npv - npvMinus) / step);
                };

                Func <double> reevalRho = () =>
                {
                    var step    = 0.001;
                    var initial = riskFreeRateValue.value();
                    riskFreeRateValue.setValue(initial + step);
                    var npvPlus = EvaluateOption(option);
                    riskFreeRateValue.setValue(initial);

                    return((npvPlus - npv) / step);
                };

                // producing output with lazy calculations of IV and greeks

                return(new OptionPriceModelResult((decimal)npv,
                                                  tryGetImpliedVol,
                                                  () => new Greeks(evalDeltaGamma,
                                                                   () => tryGetGreekOrReevaluate(() => option.vega(), reevalVega),
                                                                   () => tryGetGreekOrReevaluate(() => option.theta(), reevalTheta),
                                                                   () => tryGetGreekOrReevaluate(() => option.rho(), reevalRho),
                                                                   () => tryGetGreek(() => option.elasticity()))));
            }
            catch (Exception err)
            {
                Log.Debug("QLOptionPriceModel.Evaluate() error: " + err.Message);
                return(new OptionPriceModelResult(0m, new Greeks()));
            }
        }
Example #9
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);
            }
        }
Example #10
0
        public void testBjerksundStenslandValues()
        {
            // ("Testing Bjerksund and Stensland approximation for American options...");

            AmericanOptionData[] values = new AmericanOptionData[]
            {
                //      type, strike,   spot,    q,    r,    t,  vol,   value, tol
                // from "Option pricing formulas", Haug, McGraw-Hill 1998, pag 27
                new AmericanOptionData(Option.Type.Call, 40.00, 42.00, 0.08, 0.04, 0.75, 0.35, 5.2704),
                // from "Option pricing formulas", Haug, McGraw-Hill 1998, VBA code
                new AmericanOptionData(Option.Type.Put, 40.00, 36.00, 0.00, 0.06, 1.00, 0.20, 4.4531),
                // ATM option with very small volatility, reference value taken from R
                new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0021, 0.08032314),
                // ATM option with very small volatility,
                // reference value taken from Barone-Adesi and Whaley Approximation
                new AmericanOptionData(Option.Type.Call, 100, 100, 0.05, 0.05, 1.0, 0.0001, 0.003860656),
                new AmericanOptionData(Option.Type.Call, 100, 99.99, 0.05, 0.05, 1.0, 0.0001, 0.00081),
                // ITM option with a very small volatility
                new AmericanOptionData(Option.Type.Call, 100, 110, 0.05, 0.05, 1.0, 0.0001, 10.0),
                new AmericanOptionData(Option.Type.Put, 110, 100, 0.05, 0.05, 1.0, 0.0001, 10.0),
                // ATM option with a very large volatility
                new AmericanOptionData(Option.Type.Put, 100, 110, 0.05, 0.05, 1.0, 10, 94.89543)
            };

            Date               today = Date.Today;
            DayCounter         dc    = new Actual360();
            SimpleQuote        spot  = new SimpleQuote(0.0);
            SimpleQuote        qRate = new SimpleQuote(0.0);
            YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            double tolerance = 5.0e-5;

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

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

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

                IPricingEngine engine = new BjerksundStenslandApproximationEngine(stochProcess);

                VanillaOption option = new VanillaOption(payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q,
                                   values[i].r, today, values[i].v, values[i].result,
                                   calculated, error, tolerance);
                }
            }
        }
Example #11
0
        public void testFdmHestonBarrierVsBlackScholes()
        {
            //Testing FDM with barrier option in Heston model...
            using (SavedSettings backup = new SavedSettings())
            {
                NewBarrierOptionData[] values = new NewBarrierOptionData[] {
                    /* The data below are from
                     * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag. 72
                     */
                    //                          barrierType,        barrier, rebate,         type,  strike,     s,    q,    r,    t,    v
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 100, 100.0, 0.00, 0.08, 1.00, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 90, 100.0, 0.00, 0.08, 0.25, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.25),

                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 90, 100.0, 0.00, 0.08, 0.25, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 100, 100.0, 0.00, 0.08, 0.40, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.15),

                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 100, 100.0, 0.00, 0.08, 0.40, 0.35),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.15),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Call, 110, 100.0, 0.00, 0.00, 1.00, 0.20),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.30),

                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Call, 110, 100.0, 0.00, 0.08, 1.00, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Call, 110, 100.0, 0.04, 0.08, 0.50, 0.30),

                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.25),

                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.25),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 110, 100.0, 0.00, 0.04, 1.00, 0.15),

                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 95.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownOut, 100.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpOut, 105.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.30),

                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 95.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.DownIn, 100.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 1.00, 0.15),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 90, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 100, 100.0, 0.04, 0.08, 0.50, 0.30),
                    new NewBarrierOptionData(Barrier.Type.UpIn, 105.0, 3.0, Option.Type.Put, 110, 100.0, 0.04, 0.08, 0.50, 0.30)
                };

                DayCounter dc           = new Actual365Fixed();
                Date       todaysDate   = new Date(28, 3, 2004);
                Date       exerciseDate = new Date(28, 3, 2005);
                Settings.Instance.setEvaluationDate(todaysDate);

                Handle <Quote> spot             = new Handle <Quote>(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 bsProcess = new BlackScholesMertonProcess(spot, qTS, rTS, volTS);

                IPricingEngine analyticEngine = new AnalyticBarrierEngine(bsProcess);

                for (int i = 0; i < values.Length; i++)
                {
                    Date     exDate   = todaysDate + Convert.ToInt32(values[i].t * 365 + 0.5);
                    Exercise exercise = new EuropeanExercise(exDate);

                    (spot.currentLink() as SimpleQuote).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);

                    BarrierOption barrierOption = new BarrierOption(values[i].barrierType, values[i].barrier,
                                                                    values[i].rebate, payoff, exercise);

                    double        v0            = vol.value() * vol.value();
                    HestonProcess hestonProcess =
                        new HestonProcess(rTS, qTS, spot, v0, 1.0, v0, 0.005, 0.0);

                    barrierOption.setPricingEngine(new FdHestonBarrierEngine(new HestonModel(hestonProcess), 200, 101, 3));

                    double calculatedHE = barrierOption.NPV();

                    barrierOption.setPricingEngine(analyticEngine);
                    double expected = barrierOption.NPV();

                    double tol = 0.0025;
                    if (Math.Abs(calculatedHE - expected) / expected > tol)
                    {
                        QAssert.Fail("Failed to reproduce expected Heston npv"
                                     + "\n    calculated: " + calculatedHE
                                     + "\n    expected:   " + expected
                                     + "\n    tolerance:  " + tol);
                    }
                }
            }
        }
Example #12
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BlackScholesMertonProcess obj) {
   return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
 }
        public void calculate(GBMParaViewModel para)
        {
            // set up dates
            Calendar calendar = new TARGET();
            //Date todaysDate = new Date(DateTime.Now);
            Date settlementDate = new Date(para.ReferenceDate_);

            Settings.setEvaluationDate(settlementDate);

            // our options
            Option.Type type = this.callPutEnum_;

            double underlying    = para.CurrentPrice_;
            double strike        = this.strike_;
            double dividendYield = para.Dividend_ / 100;
            double riskFreeRate  = para.Drift_ / 100;
            double volatility    = 0.0;

            if (this.callPutEnum_ == Option.Type.Call)
            {
                try
                {
                    volatility     = para.Call_Interpolation_.value(this.strike_) / 100;
                    this.imVolCal_ = Math.Round(para.Call_Interpolation_.value(this.strike_), 1);
                }
                catch (Exception)
                {
                    volatility     = para.Call_Interpolation_.value(this.strike_, true) / 100;
                    this.imVolCal_ = Math.Round(para.Call_Interpolation_.value(this.strike_, true), 1);
                }
            }
            else if (this.callPutEnum_ == Option.Type.Put)
            {
                try
                {
                    volatility     = para.Call_Interpolation_.value(this.strike_) / 100;
                    this.imVolCal_ = Math.Round(para.Put_Interpolation_.value(this.strike_), 1);
                }
                catch (Exception)
                {
                    volatility     = para.Call_Interpolation_.value(this.strike_, true) / 100;
                    this.imVolCal_ = Math.Round(para.Put_Interpolation_.value(this.strike_, true), 1);
                }
            }



            Date maturity = new Date(this.maturiry_);

            DayCounter dayCounter = new Actual365Fixed();

            //// 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);

            // Analytic formulas:
            // Black-Scholes for European
            europeanOption.setPricingEngine(new AnalyticEuropeanEngine(bsmProcess));

            this.npv_      = Math.Round(europeanOption.NPV(), 6);
            this.deltaCal_ = Math.Round(europeanOption.delta(), 6);
            this.gammaCal_ = Math.Round(europeanOption.gamma(), 6);
            this.vegaCal_  = Math.Round(europeanOption.vega() / 100, 6);
            this.thetaCal_ = Math.Round(europeanOption.theta() / 365, 6);
            this.rhoCal_   = Math.Round(europeanOption.rho() / 100, 6);
        }
Example #14
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);
            }
        }
        public void testEuropeanGreeks()
        {
            // Testing dividend European option greeks...
            using (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.Instance.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.Instance.setEvaluationDate(today - 1);
                                                value_m = option.NPV();
                                                Settings.Instance.setEvaluationDate(today + 1);
                                                value_p = option.NPV();
                                                Settings.Instance.setEvaluationDate(today);
                                                expected["theta"] = (value_p - value_m) / dT;

                                                // compare
                                                foreach (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);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #16
0
        //static void Main(string[] args)
        //{
        //    List<double> xGrid = Enumerable.Range(0, 100).Select(x => x / 10.0).ToList();
        //    List<double> yGrid = Enumerable.Range(0, 100).Select(x => x / 10.0).ToList();

        //    //List<double> xGrid = Enumerable.Range(0, 100);
        //    CubicInterpolation cubic = new CubicInterpolation(xGrid, xGrid.Count, yGrid,
        //                                                      CubicInterpolation.DerivativeApprox.Kruger, true,
        //                                                      CubicInterpolation.BoundaryCondition.SecondDerivative , 0.0,
        //                                                      CubicInterpolation.BoundaryCondition.SecondDerivative , 0.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");

            europeanOption.theta();

            // 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();
        }
        private void testFdGreeks <Engine>(Date today, Exercise exercise) where Engine : IFDEngine, new ()
        {
            Dictionary <string, double> calculated = new Dictionary <string, double>(),
                                        expected   = new Dictionary <string, double>(),
                                        tolerance  = new Dictionary <string, double>();

            tolerance.Add("delta", 5.0e-3);
            tolerance.Add("gamma", 7.0e-3);
            // tolerance["theta"] = 1.0e-2;

            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.20 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            double[]      vols        = { 0.05, 0.20, 0.50 };

            DayCounter dc = new Actual360();

            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++)
                {
                    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 = FastActivator <Engine> .Create().factory(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);

                                    // FLOATING_POINT_EXCEPTION
                                    double value = option.NPV();
                                    calculated["delta"] = option.delta();
                                    calculated["gamma"] = option.gamma();
                                    // calculated["theta"]  = option.theta();

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

                                        // perturb date and get theta

                                        /*
                                         * Time dT = dc.yearFraction(today-1, today+1);
                                         * Settings::instance().evaluationDate() = today-1;
                                         * value_m = option.NPV();
                                         * Settings::instance().evaluationDate() = today+1;
                                         * value_p = option.NPV();
                                         * Settings::instance().evaluationDate() = today;
                                         * expected["theta"] = (value_p - value_m)/dT;
                                         */

                                        // compare
                                        foreach (string greek in calculated.Keys)
                                        {
                                            double expct      = expected[greek],
                                                        calcl = calculated[greek],
                                                        tol   = tolerance[greek];
                                            double error      = Utilities.relativeError(expct, calcl, u);
                                            if (error > tol)
                                            {
                                                REPORT_FAILURE(greek, payoff, exercise,
                                                               u, q, r, today, v,
                                                               expct, calcl, error, tol);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        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.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] == QLNet.Option.Type.Put) ? "Put" : "Call"));
                        }
                    }
                }
            }
        }
        public void testFdEuropeanValues()
        {
            // Testing finite-difference dividend European option values...
            using (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.Instance.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 testDiscretizationError()
        {
            // Testing the discretization error of the Heston Hull-White process
            DayCounter dc    = new Actual360();
            Date       today = Date.Today;

            Settings.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);
                    }
                }
            }
        }
Example #21
0
        static void Main(string[] args)
        {
            try
            {
                Option.Type type       = Option.Type.Put;
                double      underlying = 36.0;
                double      spreadRate = 0.005;

                double dividendYield = 0.02;
                double riskFreeRate  = 0.06;
                double volatility    = 0.2;

                int    settlementDays  = 3;
                int    length          = 5;
                double redemption      = 100.0;
                double conversionRatio = redemption / underlying; // at the money

                // set up dates/schedules
                Calendar calendar = new TARGET();
                Date     today    = calendar.adjust(Date.Today);

                Settings.setEvaluationDate(today);
                Date settlementDate = calendar.advance(today, settlementDays, TimeUnit.Days);
                Date exerciseDate   = calendar.advance(settlementDate, length, TimeUnit.Years);
                Date issueDate      = calendar.advance(exerciseDate, -length, TimeUnit.Years);

                BusinessDayConvention convention = BusinessDayConvention.ModifiedFollowing;

                Frequency frequency = Frequency.Annual;

                Schedule schedule = new Schedule(issueDate, exerciseDate,
                                                 new Period(frequency), calendar, convention, convention,
                                                 DateGeneration.Rule.Backward, false);

                DividendSchedule    dividends   = new DividendSchedule();
                CallabilitySchedule callability = new CallabilitySchedule();

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

                int[] callLength = { 2, 4 }; // Call dates, years 2,4.
                int[] putLength  = { 3 };    // Put dates year 3.

                double[] callPrices = { 101.5, 100.85 };
                double[] putPrices  = { 105.0 };

                // Load call schedules
                for (int i = 0; i < callLength.Length; i++)
                {
                    SoftCallability s = new SoftCallability(
                        new Callability.Price(callPrices[i], Callability.Price.Type.Clean), schedule.date(callLength[i]),
                        1.20);
                    callability.Add(s);
                }

                for (int j = 0; j < putLength.Length; j++)
                {
                    Callability s = new Callability(new Callability.Price(putPrices[j], Callability.Price.Type.Clean),
                                                    Callability.Type.Put, schedule.date(putLength[j]));
                    callability.Add(s);
                }

                // Assume dividends are paid every 6 months .
                for (Date d = today + new Period(6, TimeUnit.Months); d < exerciseDate; d += new Period(6, TimeUnit.Months))
                {
                    Dividend div = new FixedDividend(1.0, d);
                    dividends.Add(div);
                }

                DayCounter dayCounter = new Actual365Fixed();
                double     maturity   = dayCounter.yearFraction(settlementDate, exerciseDate);

                Console.WriteLine("option type = " + type);
                Console.WriteLine("Time to maturity = " + maturity);
                Console.WriteLine("Underlying price = " + underlying);
                Console.WriteLine("Risk-free interest rate = {0:0.0%}", riskFreeRate);
                Console.WriteLine("Dividend yield = {0:0.0%}%", dividendYield);
                Console.WriteLine("Volatility = {0:0.0%}%", volatility);
                Console.WriteLine("");


                // write column headings
                int[]  widths     = { 35, 14, 14 };
                int    totalWidth = widths[0] + widths[1] + widths[2];
                string rule       = new string('-', totalWidth);
                string dblrule    = new string('=', totalWidth);

                Console.WriteLine(dblrule);
                Console.WriteLine("Tsiveriotis-Fernandes method");
                Console.WriteLine(dblrule);
                Console.WriteLine("Tree Type                           European     American        ");
                Console.WriteLine(rule);


                Exercise exercise   = new EuropeanExercise(exerciseDate);
                Exercise amexercise = new AmericanExercise(settlementDate, exerciseDate);

                Handle <Quote> underlyingH = new Handle <Quote>(new SimpleQuote(underlying));
                Handle <YieldTermStructure> flatTermStructure =
                    new Handle <YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter));
                Handle <YieldTermStructure> flatDividendTS =
                    new Handle <YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter));
                Handle <BlackVolTermStructure> flatVolTS =
                    new Handle <BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, volatility,
                                                                            dayCounter));

                BlackScholesMertonProcess stochasticProcess =
                    new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS);

                int timeSteps = 801;

                Handle <Quote> creditSpread = new Handle <Quote>(new SimpleQuote(spreadRate));

                Quote rate = new SimpleQuote(riskFreeRate);

                Handle <YieldTermStructure> discountCurve =
                    new Handle <YieldTermStructure>(new FlatForward(today, new Handle <Quote>(rate), dayCounter));

                IPricingEngine engine = new BinomialConvertibleEngine <JarrowRudd>(stochasticProcess, timeSteps);

                ConvertibleFixedCouponBond europeanBond = new ConvertibleFixedCouponBond(exercise, conversionRatio,
                                                                                         dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule,
                                                                                         redemption);

                europeanBond.setPricingEngine(engine);

                ConvertibleFixedCouponBond americanBond = new ConvertibleFixedCouponBond(amexercise, conversionRatio,
                                                                                         dividends, callability, creditSpread, issueDate, settlementDays, coupons, bondDayCount, schedule,
                                                                                         redemption);
                americanBond.setPricingEngine(engine);


                Console.WriteLine("Jarrow-Rudd                         {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <CoxRossRubinstein>(stochasticProcess, timeSteps));

                Console.WriteLine("CoxRossRubinstein                   {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <AdditiveEQPBinomialTree>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <AdditiveEQPBinomialTree>(stochasticProcess, timeSteps));

                Console.WriteLine("AdditiveEQPBinomialTree             {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <Trigeorgis>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <Trigeorgis>(stochasticProcess, timeSteps));

                Console.WriteLine("Trigeorgis                          {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <Tian>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <Tian>(stochasticProcess, timeSteps));

                Console.WriteLine("Tian                                {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <LeisenReimer>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <LeisenReimer>(stochasticProcess, timeSteps));

                Console.WriteLine("LeisenReimer                        {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());

                americanBond.setPricingEngine(new BinomialConvertibleEngine <Joshi4>(stochasticProcess, timeSteps));
                europeanBond.setPricingEngine(new BinomialConvertibleEngine <Joshi4>(stochasticProcess, timeSteps));

                Console.WriteLine("Joshi4                              {0:0.000000}   {1:0.000000}", europeanBond.NPV(), americanBond.NPV());
                Console.WriteLine("===========================================================================");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            Console.ReadKey();
        }
Example #22
0
        public void testCashOrNothingHaugValues()
        {
            // Testing cash-or-nothing barrier options against Haug's values

            BinaryOptionData[] values =
            {
                /* The data below are from
                 * "Option pricing formulas 2nd Ed.", E.G. Haug, McGraw-Hill 2007 pag. 180 - cases 13,14,17,18,21,22,25,26
                 * Note:
                 * q is the dividend rate, while the book gives b, the cost of carry (q=r-b)
                 */
                //    barrierType, barrier,  cash,         type, strike,   spot,    q,    r,   t,  vol,   value, tol
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call, 102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.9289, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  6.2150, 1e-4),
                // following value is wrong in book.
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  5.8926, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  7.4519, 1e-4),
                // 17,18
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,  102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.4314, 1e-4),
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,   98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  3.1454, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,  102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  5.3297, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,   98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.7704, 1e-4),
                // 21,22
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call, 102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.8758, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  4.9081, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  0.0407, 1e-4),
                // 25,26
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,  102.00, 105.00,  0.00, 0.10, 0.5, 0.20,  0.0323, 1e-4),
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,   98.00, 105.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,  102.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.0461, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,   98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  3.0054, 1e-4),

                // other values calculated with book vba
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00, -0.14, 0.10, 0.5, 0.20,  8.6806, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call, 102.00,  95.00,  0.03, 0.10, 0.5, 0.20,  5.3112, 1e-4),
                // degenerate conditions (barrier touched)
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Call,  98.00,  95.00,  0.00, 0.10, 0.5, 0.20,  7.4926, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Call,  98.00, 105.00,  0.00, 0.10, 0.5, 0.20, 11.1231, 1e-4),
                // 17,18
                new BinaryOptionData(Barrier.Type.DownIn,  100.00, 15.00, Option.Type.Put,  102.00,  98.00,  0.00, 0.10, 0.5, 0.20,  7.1344, 1e-4),
                new BinaryOptionData(Barrier.Type.UpIn,    100.00, 15.00, Option.Type.Put,  102.00, 101.00,  0.00, 0.10, 0.5, 0.20,  5.9299, 1e-4),
                // 21,22
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Call,  98.00,  99.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Call,  98.00, 101.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                // 25,26
                new BinaryOptionData(Barrier.Type.DownOut, 100.00, 15.00, Option.Type.Put,   98.00,  99.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
                new BinaryOptionData(Barrier.Type.UpOut,   100.00, 15.00, Option.Type.Put,   98.00, 101.00,  0.00, 0.10, 0.5, 0.20,  0.0000, 1e-4),
            };

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

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

            for (int i = 0; i < values.Length; i++)
            {
                StrikedTypePayoff payoff = new CashOrNothingPayoff(values[i].type, values[i].strike, values[i].cash);

                Date     exDate     = today + Convert.ToInt32(values[i].t * 360 + 0.5);
                Exercise amExercise = new AmericanExercise(today, exDate, true);

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

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

                IPricingEngine engine = new AnalyticBinaryBarrierEngine(stochProcess);

                BarrierOption opt = new BarrierOption(values[i].barrierType, values[i].barrier, 0, payoff, amExercise);

                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].barrierType,
                                   values[i].barrier, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol);
                }
            }
        }
Example #23
0
        public void testBaroneAdesiWhaleyValues()
        {
            // ("Testing Barone-Adesi and Whaley approximation for American options...");

            /* The data below are from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 pag 24
             *
             * The following values were replicated only up to the second digit
             * by the VB code provided by Haug, which was used as base for the
             * C++ implementation
             *
             */
            AmericanOptionData[] values =
            {
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  0.0206),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8771),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15, 10.0089),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.25,  0.3159),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1280),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3919),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.35,  0.9495),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3777),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1679),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.15,  0.8208),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0842),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.8087),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.25,  2.7437),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.8015),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 13.0170),
                new AmericanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.35,  5.0063),
                new AmericanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.5106),
                new AmericanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.5689),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.15, 10.0000),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8770),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  0.0410),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.25, 10.2533),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1277),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.25,  0.4562),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.35, 10.8787),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3777),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.35,  1.2402),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.15, 10.5595),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0842),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.15,  1.0822),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.25, 12.4419),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.8014),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.25,  3.3226),
                new AmericanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.35, 14.6945),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.5104),
                new AmericanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 5.8823)
            };

            Date               today = Date.Today;
            DayCounter         dc    = new Actual360();
            SimpleQuote        spot  = new SimpleQuote(0.0);
            SimpleQuote        qRate = new SimpleQuote(0.0);
            YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            double tolerance = 3.0e-3;

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

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

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

                IPricingEngine engine = new BaroneAdesiWhaleyApproximationEngine(stochProcess);

                VanillaOption option = new VanillaOption(payoff, exercise);
                option.setPricingEngine(engine);

                double calculated = option.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > tolerance)
                {
                    REPORT_FAILURE("value", payoff, exercise, values[i].s, values[i].q,
                                   values[i].r, today, values[i].v, values[i].result,
                                   calculated, error, tolerance);
                }
            }
        }
Example #24
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);
                }
            }
        }
Example #25
0
        public void testFdGreeks <Engine>() where Engine : IFDEngine, new()
        {
            //SavedSettings backup;

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

            tolerance.Add("delta", 7.0e-4);
            tolerance.Add("gamma", 2.0e-4);
            //tolerance["theta"]  = 1.0e-4;

            Option.Type[] types       = new Option.Type[] { Option.Type.Call, Option.Type.Put };
            double[]      strikes     = { 50.0, 99.5, 100.0, 100.5, 150.0 };
            double[]      underlyings = { 100.0 };
            double[]      qRates      = { 0.04, 0.05, 0.06 };
            double[]      rRates      = { 0.01, 0.05, 0.15 };
            int[]         years       = { 1, 2 };
            double[]      vols        = { 0.11, 0.50, 1.20 };

            Date today = Date.Today;

            Settings.setEvaluationDate(today);

            DayCounter         dc    = new Actual360();
            SimpleQuote        spot  = new SimpleQuote(0.0);
            SimpleQuote        qRate = new SimpleQuote(0.0);
            YieldTermStructure qTS   = Utilities.flatRate(today, qRate, dc);

            SimpleQuote           rRate = new SimpleQuote(0.0);
            YieldTermStructure    rTS   = Utilities.flatRate(today, rRate, dc);
            SimpleQuote           vol   = new SimpleQuote(0.0);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

            for (int i = 0; i < types.Length; i++)
            {
                for (int j = 0; j < strikes.Length; j++)
                {
                    for (int k = 0; k < years.Length; k++)
                    {
                        Date                      exDate       = today + new Period(years[k], TimeUnit.Years);
                        Exercise                  exercise     = new AmericanExercise(today, exDate);
                        StrikedTypePayoff         payoff       = new PlainVanillaPayoff(types[i], strikes[j]);
                        BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot),
                                                                                               new Handle <YieldTermStructure>(qTS),
                                                                                               new Handle <YieldTermStructure>(rTS),
                                                                                               new Handle <BlackVolTermStructure>(volTS));

                        IPricingEngine engine = new Engine().factory(stochProcess);

                        VanillaOption option = new VanillaOption(payoff, exercise);
                        option.setPricingEngine(engine);

                        for (int l = 0; l < underlyings.Length; l++)
                        {
                            for (int m = 0; m < qRates.Length; m++)
                            {
                                for (int n = 0; n < rRates.Length; n++)
                                {
                                    for (int p = 0; p < vols.Length; p++)
                                    {
                                        double u = underlyings[l];
                                        double q = qRates[m],
                                               r = rRates[n];
                                        double v = vols[p];
                                        spot.setValue(u);
                                        qRate.setValue(q);
                                        rRate.setValue(r);
                                        vol.setValue(v);

                                        double value = option.NPV();
                                        calculated.Add("delta", option.delta());
                                        calculated.Add("gamma", option.gamma());
                                        //calculated["theta"]  = option.theta();

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

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

                                            // compare
                                            foreach (string greek in calculated.Keys)
                                            {
                                                double expct      = expected  [greek],
                                                            calcl = calculated[greek],
                                                            tol   = tolerance [greek];
                                                double error      = Utilities.relativeError(expct, calcl, u);
                                                if (error > tol)
                                                {
                                                    REPORT_FAILURE(greek, payoff, exercise,
                                                                   u, q, r, today, v,
                                                                   expct, calcl, error, tol);
                                                }
                                            }
                                        }
                                        calculated.Clear();
                                        expected.Clear();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #26
0
        private void testForwardGreeks(Type engine_type)
        {
            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 };
            int[]         startMonths = { 6, 9 };
            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 stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS);

            IPricingEngine engine = engine_type == typeof(ForwardVanillaEngine) ? new ForwardVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process)) :
                                    new ForwardPerformanceVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process));

            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 h = 0; h < startMonths.Length; h++)
                        {
                            Date     exDate   = today + new Period(lengths[k], TimeUnit.Years);
                            Exercise exercise = new EuropeanExercise(exDate);

                            Date reset = today + new Period(startMonths[h], TimeUnit.Months);

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

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

                            for (int l = 0; l < underlyings.Length; l++)
                            {
                                for (int m = 0; m < qRates.Length; m++)
                                {
                                    for (int n = 0; n < rRates.Length; n++)
                                    {
                                        for (int p = 0; p < vols.Length; p++)
                                        {
                                            double u = underlyings[l];
                                            double q = qRates[m],
                                                   r = rRates[n];
                                            double v = vols[p];
                                            spot.setValue(u);
                                            qRate.setValue(q);
                                            rRate.setValue(r);
                                            vol.setValue(v);

                                            double value = option.NPV();
                                            calculated["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
                                                //std::map<std::string,double>::iterator it;
                                                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,
                                                                       moneyness[j], reset,
                                                                       expct, calcl, error, tol);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #27
0
        private static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;

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

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

            Settings.instance().setEvaluationDate(todaysDate);

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

            Calendar calendar = new TARGET();

            var exerciseDates = new DateVector(4);

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

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

            // bootstrap the yield/dividend/vol curves and create a BlackScholesMerton stochastic process
            DayCounter dayCounter        = new Actual365Fixed();
            var        flatRateTSH       = new YieldTermStructureHandle(new FlatForward(settlementDate, riskFreeRate, dayCounter));
            var        flatDividendTSH   = new YieldTermStructureHandle(new FlatForward(settlementDate, dividendYield, dayCounter));
            var        flatVolTSH        = new BlackVolTermStructureHandle(new BlackConstantVol(settlementDate, calendar, volatility, dayCounter));
            var        underlyingQuoteH  = new QuoteHandle(new SimpleQuote(underlyingPrice));
            var        stochasticProcess = new BlackScholesMertonProcess(underlyingQuoteH, flatDividendTSH, flatRateTSH, flatVolTSH);
            var        payoff            = new PlainVanillaPayoff(optionType, strikePrice);

            // options
            var europeanOption = new VanillaOption(payoff, europeanExercise);
            var bermudanOption = new VanillaOption(payoff, bermudanExercise);
            var 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 FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1));
                bermudanOption.setPricingEngine(new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1));
                americanOption.setPricingEngine(new FdBlackScholesVanillaEngine(stochasticProcess, timeSteps, timeSteps - 1));
                ReportResults("Finite differences", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

            //Variance Gamma
            try
            {
                var 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 BinomialJRVanillaEngine(stochasticProcess, timeSteps));
                bermudanOption.setPricingEngine(new BinomialJRVanillaEngine(stochasticProcess, timeSteps));
                americanOption.setPricingEngine(new BinomialJRVanillaEngine(stochasticProcess, 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 BinomialCRRVanillaEngine(stochasticProcess, timeSteps));
                bermudanOption.setPricingEngine(new BinomialCRRVanillaEngine(stochasticProcess, timeSteps));
                americanOption.setPricingEngine(new BinomialCRRVanillaEngine(stochasticProcess, 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 BinomialEQPVanillaEngine(stochasticProcess, timeSteps));
                bermudanOption.setPricingEngine(new BinomialEQPVanillaEngine(stochasticProcess, timeSteps));
                americanOption.setPricingEngine(new BinomialEQPVanillaEngine(stochasticProcess, timeSteps));
                ReportResults("Additive Equiprobabilities", europeanOption.NPV(), bermudanOption.NPV(), americanOption.NPV());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

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

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

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

            // Binomial Joshi
            try
            {
                europeanOption.setPricingEngine(new BinomialJ4VanillaEngine(stochasticProcess, timeSteps));
                bermudanOption.setPricingEngine(new BinomialJ4VanillaEngine(stochasticProcess, timeSteps));
                americanOption.setPricingEngine(new BinomialJ4VanillaEngine(stochasticProcess, 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
            {
                int    mcTimeSteps       = 1;
                int    timeStepsPerYear  = int.MaxValue;
                bool   brownianBridge    = false;
                bool   antitheticVariate = false;
                int    requiredSamples   = int.MaxValue;
                double requiredTolerance = 0.02;
                int    maxSamples        = int.MaxValue;
                int    seed = 42;
                europeanOption.setPricingEngine(new MCPREuropeanEngine(stochasticProcess, 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
            {
                int    mcTimeSteps       = 1;
                int    timeStepsPerYear  = int.MaxValue;
                bool   brownianBridge    = false;
                bool   antitheticVariate = false;
                int    requiredSamples   = 32768; // 2^15
                double requiredTolerance = double.MaxValue;
                int    maxSamples        = int.MaxValue;
                int    seed = 0;
                europeanOption.setPricingEngine(new MCLDEuropeanEngine(stochasticProcess, mcTimeSteps, timeStepsPerYear, brownianBridge, antitheticVariate, requiredSamples,
                                                                       requiredTolerance, maxSamples, seed));
                ReportResults("MC (Sobol)", europeanOption.NPV(), 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();
        }
Example #28
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);
                }
            }
        }
Example #29
0
        public void testDeltaPriceConsistency()
        {
            // Testing premium-adjusted delta price consistency

            // This function tests for price consistencies with the standard
            // Black Scholes calculator, since premium adjusted deltas can be calculated
            // from spot deltas by adding/subtracting the premium.

            SavedSettings backup = new SavedSettings();

            // actually, value and tol won't be needed for testing
            EuropeanOptionData[] values =
            {
                //        type, strike,   spot,    rd,    rf,    t,  vol,   value,    tol
                new EuropeanOptionData(Option.Type.Call, 0.9123, 1.2212, 0.0231, 0.0000, 0.25, 0.301, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 0.9234, 1.2212, 0.0231, 0.0000, 0.35, 0.111, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 0.9783, 1.2212, 0.0231, 0.0000, 0.45, 0.071, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.0000, 1.2212, 0.0231, 0.0000, 0.55, 0.082, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.1230, 1.2212, 0.0231, 0.0000, 0.65, 0.012, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.2212, 1.2212, 0.0231, 0.0000, 0.75, 0.129, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3212, 1.2212, 0.0231, 0.0000, 0.85, 0.034, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3923, 1.2212, 0.0131, 0.2344, 0.95, 0.001, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Call, 1.3455, 1.2212, 0.0000, 0.0000, 1.00, 0.127, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9123, 1.2212, 0.0231, 0.0000, 0.25, 0.301, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9234, 1.2212, 0.0231, 0.0000, 0.35, 0.111, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  0.9783, 1.2212, 0.0231, 0.0000, 0.45, 0.071, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.0000, 1.2212, 0.0231, 0.0000, 0.55, 0.082, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.1230, 1.2212, 0.0231, 0.0000, 0.65, 0.012, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.2212, 1.2212, 0.0231, 0.0000, 0.75, 0.129, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3212, 1.2212, 0.0231, 0.0000, 0.85, 0.034, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3923, 1.2212, 0.0131, 0.2344, 0.95, 0.001, 0.0, 0.0),
                new EuropeanOptionData(Option.Type.Put,  1.3455, 1.2212, 0.0000, 0.0000, 1.00, 0.127, 0.0, 0.0),
                // extreme case: zero vol
                new EuropeanOptionData(Option.Type.Put,  1.3455, 1.2212, 0.0000, 0.0000, 0.50, 0.000, 0.0, 0.0),
                // extreme case: zero strike
                new EuropeanOptionData(Option.Type.Put,  0.0000, 1.2212, 0.0000, 0.0000, 1.50, 0.133, 0.0, 0.0),
                // extreme case: zero strike+zero vol
                new EuropeanOptionData(Option.Type.Put,  0.0000, 1.2212, 0.0000, 0.0000, 1.00, 0.133, 0.0, 0.0),
            };

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

            // Start setup of market data

            double discFor       = 0.0;
            double discDom       = 0.0;
            double implVol       = 0.0;
            double expectedVal   = 0.0;
            double calculatedVal = 0.0;
            double error         = 0.0;

            SimpleQuote    spotQuote  = new SimpleQuote(0.0);
            Handle <Quote> spotHandle = new Handle <Quote>(spotQuote);

            SimpleQuote        qQuote  = new SimpleQuote(0.0);
            Handle <Quote>     qHandle = new Handle <Quote>(qQuote);
            YieldTermStructure qTS     = new FlatForward(today, qHandle, dc);

            SimpleQuote        rQuote  = new SimpleQuote(0.0);
            Handle <Quote>     rHandle = new Handle <Quote>(qQuote);
            YieldTermStructure rTS     = new FlatForward(today, rHandle, dc);

            SimpleQuote           volQuote  = new SimpleQuote(0.0);
            Handle <Quote>        volHandle = new Handle <Quote>(volQuote);
            BlackVolTermStructure volTS     = new BlackConstantVol(today, calendar, volHandle, dc);

            BlackScholesMertonProcess stochProcess;
            IPricingEngine            engine;
            StrikedTypePayoff         payoff;
            Date     exDate;
            Exercise exercise;
            // Setup of market data finished

            double tolerance = 1.0e-10;

            for (int i = 0; i < values.Length; ++i)
            {
                payoff   = new PlainVanillaPayoff(values[i].type, values[i].strike);
                exDate   = today + timeToDays(values[i].t);
                exercise = new EuropeanExercise(exDate);

                spotQuote.setValue(values[i].s);
                volQuote.setValue(values[i].v);
                rQuote.setValue(values[i].r);
                qQuote.setValue(values[i].q);

                discDom = rTS.discount(exDate);
                discFor = qTS.discount(exDate);
                implVol = Math.Sqrt(volTS.blackVariance(exDate, 0.0));

                BlackDeltaCalculator myCalc = new BlackDeltaCalculator(values[i].type, DeltaVolQuote.DeltaType.PaSpot,
                                                                       spotQuote.value(), discDom, discFor, implVol);

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

                engine = new AnalyticEuropeanEngine(stochProcess);

                EuropeanOption option = new EuropeanOption(payoff, exercise);
                option.setPricingEngine(engine);

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = option.delta() - option.NPV() / spotQuote.value();
                error         = Math.Abs(expectedVal - calculatedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Premium-adjusted spot delta test failed. \n"
                                 + "Calculated Delta: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaFwd);

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = expectedVal / discFor; // Premium adjusted Fwd Delta is PA spot without discount
                error         = Math.Abs(expectedVal - calculatedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Premium-adjusted forward delta test failed. \n"
                                 + "Calculated Delta: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }


                // Test consistency with BlackScholes Calculator for Spot Delta
                myCalc.setDeltaType(DeltaVolQuote.DeltaType.Spot);

                calculatedVal = myCalc.deltaFromStrike(values[i].strike);
                expectedVal   = option.delta();
                error         = Math.Abs(calculatedVal - expectedVal);

                if (error > tolerance)
                {
                    QAssert.Fail("\n spot delta in BlackDeltaCalculator differs from delta in BlackScholesCalculator. \n"
                                 + "Calculated Value: " + calculatedVal + "\n"
                                 + "Expected Value:   " + expectedVal + "\n"
                                 + "Error: " + error);
                }
            }
        }
Example #30
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);
                //}
            }
        }
Example #31
0
        public static string eqInstAmericanOptionBaroneAdesiWhaley(
            [ExcelArgument(Description = "id of option to be constructed ")] string ObjectId,
            [ExcelArgument(Description = "Option type ")] string optype,
            [ExcelArgument(Description = "Spot price ")] double underlyingprice,
            [ExcelArgument(Description = "Strike price ")] double stirkeprice,
            [ExcelArgument(Description = "Expiry Date ")] DateTime date,
            [ExcelArgument(Description = "Risk free rate ")] double riskfreerate,
            [ExcelArgument(Description = "dividend/convenience rate ")] double dividendrate,
            [ExcelArgument(Description = "Black-Scholes Vol ")] double volatility,
            [ExcelArgument(Description = "DayCounter ")] string daycounter,
            [ExcelArgument(Description = "Calendar ")] string calendar,
            [ExcelArgument(Description = "trigger ")] object trigger)
        {
            if (ExcelUtil.CallFromWizard())
            {
                return("");
            }

            string callerAddress = "";

            callerAddress = ExcelUtil.getActiveCellAddress();

            try
            {
                if (date == DateTime.MinValue)
                {
                    throw new Exception("Date must not be empty. ");
                }

                if (ExcelUtil.isNull(daycounter))
                {
                    daycounter = "ACTUAL365";
                }
                if (ExcelUtil.isNull(calendar))
                {
                    calendar = "NYC";
                }

                Option.Type optiontype;
                if (optype.ToUpper() == "CALL")
                {
                    optiontype = Option.Type.Call;
                }
                else if (optype.ToUpper() == "PUT")
                {
                    optiontype = Option.Type.Put;
                }
                else
                {
                    throw new Exception("Unknow option type");
                }

                EliteQuant.Calendar   cal          = EliteQuant.EQConverter.ConvertObject <EliteQuant.Calendar>(calendar);
                EliteQuant.DayCounter dc           = EliteQuant.EQConverter.ConvertObject <EliteQuant.DayCounter>(daycounter);
                EliteQuant.Date       maturitydate = EliteQuant.EQConverter.ConvertObject <EliteQuant.Date>(date);

                EliteQuant.Date today          = EliteQuant.Settings.instance().getEvaluationDate();
                EliteQuant.Date settlementdate = today;           // T+2
                if (maturitydate.serialNumber() <= today.serialNumber())
                {
                    throw new Exception("Option already expired.");
                }

                AmericanExercise americanExercise = new AmericanExercise(today, maturitydate);

                QuoteHandle underlyingQuoteH = new QuoteHandle(new EliteQuant.SimpleQuote(underlyingprice));

                YieldTermStructureHandle flatRateTSH = new YieldTermStructureHandle(
                    new FlatForward(settlementdate, riskfreerate, dc));
                YieldTermStructureHandle flatDividendTSH = new YieldTermStructureHandle(
                    new FlatForward(settlementdate, dividendrate, dc));

                BlackVolTermStructureHandle flatVolTSH = new BlackVolTermStructureHandle(
                    new BlackConstantVol(settlementdate, cal, volatility, dc));

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

                PlainVanillaPayoff payoff = new PlainVanillaPayoff(optiontype, stirkeprice);

                VanillaOption europeanOption = new VanillaOption(payoff, americanExercise);

                europeanOption.setPricingEngine(new BaroneAdesiWhaleyEngine(stochasticProcess));

                // Store the option and return its id
                string id = "OPTION@" + ObjectId;
                OHRepository.Instance.storeObject(id, europeanOption, callerAddress);
                id += "#" + (String)DateTime.Now.ToString(@"HH:mm:ss");
                return(id);
            }
            catch (Exception e)
            {
                ExcelUtil.logError(callerAddress, System.Reflection.MethodInfo.GetCurrentMethod().Name.ToString(), e.Message);
                return("#EQ_ERR!");
            }
        }