private void getSuggestedJobsCallback(object sender, SimpleQuote.SuggestJobsCompletedEventArgs e)
        {
            if (e.Result.Count > 0)
            {
                m_suggestedJobs = e.Result.ToArray();
            }

            m_suggestedJobsWait.Set();
            ShowSuggestedJobsData();
        }
        //
        //  Async callback from when we get a response from the quote
        //
        void client_GetQuoteCompleted(object sender, SimpleQuote.GetQuoteCompletedEventArgs e)
        {
            LoadingPanel.Visibility = System.Windows.Visibility.Collapsed;
            ResultsPanel.Visibility = System.Windows.Visibility.Visible;

            // HACK: Silverlight ONLY SUPPORTS JPEG images.  The PayScale webservice only returns PNGs.  I found this little script
            //       in the PHP documentation, and ported it to my needs.  hopefully nobody abuses the script (or roots my wedding website)
            string url = "http://www.adamandmckenna.com/tmp/png2jpg.php?img=http://www.payscale.com" + e.Result.ChartUrl;

            // Get the Image
            WebClient webClientImgDownloader = new WebClient();
            webClientImgDownloader.OpenReadCompleted += new OpenReadCompletedEventHandler(webClientImgDownloader_OpenReadCompleted);
            webClientImgDownloader.OpenReadAsync(new Uri(url));

            // Formatting the lines of text for display
            TwentyFifth.Text = "25th Percentile: $" + Math.Round(e.Result.Percentile25,2).ToString();
            Fiftieth.Text = "50th Percentile: $" + Math.Round(e.Result.Median,2).ToString();
            SeventyFifth.Text = "75th Percentile: $" + Math.Round(e.Result.Percentile75,2).ToString();
            Location.Text = e.Result.LocationType + ": " + e.Result.LocationRegion;
            Job.Text = "Job: " + m_selectedJob;
        }
Ejemplo n.º 3
0
        public void testBootstrap()
        {
            // Testing Eonia-swap curve building...
            CommonVars vars = new CommonVars();

            List <RateHelper> eoniaHelpers  = new List <RateHelper>();
            List <RateHelper> swap3mHelpers = new List <RateHelper>();

            IborIndex euribor3m = new Euribor3M();
            Eonia     eonia     = new Eonia();

            for (int i = 0; i < depositData.Length; i++)
            {
                double         rate   = 0.01 * depositData[i].rate;
                SimpleQuote    simple = new SimpleQuote(rate);
                Handle <Quote> quote  = new Handle <Quote>(simple);

                Period     term   = new Period(depositData[i].n, depositData[i].unit);
                RateHelper helper = new DepositRateHelper(quote,
                                                          term,
                                                          depositData[i].settlementDays,
                                                          euribor3m.fixingCalendar(),
                                                          euribor3m.businessDayConvention(),
                                                          euribor3m.endOfMonth(),
                                                          euribor3m.dayCounter());


                if (term <= new Period(2, TimeUnit.Days))
                {
                    eoniaHelpers.Add(helper);
                }
                if (term <= new Period(3, TimeUnit.Months))
                {
                    swap3mHelpers.Add(helper);
                }
            }


            for (int i = 0; i < fraData.Length; i++)
            {
                double         rate   = 0.01 * fraData[i].rate;
                SimpleQuote    simple = new SimpleQuote(rate);
                Handle <Quote> quote  = new Handle <Quote>(simple);
                RateHelper     helper = new FraRateHelper(quote,
                                                          fraData[i].nExpiry,
                                                          fraData[i].nMaturity,
                                                          fraData[i].settlementDays,
                                                          euribor3m.fixingCalendar(),
                                                          euribor3m.businessDayConvention(),
                                                          euribor3m.endOfMonth(),
                                                          euribor3m.dayCounter());
                swap3mHelpers.Add(helper);
            }

            for (int i = 0; i < eoniaSwapData.Length; i++)
            {
                double         rate   = 0.01 * eoniaSwapData[i].rate;
                SimpleQuote    simple = new SimpleQuote(rate);
                Handle <Quote> quote  = new Handle <Quote>(simple);
                Period         term   = new Period(eoniaSwapData[i].n, eoniaSwapData[i].unit);
                RateHelper     helper = new OISRateHelper(eoniaSwapData[i].settlementDays,
                                                          term,
                                                          quote,
                                                          eonia);
                eoniaHelpers.Add(helper);
            }


            for (int i = 0; i < swapData.Length; i++)
            {
                double         rate   = 0.01 * swapData[i].rate;
                SimpleQuote    simple = new SimpleQuote(rate);
                Handle <Quote> quote  = new Handle <Quote>(simple);
                Period         tenor  = new Period(swapData[i].nIndexUnits, swapData[i].indexUnit);
                Period         term   = new Period(swapData[i].nTermUnits, swapData[i].termUnit);

                RateHelper helper = new SwapRateHelper(quote,
                                                       term,
                                                       vars.calendar,
                                                       vars.fixedSwapFrequency,
                                                       vars.fixedSwapConvention,
                                                       vars.fixedSwapDayCount,
                                                       euribor3m);
                if (tenor == new Period(3, TimeUnit.Months))
                {
                    swap3mHelpers.Add(helper);
                }
            }


            PiecewiseYieldCurve <Discount, LogLinear> eoniaTS = new PiecewiseYieldCurve <Discount, LogLinear>(vars.today,
                                                                                                              eoniaHelpers,
                                                                                                              new Actual365Fixed());

            PiecewiseYieldCurve <Discount, LogLinear> swapTS = new PiecewiseYieldCurve <Discount, LogLinear>(vars.today,
                                                                                                             swap3mHelpers,
                                                                                                             new Actual365Fixed());

            vars.eoniaTermStructure.linkTo(eoniaTS);

            // test curve consistency
            double tolerance = 1.0e-10;

            for (int i = 0; i < eoniaSwapData.Length; i++)
            {
                double expected           = eoniaSwapData[i].rate;
                Period term               = new Period(eoniaSwapData[i].n, eoniaSwapData[i].unit);
                OvernightIndexedSwap swap = vars.makeSwap(term, 0.0, 0.0);
                double?calculated         = 100.0 * swap.fairRate();

                if (Math.Abs(expected - calculated.Value) > tolerance)
                {
                    QAssert.Fail("curve inconsistency:\n"
                                 + "    swap length:     " + term + "\n"
                                 + "    quoted rate:     " + expected + "\n"
                                 + "    calculated rate: " + calculated);
                }
            }
        }
Ejemplo n.º 4
0
        public void testCashAtHitOrNothingAmericanGreeks()
        {
            // Testing American cash-(at-hit)-or-nothing digital option greeks

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

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

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

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

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

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

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

                IPricingEngine euroEngine = new AnalyticEuropeanEngine(stochProcess);

                IPricingEngine amEngine = new AnalyticDigitalAmericanEngine(stochProcess);

                IPricingEngine[] engines = { euroEngine, amEngine };

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

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

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

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

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

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

                                                // check
                                                //std::map<std::string,Real>::iterator it;
                                                foreach (var it in calculated)
                                                {
                                                    string greek = it.Key;
                                                    double expct = expected  [greek],
                                                           calcl = calculated[greek],
                                                           tol   = tolerance [greek];
                                                    double error = Utilities.relativeError(expct, calcl, value);
                                                    if (error > tol)
                                                    {
                                                        REPORT_FAILURE(greek, payoff, exercise,
                                                                       u, q, r, today, v,
                                                                       expct, calcl, error, tol, knockin);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 5
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);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 6
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);
            }
        }
Ejemplo n.º 7
0
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;

            Date     todaysDate     = new Date(15, Month.February, 2002);
            Calendar calendar       = new TARGET();
            Date     settlementDate = new Date(19, Month.February, 2002);

            Settings.instance().setEvaluationDate(todaysDate);

            // flat yield term structure impling 1x5 swap at 5%
            Quote       flatRate        = new SimpleQuote(0.04875825);
            FlatForward myTermStructure = new FlatForward(
                settlementDate,
                new QuoteHandle(flatRate),
                new Actual365Fixed());
            RelinkableYieldTermStructureHandle rhTermStructure =
                new RelinkableYieldTermStructureHandle();

            rhTermStructure.linkTo(myTermStructure);

            // Define the ATM/OTM/ITM swaps
            Period fixedLegTenor = new Period(1, TimeUnit.Years);
            BusinessDayConvention fixedLegConvention =
                BusinessDayConvention.Unadjusted;
            BusinessDayConvention floatingLegConvention =
                BusinessDayConvention.ModifiedFollowing;
            DayCounter fixedLegDayCounter =
                new Thirty360(Thirty360.Convention.European);
            Period    floatingLegTenor = new Period(6, TimeUnit.Months);
            double    dummyFixedRate   = 0.03;
            IborIndex indexSixMonths   = new Euribor6M(rhTermStructure);

            Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years,
                                              floatingLegConvention);
            Date maturity = calendar.advance(startDate, 5, TimeUnit.Years,
                                             floatingLegConvention);
            Schedule fixedSchedule = new Schedule(startDate, maturity,
                                                  fixedLegTenor, calendar, fixedLegConvention, fixedLegConvention,
                                                  DateGeneration.Rule.Forward, false);
            Schedule floatSchedule = new Schedule(startDate, maturity,
                                                  floatingLegTenor, calendar, floatingLegConvention,
                                                  floatingLegConvention, DateGeneration.Rule.Forward, false);
            VanillaSwap swap = new VanillaSwap(
                VanillaSwap.Payer, 1000.0,
                fixedSchedule, dummyFixedRate, fixedLegDayCounter,
                floatSchedule, indexSixMonths, 0.0,
                indexSixMonths.dayCounter());
            DiscountingSwapEngine swapEngine =
                new DiscountingSwapEngine(rhTermStructure);

            swap.setPricingEngine(swapEngine);
            double fixedATMRate = swap.fairRate();
            double fixedOTMRate = fixedATMRate * 1.2;
            double fixedITMRate = fixedATMRate * 0.8;

            VanillaSwap atmSwap = new VanillaSwap(
                VanillaSwap.Payer, 1000.0,
                fixedSchedule, fixedATMRate, fixedLegDayCounter,
                floatSchedule, indexSixMonths, 0.0,
                indexSixMonths.dayCounter());
            VanillaSwap otmSwap = new VanillaSwap(
                VanillaSwap.Payer, 1000.0,
                fixedSchedule, fixedOTMRate, fixedLegDayCounter,
                floatSchedule, indexSixMonths, 0.0,
                indexSixMonths.dayCounter());
            VanillaSwap itmSwap = new VanillaSwap(
                VanillaSwap.Payer, 1000.0,
                fixedSchedule, fixedITMRate, fixedLegDayCounter,
                floatSchedule, indexSixMonths, 0.0,
                indexSixMonths.dayCounter());

            atmSwap.setPricingEngine(swapEngine);
            otmSwap.setPricingEngine(swapEngine);
            itmSwap.setPricingEngine(swapEngine);

            // defining the swaptions to be used in model calibration
            PeriodVector swaptionMaturities = new PeriodVector();

            swaptionMaturities.Add(new Period(1, TimeUnit.Years));
            swaptionMaturities.Add(new Period(2, TimeUnit.Years));
            swaptionMaturities.Add(new Period(3, TimeUnit.Years));
            swaptionMaturities.Add(new Period(4, TimeUnit.Years));
            swaptionMaturities.Add(new Period(5, TimeUnit.Years));

            CalibrationHelperVector swaptions = new CalibrationHelperVector();

            // List of times that have to be included in the timegrid
            DoubleVector times = new DoubleVector();

            for (int i = 0; i < numRows; i++)
            {
                int            j      = numCols - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1
                int            k      = i * numCols + j;
                Quote          vol    = new SimpleQuote(swaptionVols[k]);
                SwaptionHelper helper = new SwaptionHelper(
                    swaptionMaturities[i],
                    new Period(swapLenghts[j], TimeUnit.Years),
                    new QuoteHandle(vol),
                    indexSixMonths,
                    indexSixMonths.tenor(),
                    indexSixMonths.dayCounter(),
                    indexSixMonths.dayCounter(),
                    rhTermStructure);
                swaptions.Add(helper);
                times.AddRange(helper.times());
            }

            // Building time-grid
            TimeGrid grid = new TimeGrid(times, 30);

            // defining the models
            // G2 modelG2 = new G2(rhTermStructure));
            HullWhite       modelHW  = new HullWhite(rhTermStructure);
            HullWhite       modelHW2 = new HullWhite(rhTermStructure);
            BlackKarasinski modelBK  = new BlackKarasinski(rhTermStructure);

            // model calibrations

//          Console.WriteLine( "G2 (analytic formulae) calibration" );
//          for (int i=0; i<swaptions.Count; i++)
//              swaptions[i].setPricingEngine( new G2SwaptionEngine( modelG2, 6.0, 16 ) );
//
//          calibrateModel( modelG2, swaptions, 0.05);
//          Console.WriteLine( "calibrated to:" );
//          Console.WriteLine( "a     = " + modelG2.parameters()[0] );
//          Console.WriteLine( "sigma = " + modelG2.parameters()[1] );
//          Console.WriteLine( "b     = " + modelG2.parameters()[2] );
//          Console.WriteLine( "eta   = " + modelG2.parameters()[3] );
//          Console.WriteLine( "rho   = " + modelG2.parameters()[4] );

            Console.WriteLine("Hull-White (analytic formulae) calibration");
            for (int i = 0; i < swaptions.Count; i++)
            {
                swaptions[i].setPricingEngine(
                    new JamshidianSwaptionEngine(modelHW));
            }

            calibrateModel(modelHW, swaptions, 0.05);
//          Console.WriteLine( "calibrated to:" );
//            Console.WriteLine( "a = " + modelHW.parameters()[0] );
//            Console.WriteLine( "sigma = " + modelHW.parameters()[1] );


            Console.WriteLine("Hull-White (numerical) calibration");
            for (int i = 0; i < swaptions.Count; i++)
            {
                swaptions[i].setPricingEngine(
                    new TreeSwaptionEngine(modelHW2, grid));
            }

            calibrateModel(modelHW2, swaptions, 0.05);
//        std::cout << "calibrated to:\n"
//                  << "a = " << modelHW2->params()[0] << ", "
//                  << "sigma = " << modelHW2->params()[1]
//                  << std::endl << std::endl;


            Console.WriteLine("Black-Karasinski (numerical) calibration");
            for (int i = 0; i < swaptions.Count; i++)
            {
                swaptions[i].setPricingEngine(
                    new TreeSwaptionEngine(modelBK, grid));
            }

            calibrateModel(modelBK, swaptions, 0.05);
//        std::cout << "calibrated to:\n"
//                  << "a = " << modelBK->params()[0] << ", "
//                  << "sigma = " << modelBK->params()[1]
//                  << std::endl << std::endl;

            // ATM Bermudan swaption pricing

            Console.WriteLine("Payer bermudan swaption struck at {0} (ATM)",
                              fixedATMRate);

            DateVector bermudanDates = new DateVector();
            Schedule   schedule      = new Schedule(startDate, maturity,
                                                    new Period(3, TimeUnit.Months), calendar,
                                                    BusinessDayConvention.Following,
                                                    BusinessDayConvention.Following,
                                                    DateGeneration.Rule.Forward, false);

            for (uint i = 0; i < schedule.size(); i++)
            {
                bermudanDates.Add(schedule.date(i));
            }
            Exercise bermudaExercise = new BermudanExercise(bermudanDates);

            Swaption bermudanSwaption =
                new Swaption(atmSwap, bermudaExercise);

            bermudanSwaption.setPricingEngine(
                new TreeSwaptionEngine(modelHW, 50));
            Console.WriteLine("HW: " + bermudanSwaption.NPV());

            bermudanSwaption.setPricingEngine(
                new TreeSwaptionEngine(modelHW2, 50));
            Console.WriteLine("HW (num): " + bermudanSwaption.NPV());

            bermudanSwaption.setPricingEngine(
                new TreeSwaptionEngine(modelBK, 50));
            Console.WriteLine("BK (num): " + bermudanSwaption.NPV());

            DateTime endTime = DateTime.Now;
            TimeSpan delta   = endTime - startTime;

            Console.WriteLine();
            Console.WriteLine("Run completed in {0} s", delta.TotalSeconds);
            Console.WriteLine();
        }
Ejemplo n.º 8
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);
                }
            }
        }
Ejemplo n.º 9
0
        void testEngineConsistency(EngineType engine, int binomialSteps, int samples, Dictionary <string, double> tolerance,
                                   bool testGreeks)
        {
            //QL_TEST_START_TIMING

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

            // test options
            Option.Type[] types         = { Option.Type.Call, Option.Type.Put };
            double[]      strikes       = { 75.0, 100.0, 125.0 };
            int[]         lengths       = { 1 };

            // test data
            double[] underlyings        = { 100.0 };
            double[] qRates             = { 0.00, 0.05 };
            double[] rRates             = { 0.01, 0.05, 0.15 };
            double[] vols               = { 0.11, 0.50, 1.20 };

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

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

            for (int i = 0; i < types.Length; i++)
            {
                for (int j = 0; j < strikes.Length; j++)
                {
                    for (int k = 0; k < lengths.Length; k++)
                    {
                        Date              exDate   = today + lengths[k] * 360;
                        Exercise          exercise = new EuropeanExercise(exDate);
                        StrikedTypePayoff payoff   = new PlainVanillaPayoff(types[i], strikes[j]);
                        // reference option
                        VanillaOption refOption = makeOption(payoff, exercise, spot, qTS, rTS, volTS,
                                                             EngineType.Analytic, 0, 0);
                        // option to check
                        VanillaOption option = makeOption(payoff, exercise, spot, qTS, rTS, volTS,
                                                          engine, binomialSteps, samples);

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

                                        expected.Clear();
                                        calculated.Clear();

                                        // FLOATING_POINT_EXCEPTION
                                        expected.Add("value", refOption.NPV());
                                        calculated.Add("value", option.NPV());

                                        if (testGreeks && option.NPV() > spot.value() * 1.0e-5)
                                        {
                                            expected.Add("delta", refOption.delta());
                                            expected.Add("gamma", refOption.gamma());
                                            expected.Add("theta", refOption.theta());
                                            calculated.Add("delta", option.delta());
                                            calculated.Add("gamma", option.gamma());
                                            calculated.Add("theta", option.theta());
                                        }
                                        foreach (string greek in calculated.Keys)
                                        {
                                            double expct      = expected[greek],
                                                        calcl = calculated[greek],
                                                        tol   = tolerance[greek];
                                            double error      = Utilities.relativeError(expct, calcl, u);
                                            if (error > tol)
                                            {
                                                REPORT_FAILURE(greek, payoff, exercise,
                                                               u, q, r, today, v,
                                                               expct, calcl, error, tol);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 10
0
        public void testCachedHullWhite()
        {
            //("Testing Hull-White calibration against cached values...");

            Date today      = new Date(15, Month.February, 2002);
            Date settlement = new Date(19, Month.February, 2002);

            Settings.setEvaluationDate(today);
            Handle <YieldTermStructure> termStructure =
                new Handle <YieldTermStructure>(Utilities.flatRate(settlement, 0.04875825, new Actual365Fixed()));
            //termStructure.link
            HullWhite model = new HullWhite(termStructure);

            CalibrationData[] data = { new CalibrationData(1, 5, 0.1148),
                                       new CalibrationData(2, 4, 0.1108),
                                       new CalibrationData(3, 3, 0.1070),
                                       new CalibrationData(4, 2, 0.1021),
                                       new CalibrationData(5, 1, 0.1000) };
            IborIndex         index = new Euribor6M(termStructure);

            IPricingEngine engine = new JamshidianSwaptionEngine(model);

            List <CalibrationHelper> swaptions = new List <CalibrationHelper>();

            for (int i = 0; i < data.Length; i++)
            {
                Quote             vol    = new SimpleQuote(data[i].volatility);
                CalibrationHelper helper =
                    new SwaptionHelper(new Period(data[i].start, TimeUnit.Years),
                                       new Period(data[i].length, TimeUnit.Years),
                                       new Handle <Quote>(vol),
                                       index,
                                       new Period(1, TimeUnit.Years),
                                       new Thirty360(),
                                       new Actual360(),
                                       termStructure);
                helper.setPricingEngine(engine);
                swaptions.Add(helper);
            }

            // Set up the optimization problem
            // Real simplexLambda = 0.1;
            // Simplex optimizationMethod(simplexLambda);
            LevenbergMarquardt optimizationMethod = new LevenbergMarquardt(1.0e-8, 1.0e-8, 1.0e-8);
            EndCriteria        endCriteria        = new EndCriteria(10000, 100, 1e-6, 1e-8, 1e-8);

            //Optimize
            model.calibrate(swaptions, optimizationMethod, endCriteria, new Constraint(), new List <double>());
            EndCriteria.Type ecType = model.endCriteria();

            // Check and print out results
#if QL_USE_INDEXED_COUPON
            double cachedA = 0.0488199, cachedSigma = 0.00593579;
#else
            double cachedA = 0.0488565, cachedSigma = 0.00593662;
#endif
            double tolerance = 1.120e-5;
            //double tolerance = 1.0e-6;
            Vector xMinCalculated = model.parameters();
            double yMinCalculated = model.value(xMinCalculated, swaptions);
            Vector xMinExpected   = new Vector(2);
            xMinExpected[0] = cachedA;
            xMinExpected[1] = cachedSigma;
            double yMinExpected = model.value(xMinExpected, swaptions);
            if (Math.Abs(xMinCalculated[0] - cachedA) > tolerance ||
                Math.Abs(xMinCalculated[1] - cachedSigma) > tolerance)
            {
                QAssert.Fail("Failed to reproduce cached calibration results:\n"
                             + "calculated: a = " + xMinCalculated[0] + ", "
                             + "sigma = " + xMinCalculated[1] + ", "
                             + "f(a) = " + yMinCalculated + ",\n"
                             + "expected:   a = " + xMinExpected[0] + ", "
                             + "sigma = " + xMinExpected[1] + ", "
                             + "f(a) = " + yMinExpected + ",\n"
                             + "difference: a = " + (xMinCalculated[0] - xMinExpected[0]) + ", "
                             + "sigma = " + (xMinCalculated[1] - xMinExpected[1]) + ", "
                             + "f(a) = " + (yMinCalculated - yMinExpected) + ",\n"
                             + "end criteria = " + ecType);
            }
        }
Ejemplo n.º 11
0
        static void Main(string[] args)
        {
            DateTime timer = DateTime.Now;

            /*********************
            ***  MARKET DATA  ***
            *********************/

            Calendar calendar = new TARGET();

            Date settlementDate = new Date(18, Month.September, 2008);

            // must be a business day
            settlementDate = calendar.adjust(settlementDate);

            int fixingDays     = 3;
            int settlementDays = 3;

            Date todaysDate = calendar.advance(settlementDate, -fixingDays, TimeUnit.Days);

            // nothing to do with Date::todaysDate
            Settings.setEvaluationDate(todaysDate);

            Console.WriteLine("Today: {0}, {1}", todaysDate.DayOfWeek, todaysDate);
            Console.WriteLine("Settlement date: {0}, {1}", settlementDate.DayOfWeek, settlementDate);


            // Building of the bonds discounting yield curve

            /*********************
            ***  RATE HELPERS ***
            *********************/

            // RateHelpers are built from the above quotes together with
            // other instrument dependant infos.  Quotes are passed in
            // relinkable handles which could be relinked to some other
            // data source later.

            // Common data

            // ZC rates for the short end
            double zc3mQuote = 0.0096;
            double zc6mQuote = 0.0145;
            double zc1yQuote = 0.0194;

            Quote zc3mRate = new SimpleQuote(zc3mQuote);
            Quote zc6mRate = new SimpleQuote(zc6mQuote);
            Quote zc1yRate = new SimpleQuote(zc1yQuote);

            DayCounter zcBondsDayCounter = new Actual365Fixed();

            RateHelper zc3m = new DepositRateHelper(new Handle <Quote>(zc3mRate),
                                                    new Period(3, TimeUnit.Months), fixingDays,
                                                    calendar, BusinessDayConvention.ModifiedFollowing,
                                                    true, zcBondsDayCounter);
            RateHelper zc6m = new DepositRateHelper(new Handle <Quote>(zc6mRate),
                                                    new Period(6, TimeUnit.Months), fixingDays,
                                                    calendar, BusinessDayConvention.ModifiedFollowing,
                                                    true, zcBondsDayCounter);
            RateHelper zc1y = new DepositRateHelper(new Handle <Quote>(zc1yRate),
                                                    new Period(1, TimeUnit.Years), fixingDays,
                                                    calendar, BusinessDayConvention.ModifiedFollowing,
                                                    true, zcBondsDayCounter);

            // setup bonds
            double redemption = 100.0;

            const int numberOfBonds = 5;

            Date[] issueDates =
            {
                new Date(15, Month.March,    2005),
                new Date(15, Month.June,     2005),
                new Date(30, Month.June,     2006),
                new Date(15, Month.November, 2002),
                new Date(15, Month.May, 1987)
            };

            Date[] maturities =
            {
                new Date(31, Month.August, 2010),
                new Date(31, Month.August, 2011),
                new Date(31, Month.August, 2013),
                new Date(15, Month.August, 2018),
                new Date(15, Month.May, 2038)
            };

            double[] couponRates =
            {
                0.02375,
                0.04625,
                0.03125,
                0.04000,
                0.04500
            };

            double[] marketQuotes =
            {
                100.390625,
                106.21875,
                100.59375,
                101.6875,
                102.140625
            };

            List <SimpleQuote> quote = new List <SimpleQuote>();

            for (int i = 0; i < numberOfBonds; i++)
            {
                SimpleQuote cp = new SimpleQuote(marketQuotes[i]);
                quote.Add(cp);
            }

            List <RelinkableHandle <Quote> > quoteHandle = new InitializedList <RelinkableHandle <Quote> >(numberOfBonds);

            for (int i = 0; i < numberOfBonds; i++)
            {
                quoteHandle[i].linkTo(quote[i]);
            }

            // Definition of the rate helpers
            List <FixedRateBondHelper> bondsHelpers = new List <FixedRateBondHelper>();

            for (int i = 0; i < numberOfBonds; i++)
            {
                Schedule schedule = new Schedule(issueDates[i], maturities[i], new Period(Frequency.Semiannual),
                                                 new UnitedStates(UnitedStates.Market.GovernmentBond),
                                                 BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted,
                                                 DateGeneration.Rule.Backward, false);

                FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle[i],
                                                                         settlementDays,
                                                                         100.0,
                                                                         schedule,
                                                                         new List <double>()
                {
                    couponRates[i]
                },
                                                                         new ActualActual(ActualActual.Convention.Bond),
                                                                         BusinessDayConvention.Unadjusted,
                                                                         redemption,
                                                                         issueDates[i]);

                bondsHelpers.Add(bondHelper);
            }

            /*********************
            **  CURVE BUILDING **
            *********************/

            // Any DayCounter would be fine.
            // ActualActual::ISDA ensures that 30 years is 30.0
            DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA);

            double tolerance = 1.0e-15;

            // A depo-bond curve
            List <RateHelper> bondInstruments = new List <RateHelper>();

            // Adding the ZC bonds to the curve for the short end
            bondInstruments.Add(zc3m);
            bondInstruments.Add(zc6m);
            bondInstruments.Add(zc1y);

            // Adding the Fixed rate bonds to the curve for the long end
            for (int i = 0; i < numberOfBonds; i++)
            {
                bondInstruments.Add(bondsHelpers[i]);
            }

            YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>(
                settlementDate, bondInstruments,
                termStructureDayCounter,
                new List <Handle <Quote> >(),
                new List <Date>(),
                tolerance);

            // Building of the Libor forecasting curve
            // deposits
            double d1wQuote = 0.043375;
            double d1mQuote = 0.031875;
            double d3mQuote = 0.0320375;
            double d6mQuote = 0.03385;
            double d9mQuote = 0.0338125;
            double d1yQuote = 0.0335125;
            // swaps
            double s2yQuote  = 0.0295;
            double s3yQuote  = 0.0323;
            double s5yQuote  = 0.0359;
            double s10yQuote = 0.0412;
            double s15yQuote = 0.0433;


            /********************
            ***    QUOTES    ***
            ********************/

            // SimpleQuote stores a value which can be manually changed;
            // other Quote subclasses could read the value from a database
            // or some kind of data feed.

            // deposits
            Quote d1wRate = new SimpleQuote(d1wQuote);
            Quote d1mRate = new SimpleQuote(d1mQuote);
            Quote d3mRate = new SimpleQuote(d3mQuote);
            Quote d6mRate = new SimpleQuote(d6mQuote);
            Quote d9mRate = new SimpleQuote(d9mQuote);
            Quote d1yRate = new SimpleQuote(d1yQuote);
            // swaps
            Quote s2yRate  = new SimpleQuote(s2yQuote);
            Quote s3yRate  = new SimpleQuote(s3yQuote);
            Quote s5yRate  = new SimpleQuote(s5yQuote);
            Quote s10yRate = new SimpleQuote(s10yQuote);
            Quote s15yRate = new SimpleQuote(s15yQuote);

            /*********************
            ***  RATE HELPERS ***
            *********************/

            // RateHelpers are built from the above quotes together with
            // other instrument dependant infos.  Quotes are passed in
            // relinkable handles which could be relinked to some other
            // data source later.

            // deposits
            DayCounter depositDayCounter = new Actual360();

            RateHelper d1w = new DepositRateHelper(
                new Handle <Quote>(d1wRate),
                new Period(1, TimeUnit.Weeks), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);
            RateHelper d1m = new DepositRateHelper(
                new Handle <Quote>(d1mRate),
                new Period(1, TimeUnit.Months), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);
            RateHelper d3m = new DepositRateHelper(
                new Handle <Quote>(d3mRate),
                new Period(3, TimeUnit.Months), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);
            RateHelper d6m = new DepositRateHelper(
                new Handle <Quote>(d6mRate),
                new Period(6, TimeUnit.Months), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);
            RateHelper d9m = new DepositRateHelper(
                new Handle <Quote>(d9mRate),
                new Period(9, TimeUnit.Months), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);
            RateHelper d1y = new DepositRateHelper(
                new Handle <Quote>(d1yRate),
                new Period(1, TimeUnit.Years), fixingDays,
                calendar, BusinessDayConvention.ModifiedFollowing,
                true, depositDayCounter);

            // setup swaps
            Frequency             swFixedLegFrequency  = Frequency.Annual;
            BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted;
            DayCounter            swFixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European);
            IborIndex             swFloatingLegIndex   = new Euribor6M();

            Period forwardStart = new Period(1, TimeUnit.Days);

            RateHelper s2y = new SwapRateHelper(
                new Handle <Quote>(s2yRate), new Period(2, TimeUnit.Years),
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, new Handle <Quote>(), forwardStart);
            RateHelper s3y = new SwapRateHelper(
                new Handle <Quote>(s3yRate), new Period(3, TimeUnit.Years),
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, new Handle <Quote>(), forwardStart);
            RateHelper s5y = new SwapRateHelper(
                new Handle <Quote>(s5yRate), new Period(5, TimeUnit.Years),
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, new Handle <Quote>(), forwardStart);
            RateHelper s10y = new SwapRateHelper(
                new Handle <Quote>(s10yRate), new Period(10, TimeUnit.Years),
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, new Handle <Quote>(), forwardStart);
            RateHelper s15y = new SwapRateHelper(
                new Handle <Quote>(s15yRate), new Period(15, TimeUnit.Years),
                calendar, swFixedLegFrequency,
                swFixedLegConvention, swFixedLegDayCounter,
                swFloatingLegIndex, new Handle <Quote>(), forwardStart);


            /*********************
            **  CURVE BUILDING **
            *********************/

            // Any DayCounter would be fine.
            // ActualActual::ISDA ensures that 30 years is 30.0

            // A depo-swap curve
            List <RateHelper> depoSwapInstruments = new List <RateHelper>();

            depoSwapInstruments.Add(d1w);
            depoSwapInstruments.Add(d1m);
            depoSwapInstruments.Add(d3m);
            depoSwapInstruments.Add(d6m);
            depoSwapInstruments.Add(d9m);
            depoSwapInstruments.Add(d1y);
            depoSwapInstruments.Add(s2y);
            depoSwapInstruments.Add(s3y);
            depoSwapInstruments.Add(s5y);
            depoSwapInstruments.Add(s10y);
            depoSwapInstruments.Add(s15y);
            YieldTermStructure depoSwapTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>(
                settlementDate, depoSwapInstruments,
                termStructureDayCounter,
                new List <Handle <Quote> >(),
                new List <Date>(),
                tolerance);

            // Term structures that will be used for pricing:
            // the one used for discounting cash flows
            RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>();
            // the one used for forward rate forecasting
            RelinkableHandle <YieldTermStructure> forecastingTermStructure = new RelinkableHandle <YieldTermStructure>();

            /*********************
             * BONDS TO BE PRICED *
             **********************/

            // Common data
            double faceAmount = 100;

            // Pricing engine
            IPricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure);

            // Zero coupon bond
            ZeroCouponBond zeroCouponBond = new ZeroCouponBond(
                settlementDays,
                new UnitedStates(UnitedStates.Market.GovernmentBond),
                faceAmount,
                new Date(15, Month.August, 2013),
                BusinessDayConvention.Following,
                116.92,
                new Date(15, Month.August, 2003));

            zeroCouponBond.setPricingEngine(bondEngine);

            // Fixed 4.5% US Treasury Note
            Schedule fixedBondSchedule = new Schedule(new Date(15, Month.May, 2007),
                                                      new Date(15, Month.May, 2017), new Period(Frequency.Semiannual),
                                                      new UnitedStates(UnitedStates.Market.GovernmentBond),
                                                      BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, false);

            FixedRateBond fixedRateBond = new FixedRateBond(
                settlementDays,
                faceAmount,
                fixedBondSchedule,
                new List <double>()
            {
                0.045
            },
                new ActualActual(ActualActual.Convention.Bond),
                BusinessDayConvention.ModifiedFollowing,
                100.0, new Date(15, Month.May, 2007));

            fixedRateBond.setPricingEngine(bondEngine);

            // Floating rate bond (3M USD Libor + 0.1%)
            // Should and will be priced on another curve later...

            RelinkableHandle <YieldTermStructure> liborTermStructure = new RelinkableHandle <YieldTermStructure>();
            IborIndex libor3m = new USDLibor(new Period(3, TimeUnit.Months), liborTermStructure);

            libor3m.addFixing(new Date(17, Month.July, 2008), 0.0278625);

            Schedule floatingBondSchedule = new Schedule(new Date(21, Month.October, 2005),
                                                         new Date(21, Month.October, 2010), new Period(Frequency.Quarterly),
                                                         new UnitedStates(UnitedStates.Market.NYSE),
                                                         BusinessDayConvention.Unadjusted, BusinessDayConvention.Unadjusted, DateGeneration.Rule.Backward, true);

            FloatingRateBond floatingRateBond = new FloatingRateBond(
                settlementDays,
                faceAmount,
                floatingBondSchedule,
                libor3m,
                new Actual360(),
                BusinessDayConvention.ModifiedFollowing,
                2,
                // Gearings
                new List <double>()
            {
                1.0
            },
                // Spreads
                new List <double>()
            {
                0.001
            },
                // Caps
                new List <double>(),
                // Floors
                new List <double>(),
                // Fixing in arrears
                true,
                100.0,
                new Date(21, Month.October, 2005));

            floatingRateBond.setPricingEngine(bondEngine);

            // Coupon pricers
            IborCouponPricer pricer = new BlackIborCouponPricer();

            // optionLet volatilities
            double volatility = 0.0;
            Handle <OptionletVolatilityStructure> vol;

            vol = new Handle <OptionletVolatilityStructure>(
                new ConstantOptionletVolatility(
                    settlementDays,
                    calendar,
                    BusinessDayConvention.ModifiedFollowing,
                    volatility,
                    new Actual365Fixed()));

            pricer.setCapletVolatility(vol);
            Utils.setCouponPricer(floatingRateBond.cashflows(), pricer);

            // Yield curve bootstrapping
            forecastingTermStructure.linkTo(depoSwapTermStructure);
            discountingTermStructure.linkTo(bondDiscountingTermStructure);

            // We are using the depo & swap curve to estimate the future Libor rates
            liborTermStructure.linkTo(depoSwapTermStructure);

            /***************
             * BOND PRICING *
             ****************/

            // write column headings
            int[] widths = { 18, 10, 10, 10 };

            Console.WriteLine("{0,18}{1,10}{2,10}{3,10}", "", "ZC", "Fixed", "Floating");

            string separator = " | ";
            int    width     = widths[0]
                               + widths[1]
                               + widths[2]
                               + widths[3];
            string rule = "".PadLeft(width, '-'), dblrule = "".PadLeft(width, '=');
            string tab = "".PadLeft(8, ' ');

            Console.WriteLine(rule);

            Console.WriteLine("Net present value".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                              zeroCouponBond.NPV(),
                              fixedRateBond.NPV(),
                              floatingRateBond.NPV());

            Console.WriteLine("Clean price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                              zeroCouponBond.cleanPrice(),
                              fixedRateBond.cleanPrice(),
                              floatingRateBond.cleanPrice());

            Console.WriteLine("Dirty price".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                              zeroCouponBond.dirtyPrice(),
                              fixedRateBond.dirtyPrice(),
                              floatingRateBond.dirtyPrice());

            Console.WriteLine("Accrued coupon".PadLeft(widths[0]) + "{0,10:n2}{1,10:n2}{2,10:n2}",
                              zeroCouponBond.accruedAmount(),
                              fixedRateBond.accruedAmount(),
                              floatingRateBond.accruedAmount());

            Console.WriteLine("Previous coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                              "N/A",
                              fixedRateBond.previousCoupon(),
                              floatingRateBond.previousCoupon());

            Console.WriteLine("Next coupon".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                              "N/A",
                              fixedRateBond.nextCoupon(),
                              floatingRateBond.nextCoupon());

            Console.WriteLine("Yield".PadLeft(widths[0]) + "{0,10:0.00%}{1,10:0.00%}{2,10:0.00%}",
                              zeroCouponBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                              fixedRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                              floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual));

            Console.WriteLine();

            // Other computations
            Console.WriteLine("Sample indirect computations (for the floating rate bond): ");
            Console.WriteLine(rule);

            Console.WriteLine("Yield to Clean Price: {0:n2}",
                              floatingRateBond.cleanPrice(floatingRateBond.yield(new Actual360(), Compounding.Compounded, Frequency.Annual),
                                                          new Actual360(), Compounding.Compounded, Frequency.Annual,
                                                          settlementDate));

            Console.WriteLine("Clean Price to Yield: {0:0.00%}",
                              floatingRateBond.yield(floatingRateBond.cleanPrice(), new Actual360(), Compounding.Compounded, Frequency.Annual,
                                                     settlementDate));

            /* "Yield to Price"
            *  "Price to Yield" */

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

            Console.Write("Press any key to continue ...");
            Console.ReadKey();
        }
Ejemplo n.º 12
0
        static void Main(string[] args)
        {
            double nominal = 575000000;

            Date _marketDate;
            Date _settlementDate;
            Dictionary <string, double> _depositRates;
            Dictionary <string, double> _swapRates;
            List <RateHelper>           _rateHelpers;
            Calendar _calendar   = new TARGET();
            int      _fixingDays = 2;

            _marketDate = new Date(new DateTime(2015, 12, 17));
            Settings.setEvaluationDate(_marketDate);

            _depositRates = new Dictionary <string, double>();
            _depositRates.Add("1M", 0.0045);
            _depositRates.Add("3M", 0.0070);
            _depositRates.Add("6M", 0.0090);

            _swapRates = new Dictionary <string, double>();
            _swapRates.Add("1Y", 0.0080);
            _swapRates.Add("2Y", 0.0109);
            _swapRates.Add("3Y", 0.0134);
            _swapRates.Add("4Y", 0.0153);
            _swapRates.Add("5Y", 0.0169);
            _swapRates.Add("7Y", 0.0193);
            _swapRates.Add("10Y", 0.0218);
            _swapRates.Add("30Y", 0.0262);

            _rateHelpers = new List <RateHelper>();
            foreach (var v in _depositRates)
            {
                SimpleQuote sq = new SimpleQuote(v.Value);
                _rateHelpers.Add(new DepositRateHelper(new Handle <Quote>(sq), new Period(v.Key),
                                                       _fixingDays, _calendar, BusinessDayConvention.ModifiedFollowing, true, new Actual360()));
            }
            foreach (var v in _swapRates)
            {
                SimpleQuote sq = new SimpleQuote(v.Value);
                _rateHelpers.Add(new SwapRateHelper(new Handle <Quote>(sq), new Period(v.Key),
                                                    _calendar, Frequency.Semiannual, BusinessDayConvention.Unadjusted,
                                                    new Thirty360(Thirty360.Thirty360Convention.USA), new Euribor3M()));
            }

            _marketDate     = _calendar.adjust(_marketDate);
            _settlementDate = _calendar.advance(_marketDate, _fixingDays, TimeUnit.Days);

            YieldTermStructure yieldTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>(
                _settlementDate, _rateHelpers, new ActualActual(ActualActual.Convention.ISDA));

            RelinkableHandle <YieldTermStructure> yieldTermStructureHandle = new RelinkableHandle <YieldTermStructure>();


            Frequency             fixedLegFrequency  = Frequency.Semiannual;
            BusinessDayConvention fixedLegConvention = BusinessDayConvention.ModifiedFollowing;
            DayCounter            fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.USA);
            double fixedRate = 0.0144;

            Frequency             floatLegFrequency  = Frequency.Quarterly;
            BusinessDayConvention floatLegConvention = BusinessDayConvention.ModifiedFollowing;
            DayCounter            floatLegDayCounter = new Actual360();
            IborIndex             iborIndex          = new Euribor3M(yieldTermStructureHandle);

            iborIndex.addFixing(new Date(18, Month.Aug, 2015), 0.0033285);
            iborIndex.addFixing(new Date(18, Month.Nov, 2015), 0.0036960);
            double floatSpread = 0.0;

            VanillaSwap.Type swapType = VanillaSwap.Type.Receiver;

            Date     maturity      = new Date(20, Month.Nov, 2018);
            Date     effective     = new Date(20, Month.Nov, 2013);
            Schedule fixedSchedule = new Schedule(effective, maturity, new Period(fixedLegFrequency), _calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false);
            Schedule floatSchedule = new Schedule(effective, maturity, new Period(floatLegFrequency), _calendar, floatLegConvention, floatLegConvention, DateGeneration.Rule.Forward, false);

            VanillaSwap vanillaSwap = new VanillaSwap(swapType, nominal, fixedSchedule, fixedRate, fixedLegDayCounter, floatSchedule, iborIndex, floatSpread, floatLegDayCounter);

            InterestRate        interestRate = new InterestRate(fixedRate, fixedLegDayCounter, Compounding.Simple, fixedLegFrequency);
            List <InterestRate> coupons      = new List <InterestRate>();

            for (int i = 0; i < fixedSchedule.Count; i++)
            {
                coupons.Add(interestRate);
            }
            FixedRateBond    fixedBond = new FixedRateBond(_fixingDays, nominal, fixedSchedule, coupons, BusinessDayConvention.ModifiedFollowing);
            FloatingRateBond floatBond = new FloatingRateBond(_fixingDays, nominal, floatSchedule, iborIndex, floatLegDayCounter);

            IPricingEngine bondPricingEngine = new DiscountingBondEngine(yieldTermStructureHandle);

            fixedBond.setPricingEngine(bondPricingEngine);
            floatBond.setPricingEngine(bondPricingEngine);

            IPricingEngine swapPricingEngine = new DiscountingSwapEngine(yieldTermStructureHandle);

            vanillaSwap.setPricingEngine(swapPricingEngine);

            yieldTermStructureHandle.linkTo(yieldTermStructure);

            double swapNPV      = vanillaSwap.NPV();
            double swapFixedNPV = vanillaSwap.fixedLegNPV();
            double swapFloatNPV = vanillaSwap.floatingLegNPV();

            double bondFixedNPV = fixedBond.NPV();
            double bondFloatNPV = floatBond.NPV();

            int    w = (swapType == VanillaSwap.Type.Receiver ? 1 : -1);
            double asBondsMarketValue      = w * (bondFixedNPV - bondFloatNPV);
            double asBondsMarketValueNoAcc = w * (fixedBond.cleanPrice() - floatBond.cleanPrice()) / 100.0 * nominal;
            double asBondsAccruedInterest  = asBondsMarketValue - asBondsMarketValueNoAcc;

            Console.WriteLine("Vanilla Swap Maket Value      : {0:N}", swapNPV);
            Console.WriteLine("As Bonds Market Value         : {0:N}", asBondsMarketValue);
            Console.WriteLine("As Bonds Market Value (no acc): {0:N}", asBondsMarketValueNoAcc);
            Console.WriteLine("As Bonds Accrued Interest     : {0:N}", asBondsAccruedInterest);

            Date   rollDate      = new Date(1, Month.Nov, 2015);
            double bondFixedCash = 0;

            foreach (CashFlow cf in fixedBond.cashflows())
            {
                if (cf.date() > rollDate & cf.date() <= _marketDate)
                {
                    bondFixedCash += cf.amount();
                }
            }
            double bondFloatCash = 0;

            foreach (CashFlow cf in floatBond.cashflows())
            {
                if (cf.date() > rollDate & cf.date() <= _marketDate)
                {
                    bondFloatCash += cf.amount();
                }
            }
            double asBondsCash = w * (bondFixedCash - bondFloatCash);

            Console.WriteLine("As Bonds Settled Cash         : {0:N}", asBondsCash);
        }
Ejemplo n.º 13
0
        public void testBSMOperatorConsistency()
        {
            //("Testing consistency of BSM operators...");

            Vector grid   = new Vector(10);
            double price  = 20.0;
            double factor = 1.1;

            for (int i = 0; i < grid.size(); i++)
            {
                grid[i] = price;
                price  *= factor;
            }

            double dx    = Math.Log(factor);
            double r     = 0.05;
            double q     = 0.01;
            double sigma = 0.5;

            BSMOperator refer = new BSMOperator(grid.size(), dx, r, q, sigma);

            DayCounter dc           = new Actual360();
            Date       today        = Date.Today;
            Date       exercise     = today + new Period(2, TimeUnit.Years);
            double     residualTime = dc.yearFraction(today, exercise);

            SimpleQuote                    spot         = new SimpleQuote(0.0);
            YieldTermStructure             qTS          = Utilities.flatRate(today, q, dc);
            YieldTermStructure             rTS          = Utilities.flatRate(today, r, dc);
            BlackVolTermStructure          volTS        = Utilities.flatVol(today, sigma, dc);
            GeneralizedBlackScholesProcess stochProcess = new GeneralizedBlackScholesProcess(
                new Handle <Quote>(spot),
                new Handle <YieldTermStructure>(qTS),
                new Handle <YieldTermStructure>(rTS),
                new Handle <BlackVolTermStructure>(volTS));
            BSMOperator          op1 = new BSMOperator(grid, stochProcess, residualTime);
            PdeOperator <PdeBSM> op2 = new PdeOperator <PdeBSM>(grid, stochProcess, residualTime);

            double tolerance = 1.0e-6;
            Vector lderror   = refer.lowerDiagonal() - op1.lowerDiagonal();
            Vector derror    = refer.diagonal() - op1.diagonal();
            Vector uderror   = refer.upperDiagonal() - op1.upperDiagonal();

            for (int i = 2; i < grid.size() - 2; i++)
            {
                if (Math.Abs(lderror[i]) > tolerance ||
                    Math.Abs(derror[i]) > tolerance ||
                    Math.Abs(uderror[i]) > tolerance)
                {
                    QAssert.Fail("inconsistency between BSM operators:\n"
                                 + i + " row:\n"
                                 + "expected:   "
                                 + refer.lowerDiagonal()[i] + ", "
                                 + refer.diagonal()[i] + ", "
                                 + refer.upperDiagonal()[i] + "\n"
                                 + "calculated: "
                                 + op1.lowerDiagonal()[i] + ", "
                                 + op1.diagonal()[i] + ", "
                                 + op1.upperDiagonal()[i]);
                }
            }
            lderror = refer.lowerDiagonal() - op2.lowerDiagonal();
            derror  = refer.diagonal() - op2.diagonal();
            uderror = refer.upperDiagonal() - op2.upperDiagonal();

            for (int i = 2; i < grid.size() - 2; i++)
            {
                if (Math.Abs(lderror[i]) > tolerance ||
                    Math.Abs(derror[i]) > tolerance ||
                    Math.Abs(uderror[i]) > tolerance)
                {
                    QAssert.Fail("inconsistency between BSM operators:\n"
                                 + i + " row:\n"
                                 + "expected:   "
                                 + refer.lowerDiagonal()[i] + ", "
                                 + refer.diagonal()[i] + ", "
                                 + refer.upperDiagonal()[i] + "\n"
                                 + "calculated: "
                                 + op2.lowerDiagonal()[i] + ", "
                                 + op2.diagonal()[i] + ", "
                                 + op2.upperDiagonal()[i]);
                }
            }
        }
Ejemplo n.º 14
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);
                }
            }
        }
Ejemplo n.º 15
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);
                }
            }
        }
Ejemplo n.º 16
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);
                }
            }
        }
Ejemplo n.º 17
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);
                    }
                }
            }
        }
Ejemplo n.º 18
0
        public void testVannaVolgaDoubleBarrierValues()
        {
            // Testing double-barrier FX options against Vanna/Volga values
            SavedSettings backup = new SavedSettings();

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

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

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

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

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

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

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

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

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

            Settings.setEvaluationDate(today);

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

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

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

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

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

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

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

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

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

                IPricingEngine vannaVolgaEngine;

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

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

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

                calculated = doubleBarrierOption.NPV();
                expected   = values[i].result;
                error      = Math.Abs(calculated - expected);
                double maxtol = 5.0e-3; // different engines have somewhat different results
                if (error > maxtol)
                {
                    REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                              values[i].barrier1, values[i].barrier2,
                                              values[i].rebate, payoff, exercise, values[i].s,
                                              values[i].q, values[i].r, today, values[i].vol25Put,
                                              values[i].volAtm, values[i].vol25Call, values[i].v,
                                              expected, calculated, error, values[i].tol);
                }
            }
        }
Ejemplo n.º 19
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);
                }
            }
        }
Ejemplo n.º 20
0
Archivo: FRA.cs Proyecto: igitur/qlnet
        static void Main()
        {
            DateTime timer = DateTime.Now;

            /*********************
            ***  MARKET DATA  ***
            *********************/

            RelinkableHandle <YieldTermStructure> euriborTermStructure = new RelinkableHandle <YieldTermStructure>();
            IborIndex euribor3m = new Euribor3M(euriborTermStructure);

            Date todaysDate = new Date(23, Month.May, 2006);

            Settings.setEvaluationDate(todaysDate);

            Calendar calendar       = euribor3m.fixingCalendar();
            int      fixingDays     = euribor3m.fixingDays();
            Date     settlementDate = calendar.advance(todaysDate, fixingDays, TimeUnit.Days);

            Console.WriteLine("Today: " + todaysDate.DayOfWeek + ", " + todaysDate);
            Console.WriteLine("Settlement date: " + settlementDate.DayOfWeek + ", " + settlementDate);


            // 3 month term FRA quotes (index refers to monthsToStart)
            double[] threeMonthFraQuote = new double[10];

            threeMonthFraQuote[1] = 0.030;
            threeMonthFraQuote[2] = 0.031;
            threeMonthFraQuote[3] = 0.032;
            threeMonthFraQuote[6] = 0.033;
            threeMonthFraQuote[9] = 0.034;

            /********************
            ***    QUOTES    ***
            ********************/

            // SimpleQuote stores a value which can be manually changed;
            // other Quote subclasses could read the value from a database
            // or some kind of data feed.


            // FRAs
            SimpleQuote fra1x4Rate  = new SimpleQuote(threeMonthFraQuote[1]);
            SimpleQuote fra2x5Rate  = new SimpleQuote(threeMonthFraQuote[2]);
            SimpleQuote fra3x6Rate  = new SimpleQuote(threeMonthFraQuote[3]);
            SimpleQuote fra6x9Rate  = new SimpleQuote(threeMonthFraQuote[6]);
            SimpleQuote fra9x12Rate = new SimpleQuote(threeMonthFraQuote[9]);

            RelinkableHandle <Quote> h1x4  = new RelinkableHandle <Quote>();  h1x4.linkTo(fra1x4Rate);
            RelinkableHandle <Quote> h2x5  = new RelinkableHandle <Quote>();  h2x5.linkTo(fra2x5Rate);
            RelinkableHandle <Quote> h3x6  = new RelinkableHandle <Quote>();  h3x6.linkTo(fra3x6Rate);
            RelinkableHandle <Quote> h6x9  = new RelinkableHandle <Quote>();  h6x9.linkTo(fra6x9Rate);
            RelinkableHandle <Quote> h9x12 = new RelinkableHandle <Quote>(); h9x12.linkTo(fra9x12Rate);

            /*********************
            ***  RATE HELPERS ***
            *********************/

            // RateHelpers are built from the above quotes together with
            // other instrument dependant infos.  Quotes are passed in
            // relinkable handles which could be relinked to some other
            // data source later.

            DayCounter            fraDayCounter = euribor3m.dayCounter();
            BusinessDayConvention convention    = euribor3m.businessDayConvention();
            bool endOfMonth = euribor3m.endOfMonth();

            RateHelper fra1x4 = new FraRateHelper(h1x4, 1, 4,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra2x5 = new FraRateHelper(h2x5, 2, 5,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra3x6 = new FraRateHelper(h3x6, 3, 6,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra6x9 = new FraRateHelper(h6x9, 6, 9,
                                                  fixingDays, calendar, convention,
                                                  endOfMonth, fraDayCounter);

            RateHelper fra9x12 = new FraRateHelper(h9x12, 9, 12,
                                                   fixingDays, calendar, convention,
                                                   endOfMonth, fraDayCounter);


            /*********************
            **  CURVE BUILDING **
            *********************/

            // Any DayCounter would be fine.
            // ActualActual::ISDA ensures that 30 years is 30.0
            DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA);

            double tolerance = 1.0e-15;

            // A FRA curve
            List <RateHelper> fraInstruments = new List <RateHelper>();

            fraInstruments.Add(fra1x4);
            fraInstruments.Add(fra2x5);
            fraInstruments.Add(fra3x6);
            fraInstruments.Add(fra6x9);
            fraInstruments.Add(fra9x12);

            YieldTermStructure fraTermStructure = new PiecewiseYieldCurve <Discount, LogLinear>(
                settlementDate, fraInstruments, termStructureDayCounter,
                new List <Handle <Quote> >(), new List <Date>(), tolerance);


            // Term structures used for pricing/discounting
            RelinkableHandle <YieldTermStructure> discountingTermStructure = new RelinkableHandle <YieldTermStructure>();

            discountingTermStructure.linkTo(fraTermStructure);


            /***********************
            ***  construct FRA's ***
            ***********************/

            Calendar fraCalendar = euribor3m.fixingCalendar();
            BusinessDayConvention fraBusinessDayConvention = euribor3m.businessDayConvention();

            Position.Type fraFwdType    = Position.Type.Long;
            double        fraNotional   = 100.0;
            const int     FraTermMonths = 3;

            int[] monthsToStart = new [] { 1, 2, 3, 6, 9 };

            euriborTermStructure.linkTo(fraTermStructure);

            Console.WriteLine("\nTest FRA construction, NPV calculation, and FRA purchase\n");

            int i;

            for (i = 0; i < monthsToStart.Length; i++)
            {
                Date fraValueDate = fraCalendar.advance(
                    settlementDate, monthsToStart[i], TimeUnit.Months,
                    fraBusinessDayConvention);

                Date fraMaturityDate = fraCalendar.advance(
                    fraValueDate, FraTermMonths, TimeUnit.Months,
                    fraBusinessDayConvention);

                double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]];

                ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate,
                                                                      fraFwdType, fraStrikeRate,
                                                                      fraNotional, euribor3m,
                                                                      discountingTermStructure);

                Console.WriteLine("3m Term FRA, Months to Start: " + monthsToStart[i]);

                Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate);
                Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate());
                Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]);
                Console.WriteLine("FRA spot value: " + myFRA.spotValue());
                Console.WriteLine("FRA forward value: " + myFRA.forwardValue());
                Console.WriteLine("FRA implied Yield: {0:0.00%}",
                                  myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter));
                Console.WriteLine("market Zero Rate: {0:0.00%}",
                                  discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple));
                Console.WriteLine("FRA NPV [should be zero]: {0}\n", myFRA.NPV());
            }



            Console.WriteLine("\n");
            Console.WriteLine("Now take a 100 basis-point upward shift in FRA quotes and examine NPV\n");


            const double BpsShift = 0.01;

            threeMonthFraQuote[1] = 0.030 + BpsShift;
            threeMonthFraQuote[2] = 0.031 + BpsShift;
            threeMonthFraQuote[3] = 0.032 + BpsShift;
            threeMonthFraQuote[6] = 0.033 + BpsShift;
            threeMonthFraQuote[9] = 0.034 + BpsShift;

            fra1x4Rate.setValue(threeMonthFraQuote[1]);
            fra2x5Rate.setValue(threeMonthFraQuote[2]);
            fra3x6Rate.setValue(threeMonthFraQuote[3]);
            fra6x9Rate.setValue(threeMonthFraQuote[6]);
            fra9x12Rate.setValue(threeMonthFraQuote[9]);


            for (i = 0; i < monthsToStart.Length; i++)
            {
                Date fraValueDate = fraCalendar.advance(
                    settlementDate, monthsToStart[i], TimeUnit.Months,
                    fraBusinessDayConvention);

                Date fraMaturityDate = fraCalendar.advance(
                    fraValueDate, FraTermMonths, TimeUnit.Months,
                    fraBusinessDayConvention);

                double fraStrikeRate = threeMonthFraQuote[monthsToStart[i]] - BpsShift;

                ForwardRateAgreement myFRA = new ForwardRateAgreement(fraValueDate, fraMaturityDate,
                                                                      fraFwdType, fraStrikeRate,
                                                                      fraNotional, euribor3m,
                                                                      discountingTermStructure);

                Console.WriteLine("3m Term FRA, 100 notional, Months to Start: " + monthsToStart[i]);
                Console.WriteLine("strike FRA rate: {0:0.00%}", fraStrikeRate);
                Console.WriteLine("FRA 3m forward rate: {0:0.00%}", myFRA.forwardRate());
                Console.WriteLine("FRA market quote: {0:0.00%}", threeMonthFraQuote[monthsToStart[i]]);
                Console.WriteLine("FRA spot value: " + myFRA.spotValue());
                Console.WriteLine("FRA forward value: " + myFRA.forwardValue());
                Console.WriteLine("FRA implied Yield: {0:0.00%}",
                                  myFRA.impliedYield(myFRA.spotValue(), myFRA.forwardValue(), settlementDate, Compounding.Simple, fraDayCounter));
                Console.WriteLine("market Zero Rate: {0:0.00%}",
                                  discountingTermStructure.link.zeroRate(fraMaturityDate, fraDayCounter, Compounding.Simple));
                Console.WriteLine("FRA NPV [should be positive]: {0}\n", myFRA.NPV());
            }

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

            Console.Write("Press any key to continue ...");
            Console.ReadKey();
        }
Ejemplo n.º 21
0
        public void testPutCallParity()
        {
            // Testing put-call parity for deltas

            // Test for put call parity between put and call deltas.

            SavedSettings backup = new SavedSettings();

            /* The data below are from
             * "Option pricing formulas", E.G. Haug, McGraw-Hill 1998
             * pag 11-16
             */

            EuropeanOptionData[] values =
            {
                // pag 2-8
                //        type, strike,   spot,    q,    r,    t,  vol,   value,    tol
                new EuropeanOptionData(Option.Type.Call,  65.00,  60.00, 0.00, 0.08, 0.25, 0.30,  2.1334, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   95.00, 100.00, 0.05, 0.10, 0.50, 0.20,  2.4648, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   19.00,  19.00, 0.10, 0.10, 0.75, 0.28,  1.7011, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call,  19.00,  19.00, 0.10, 0.10, 0.75, 0.28,  1.7011, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call,   1.60,   1.56, 0.08, 0.06, 0.50, 0.12,  0.0291, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,   70.00,  75.00, 0.05, 0.10, 0.50, 0.35,  4.0870, 1.0e-4),
                // pag 24
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  0.0205, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  9.9413, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.25,  0.3150, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1217, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.25, 10.3556, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.10, 0.35,  0.9474, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3693, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.10, 0.35, 11.1381, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.15,  0.8069, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0232, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.15, 10.5769, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.25,  2.7026, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.6997, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.25, 12.7857, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00,  90.00, 0.10, 0.10, 0.50, 0.35,  4.9329, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.3679, 1.0e-4),
                new EuropeanOptionData(Option.Type.Call, 100.00, 110.00, 0.10, 0.10, 0.50, 0.35, 15.3086, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.15,  9.9210, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.15,  1.8734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.15,  0.0408, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.25, 10.2155, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.25,  3.1217, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.25,  0.4551, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.10, 0.35, 10.8479, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.10, 0.35,  4.3693, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.10, 0.35,  1.2376, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.15, 10.3192, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.15,  4.0232, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.15,  1.0646, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.25, 12.2149, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.25,  6.6997, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.25,  3.2734, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00,  90.00, 0.10, 0.10, 0.50, 0.35, 14.4452, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 100.00, 0.10, 0.10, 0.50, 0.35,  9.3679, 1.0e-4),
                new EuropeanOptionData(Option.Type.Put,  100.00, 110.00, 0.10, 0.10, 0.50, 0.35,  5.7963, 1.0e-4),
                // pag 27
                new EuropeanOptionData(Option.Type.Call,  40.00,  42.00, 0.08, 0.04, 0.75, 0.35,  5.0975, 1.0e-4)
            };

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

            double discFor        = 0.0;
            double discDom        = 0.0;
            double implVol        = 0.0;
            double deltaCall      = 0.0;
            double deltaPut       = 0.0;
            double expectedDiff   = 0.0;
            double calculatedDiff = 0.0;
            double error          = 0.0;
            double forward        = 0.0;

            SimpleQuote spotQuote = new SimpleQuote(0.0);

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

            StrikedTypePayoff payoff;
            Date     exDate;
            Exercise exercise;

            double tolerance = 1.0e-10;

            for (int i = 0; i < values.Length; ++i)
            {
                payoff   = new PlainVanillaPayoff(Option.Type.Call, 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));
                forward = spotQuote.value() * discFor / discDom;

                BlackDeltaCalculator myCalc = new BlackDeltaCalculator(Option.Type.Call, DeltaVolQuote.DeltaType.Spot,
                                                                       spotQuote.value(), discDom, discFor, implVol);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = discFor;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for spot delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }
                myCalc.setDeltaType(DeltaVolQuote.DeltaType.Fwd);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = 1.0;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for forward delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaSpot);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = discFor * values[i].strike / forward;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for premium-adjusted spot delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }

                myCalc.setDeltaType(DeltaVolQuote.DeltaType.PaFwd);

                deltaCall = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Put);
                deltaPut = myCalc.deltaFromStrike(values[i].strike);
                myCalc.setOptionType(Option.Type.Call);

                expectedDiff   = values[i].strike / forward;
                calculatedDiff = deltaCall - deltaPut;
                error          = Math.Abs(expectedDiff - calculatedDiff);

                if (error > tolerance)
                {
                    QAssert.Fail("\n Put-call parity failed for premium-adjusted forward delta. \n"
                                 + "Calculated Call Delta: " + deltaCall + "\n"
                                 + "Calculated Put Delta:  " + deltaPut + "\n"
                                 + "Expected Difference:   " + expectedDiff + "\n"
                                 + "Calculated Difference: " + calculatedDiff);
                }
            }
        }
Ejemplo n.º 22
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),
                new AmericanOptionData(Option.Type.Put,  100.00, 100.00, 0.00, 0.00, 0.50, 0.15, 4.22949)
            };

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

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

            double tolerance = 3.0e-3;

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

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

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

                IPricingEngine engine = new BaroneAdesiWhaleyApproximationEngine(stochProcess);

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

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

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

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

                Date today = Date.Today;
                Settings.setEvaluationDate(today);

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

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

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

                            IPricingEngine engine = FastActivator <Engine> .Create().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();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 25
0
        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);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <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 err)
                    {
                        return(optionSecurity.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 (optionSecurity.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()));
            }
        }
Ejemplo n.º 27
0
        public static string eqInstSpreadOptionMonteCarlo(
            [ExcelArgument(Description = "id of option to be constructed ")] string ObjectId,
            [ExcelArgument(Description = "Option type (Call/Put) ")] string optype,
            [ExcelArgument(Description = "Spot price leg 1")] double spot1,
            [ExcelArgument(Description = "Spot price leg 2")] double spot2,
            [ExcelArgument(Description = "Strike price ")] double stirkeprice,
            [ExcelArgument(Description = "Expiry Date ")] DateTime exdate,
            [ExcelArgument(Description = "Risk free rate ")] double riskfreerate,
            [ExcelArgument(Description = "Black-Scholes Vol for leg 1 ")] double vol1,
            [ExcelArgument(Description = "Black-Scholes Vol for leg 2 ")] double vol2,
            [ExcelArgument(Description = "correlation between leg 1 and leg 2 ")] double corr,
            [ExcelArgument(Description = "DayCounter ")] string daycounter,
            [ExcelArgument(Description = "Calendar ")] string calendar,
            [ExcelArgument(Description = "Pseudorandom (pr) or lowdiscrepancy (ld) ")] string traits,
            [ExcelArgument(Description = "trigger ")] object trigger)
        {
            if (ExcelUtil.CallFromWizard())
            {
                return("");
            }

            string callerAddress = "";

            callerAddress = ExcelUtil.getActiveCellAddress();

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

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

                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>(exdate);

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


                YieldTermStructureHandle rTSH = new YieldTermStructureHandle(
                    new FlatForward(settlementdate, riskfreerate, dc));
                BlackVolTermStructureHandle flatVolTSH1 = new BlackVolTermStructureHandle(
                    new BlackConstantVol(settlementdate, cal, vol1, dc));
                BlackVolTermStructureHandle flatVolTSH2 = new BlackVolTermStructureHandle(
                    new BlackConstantVol(settlementdate, cal, vol2, dc));

                Quote       qh1 = new SimpleQuote(spot1);
                Quote       qh2 = new SimpleQuote(spot2);
                QuoteHandle s1  = new QuoteHandle(qh1);
                QuoteHandle s2  = new QuoteHandle(qh2);

                BlackProcess p1 = new BlackProcess(s1, rTSH, flatVolTSH1);
                BlackProcess p2 = new BlackProcess(s2, rTSH, flatVolTSH2);

                StochasticProcessVector spv = new StochasticProcessVector(2);
                spv.Add(p1);
                spv.Add(p2);

                Matrix corrmtrx = new Matrix(2, 2);
                corrmtrx.set(0, 0, 1.0); corrmtrx.set(1, 1, 1.0);
                corrmtrx.set(0, 1, corr); corrmtrx.set(1, 0, corr);
                StochasticProcessArray spa = new StochasticProcessArray(spv, corrmtrx);

                PricingEngine engine = new MCEuropeanBasketEngine(spa, traits, 100, 1, false, true, 5000, 1e-6);

                Payoff payoff1 = new PlainVanillaPayoff(optiontype, stirkeprice);
                Payoff payoff2 = new SpreadBasketPayoff(payoff1);

                Exercise exercise = new EuropeanExercise(maturitydate);

                BasketOption bo = new BasketOption(payoff2, exercise);

                bo.setPricingEngine(engine);

                // Store the option and return its id
                string id = "OPTION@" + ObjectId;
                OHRepository.Instance.storeObject(id, bo, 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!");
            }
        }
Ejemplo n.º 28
0
        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);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 29
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);
            }
        }
Ejemplo n.º 30
0
        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);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 31
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);
                //}
            }
        }
Ejemplo n.º 32
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SimpleQuote obj) {
   return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
 }
Ejemplo n.º 33
0
        public void testAssetAtExpiryOrNothingAmericanValues()
        {
            // Testing American asset-(at-expiry)-or-nothing digital option

            DigitalOptionData[] values =
            {
                //        type, strike,   spot,    q,    r,   t,  vol,   value, tol
                // "Option pricing formulas", E.G. Haug, McGraw-Hill 1998 - pag 95, case 7,8,11,12
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                     64.8426, 1e-04, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     77.7017, 1e-04, true),
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                     40.1574, 1e-04, false),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     17.2983, 1e-04, false),
                // data from Haug VBA code results
                new DigitalOptionData(Option.Type.Put,  100.00, 105.00, 0.01, 0.10, 0.5, 0.20,                     65.5291, 1e-04, true),
                new DigitalOptionData(Option.Type.Call, 100.00,  95.00, 0.01, 0.10, 0.5, 0.20,                     76.5951, 1e-04, true),
                // in the money options (guaranteed discounted payoff = forward * riskFreeDiscount
                //                                                    = spot * dividendDiscount)
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.00, 0.10, 0.5, 0.20,                    105.0000, 1e-12, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.00, 0.10, 0.5, 0.20,                     95.0000, 1e-12, true),
                new DigitalOptionData(Option.Type.Call, 100.00, 105.00, 0.01, 0.10, 0.5, 0.20, 105.0000 * Math.Exp(-0.005), 1e-12, true),
                new DigitalOptionData(Option.Type.Put,  100.00,  95.00, 0.01, 0.10, 0.5, 0.20,  95.0000 * Math.Exp(-0.005), 1e-12, true)
            };

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

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

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

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

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

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

                IPricingEngine engine;
                if (values[i].knockin)
                {
                    engine = new AnalyticDigitalAmericanEngine(stochProcess);
                }
                else
                {
                    engine = new AnalyticDigitalAmericanKOEngine(stochProcess);
                }

                VanillaOption opt = new VanillaOption(payoff, amExercise);
                opt.setPricingEngine(engine);

                double calculated = opt.NPV();
                double error      = Math.Abs(calculated - values[i].result);
                if (error > values[i].tol)
                {
                    REPORT_FAILURE("value", payoff, amExercise, values[i].s,
                                   values[i].q, values[i].r, today, values[i].v,
                                   values[i].result, calculated, error, values[i].tol, values[i].knockin);
                }
            }
        }