Пример #1
0
        public void testAnalyticContinuousGeometricAveragePrice()
        {
            //("Testing analytic continuous geometric average-price Asians...");
            // data from "Option Pricing Formulas", Haug, pag.96-97

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

            SimpleQuote spot = new SimpleQuote(80.0);
            SimpleQuote qRate = new SimpleQuote(-0.03);
            YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc);
            SimpleQuote rRate = new SimpleQuote(0.05);
            YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc);
            SimpleQuote vol = new SimpleQuote(0.20);
            BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc);

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

            IPricingEngine engine = new
                AnalyticContinuousGeometricAveragePriceAsianEngine(stochProcess);

            Average.Type averageType = Average.Type.Geometric;
            Option.Type type = Option.Type.Put;
            double strike = 85.0;
            Date exerciseDate = today + 90;

            int pastFixings = 0; //Null<int>();
            double runningAccumulator = 0.0; //Null<Real>();

            StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);

            Exercise exercise = new EuropeanExercise(exerciseDate);

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

            double calculated = option.NPV();
            double expected = 4.6922;
            double tolerance = 1.0e-4;
            if (Math.Abs(calculated - expected) > tolerance)
            {
                REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings,
                               new List<Date>(), payoff, exercise, spot.value(),
                               qRate.value(), rRate.value(), today,
                               vol.value(), expected, calculated, tolerance);
            }

            // trying to approximate the continuous version with the discrete version
            runningAccumulator = 1.0;
            pastFixings = 0;
            List<Date> fixingDates = new InitializedList<Date>(exerciseDate - today + 1);
            for (int i = 0; i < fixingDates.Count; i++)
            {
                fixingDates[i] = today + i;
            }
            IPricingEngine engine2 = new
                AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess);

            DiscreteAveragingAsianOption option2 =
                new DiscreteAveragingAsianOption(averageType,
                                                 runningAccumulator, pastFixings,
                                                 fixingDates,
                                                 payoff,
                                                 exercise);
            option2.setPricingEngine(engine2);

            calculated = option2.NPV();
            tolerance = 3.0e-3;
            /*if (Math.Abs(calculated - expected) > tolerance)
            {
                REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings,
                               fixingDates, payoff, exercise, spot.value(),
                               qRate.value(), rRate.value(), today,
                               vol.value(), expected, calculated, tolerance);
            }*/
        }
Пример #2
0
        public void testMCDiscreteGeometricAveragePrice()
        {
            //BOOST_MESSAGE("Testing Monte Carlo discrete geometric average-price Asians...");

            // data from "Implementing Derivatives Model",
            // Clewlow, Strickland, p.118-123

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

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

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

            double tolerance = 4.0e-3;

            IPricingEngine engine =
            new MakeMCDiscreteGeometricAPEngine
                                <LowDiscrepancy,Statistics>(stochProcess)
                                .withStepsPerYear(1)
                                .withSamples(8191)
                                .value();

            Average.Type averageType = Average.Type.Geometric;
            double runningAccumulator = 1.0;
            int pastFixings = 0;
            int futureFixings = 10;
            Option.Type type = Option.Type.Call;
            double strike = 100.0;
            StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);

            Date exerciseDate = today + 360;
            Exercise exercise = new EuropeanExercise(exerciseDate);

            List<Date> fixingDates = new InitializedList<Date>(futureFixings);
            int dt = (int)(360/futureFixings+0.5);
            fixingDates[0] = today + dt;
            for (int j=1; j<futureFixings; j++)
            fixingDates[j] = fixingDates[j-1] + dt;

            DiscreteAveragingAsianOption  option =
            new DiscreteAveragingAsianOption(averageType, runningAccumulator,
                                            pastFixings, fixingDates,
                                            payoff, exercise);
            option.setPricingEngine(engine);

            double calculated = option.NPV();

            IPricingEngine engine2 =
              new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess);
            option.setPricingEngine(engine2);
            double expected = option.NPV();

            if (Math.Abs(calculated-expected) > tolerance) {
            REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings,
                           fixingDates, payoff, exercise, spot.value(),
                           qRate.value(), rRate.value(), today,
                           vol.value(), expected, calculated, tolerance);
            }
        }
Пример #3
0
        public void testPastFixings()
        {
            //BOOST_MESSAGE("Testing use of past fixings in Asian options...");
            DayCounter dc = new Actual360();
            Date today = Date.Today ;

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

            StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Put, 100.0);

            Exercise exercise = new EuropeanExercise(today + new Period(1,TimeUnit.Years));

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

            // MC arithmetic average-price
            double runningSum = 0.0;
            int pastFixings = 0;
            List<Date> fixingDates1 = new InitializedList<Date>();
            for (int i=0; i<=12; ++i)
                fixingDates1.Add(today + new Period(i,TimeUnit.Months));

            DiscreteAveragingAsianOption option1 =
                new DiscreteAveragingAsianOption(Average.Type.Arithmetic, runningSum,
                                                 pastFixings, fixingDates1,
                                                 payoff, exercise);

            pastFixings = 2;
            runningSum = pastFixings * spot.value() * 0.8;
            List<Date> fixingDates2 = new InitializedList<Date>();
            for (int i=-2; i<=12; ++i)
                fixingDates2.Add(today + new Period(i,TimeUnit.Months));

            DiscreteAveragingAsianOption option2 =
                new DiscreteAveragingAsianOption(Average.Type.Arithmetic, runningSum,
                                                 pastFixings, fixingDates2,
                                                 payoff, exercise);

            IPricingEngine engine =
               new MakeMCDiscreteArithmeticAPEngine<LowDiscrepancy,Statistics>(stochProcess)
                .withStepsPerYear(1)
                .withSamples(2047)
                .value() ;

            option1.setPricingEngine(engine);
            option2.setPricingEngine(engine);

            double price1 = option1.NPV();
            double price2 = option2.NPV();

            if (Utils.close(price1, price2)) {
                Assert.Fail(
                     "past fixings had no effect on arithmetic average-price option"
                     + "\n  without fixings: " + price1
                     + "\n  with fixings:    " + price2);
            }

            // MC arithmetic average-strike
            engine = new MakeMCDiscreteArithmeticASEngine<LowDiscrepancy,Statistics>(stochProcess)
                .withSamples(2047)
                .value();

            option1.setPricingEngine(engine);
            option2.setPricingEngine(engine);

            price1 = option1.NPV();
            price2 = option2.NPV();

            if (Utils.close(price1, price2)) {
                Assert.Fail(
                     "past fixings had no effect on arithmetic average-strike option"
                     + "\n  without fixings: " + price1
                     + "\n  with fixings:    " + price2);
            }

            // analytic geometric average-price
            double runningProduct = 1.0;
            pastFixings = 0;

            DiscreteAveragingAsianOption option3 =
                new DiscreteAveragingAsianOption(Average.Type.Geometric, runningProduct,
                                                 pastFixings, fixingDates1,
                                                 payoff, exercise);

            pastFixings = 2;
            runningProduct = spot.value() * spot.value();

            DiscreteAveragingAsianOption option4 =
                new DiscreteAveragingAsianOption(Average.Type.Geometric, runningProduct,
                                                 pastFixings, fixingDates2,
                                                 payoff, exercise);

            engine = new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess);

            option3.setPricingEngine(engine);
            option4.setPricingEngine(engine);

            double price3 = option3.NPV();
            double price4 = option4.NPV();

            if (Utils.close(price3, price4)) {
                Assert.Fail(
                     "past fixings had no effect on geometric average-price option"
                     + "\n  without fixings: " + price3
                     + "\n  with fixings:    " + price4);
            }

            // MC geometric average-price
            engine = new MakeMCDiscreteGeometricAPEngine<LowDiscrepancy,Statistics>(stochProcess)
                        .withStepsPerYear(1)
                        .withSamples(2047)
                        .value();

            option3.setPricingEngine(engine);
            option4.setPricingEngine(engine);

            price3 = option3.NPV();
            price4 = option4.NPV();

            if (Utils.close(price3, price4)) {
                Assert.Fail(
                     "past fixings had no effect on geometric average-price option"
                     + "\n  without fixings: " + price3
                     + "\n  with fixings:    " + price4);
            }
        }
Пример #4
0
        public void testAnalyticDiscreteGeometricAveragePriceGreeks()
        {
            //BOOST_MESSAGE("Testing discrete-averaging geometric Asian greeks...");

             //SavedSettings backup;

             Dictionary<string,double> calculated, expected, tolerance;
             calculated = new Dictionary<string, double>(6);
             expected = new Dictionary<string, double>(6);
             tolerance = new Dictionary<string, double>(6);
             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[] underlyings = { 100.0 };
             double[] strikes = { 90.0, 100.0, 110.0 };
             double[] qRates = { 0.04, 0.05, 0.06 };
             double[] rRates = { 0.01, 0.05, 0.15 };
             int[] lengths = { 1, 2 };
             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<strikes.Length ; j++) {
                 for (int k=0; k<lengths.Length ; k++) {

                     EuropeanExercise maturity =
                                       new EuropeanExercise(
                                           today + new Period(lengths[k],TimeUnit.Years));

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

                     double runningAverage = 120;
                     int pastFixings = 1;

                     List<Date> fixingDates = new List<Date>();
                     for (Date d = today + new Period(3, TimeUnit.Months);
                               d <= maturity.lastDate();
                               d += new Period(3, TimeUnit.Months))
                         fixingDates.Add(d);

                     IPricingEngine engine =
                        new AnalyticDiscreteGeometricAveragePriceAsianEngine(process);

                     DiscreteAveragingAsianOption option =
                         new DiscreteAveragingAsianOption(Average.Type.Geometric,
                                                         runningAverage, pastFixings,
                                                         fixingDates, payoff, maturity);
                     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 (KeyValuePair<string, double> kvp in calculated){
                                       string greek = kvp.Key;
                                       double expct = expected[greek],
                                            calcl = calculated[greek],
                                            tol   = tolerance [greek];
                                       double error =Utilities.relativeError(expct,calcl,u);
                                       if (error>tol) {
                                           REPORT_FAILURE(greek, Average.Type.Geometric,
                                                          runningAverage, pastFixings,
                                                          new List<Date>(),
                                                          payoff, maturity,
                                                          u, q, r, today, v,
                                                          expct, calcl, tol);
                                       }
                                   }
                               }
                           }
                         }
                       }
                     }
                 }
               }
             }
        }