Example #1
0
        public double volatility(double strike, VolatilityType volatilityType, double shift = 0.0)
        {
            if (volatilityType == volatilityType_ && Utils.close(shift, this.shift()))
            {
                return(volatility(strike));
            }
            double?atm = atmLevel();

            Utils.QL_REQUIRE(atm != null, () => "smile section must provide atm level to compute converted volatilties");
            Option.Type type       = strike >= atm ? Option.Type.Call : Option.Type.Put;
            double      premium    = optionPrice(strike, type);
            double      premiumAtm = optionPrice(atm.Value, type);

            if (volatilityType == VolatilityType.ShiftedLognormal)
            {
                try
                {
                    return(Utils.blackFormulaImpliedStdDev(type, strike, atm.Value, premium, 1.0, shift) /
                           Math.Sqrt(exerciseTime()));
                }
                catch (Exception)
                {
                    return(Utils.blackFormulaImpliedStdDevChambers(type, strike, atm.Value, premium, premiumAtm, 1.0, shift) /
                           Math.Sqrt(exerciseTime()));
                }
            }
            else
            {
                return(Utils.bachelierBlackFormulaImpliedVol(type, strike, atm.Value, exerciseTime(), premium));
            }
        }
Example #2
0
        //! \name LazyObject interface
        //@{
        protected override void performCalculations()
        {
            // update dates
            Date                referenceDate = termVolSurface_.referenceDate();
            DayCounter          dc            = termVolSurface_.dayCounter();
            BlackCapFloorEngine dummy         = new BlackCapFloorEngine( // discounting does not matter here
                iborIndex_.forwardingTermStructure(), 0.20, dc);

            for (int i = 0; i < nOptionletTenors_; ++i)
            {
                CapFloor temp = new MakeCapFloor(CapFloorType.Cap,
                                                 capFloorLengths_[i],
                                                 iborIndex_,
                                                 0.04, // dummy strike
                                                 new Period(0, TimeUnit.Days))
                                .withPricingEngine(dummy);
                FloatingRateCoupon lFRC = temp.lastFloatingRateCoupon();
                optionletDates_[i]          = lFRC.fixingDate();
                optionletPaymentDates_[i]   = lFRC.date();
                optionletAccrualPeriods_[i] = lFRC.accrualPeriod();
                optionletTimes_[i]          = dc.yearFraction(referenceDate,
                                                              optionletDates_[i]);
                atmOptionletRate_[i] = lFRC.indexFixing();
            }

            if (floatingSwitchStrike_ && capFlooMatrixNotInitialized_)
            {
                double averageAtmOptionletRate = 0.0;
                for (int i = 0; i < nOptionletTenors_; ++i)
                {
                    averageAtmOptionletRate += atmOptionletRate_[i];
                }
                switchStrike_ = averageAtmOptionletRate / nOptionletTenors_;
            }

            Handle <YieldTermStructure> discountCurve = discount_.empty()
            ? iborIndex_.forwardingTermStructure()
            : discount_;

            List <double> strikes = new List <double>(termVolSurface_.strikes());

            // initialize CapFloorMatrix
            if (capFlooMatrixNotInitialized_)
            {
                for (int i = 0; i < nOptionletTenors_; ++i)
                {
                    capFloors_[i] = new List <CapFloor>(nStrikes_);
                }
                // construction might go here
                for (int j = 0; j < nStrikes_; ++j)
                {
                    // using out-of-the-money options
                    CapFloorType capFloorType = strikes[j] < switchStrike_
                  ? CapFloorType.Floor
                  : CapFloorType.Cap;
                    for (int i = 0; i < nOptionletTenors_; ++i)
                    {
                        //volQuotes_[i][j] = new SimpleQuote();
                        if (volatilityType_ == VolatilityType.ShiftedLognormal)
                        {
                            BlackCapFloorEngine engine = new BlackCapFloorEngine(discountCurve,
                                                                                 new Handle <Quote>(volQuotes_[i][j]), dc, displacement_);
                            capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j],
                                                               new Period(0, TimeUnit.Days)).withPricingEngine(engine));
                        }
                        else if (volatilityType_ == VolatilityType.Normal)
                        {
                            BachelierCapFloorEngine engine = new BachelierCapFloorEngine(discountCurve,
                                                                                         new Handle <Quote>(volQuotes_[i][j]), dc);
                            capFloors_[i].Add(new MakeCapFloor(capFloorType, capFloorLengths_[i], iborIndex_, strikes[j],
                                                               new Period(0, TimeUnit.Days)).withPricingEngine(engine));
                        }
                        else
                        {
                            Utils.QL_FAIL("unknown volatility type: " + volatilityType_);
                        }
                    }
                }
                capFlooMatrixNotInitialized_ = false;
            }

            for (int j = 0; j < nStrikes_; ++j)
            {
                Option.Type optionletType = strikes[j] < switchStrike_ ? Option.Type.Put : Option.Type.Call;

                double previousCapFloorPrice = 0.0;
                for (int i = 0; i < nOptionletTenors_; ++i)
                {
                    capFloorVols_[i, j] = termVolSurface_.volatility(capFloorLengths_[i], strikes[j], true);
                    volQuotes_[i][j].setValue(capFloorVols_[i, j]);

                    capFloorPrices_[i, j]  = capFloors_[i][j].NPV();
                    optionletPrices_[i, j] = capFloorPrices_[i, j] - previousCapFloorPrice;
                    previousCapFloorPrice  = capFloorPrices_[i, j];
                    double d = discountCurve.link.discount(optionletPaymentDates_[i]);
                    double optionletAnnuity = optionletAccrualPeriods_[i] * d;
                    try
                    {
                        if (volatilityType_ == VolatilityType.ShiftedLognormal)
                        {
                            optionletStDevs_[i, j] = Utils.blackFormulaImpliedStdDev(optionletType, strikes[j], atmOptionletRate_[i],
                                                                                     optionletPrices_[i, j], optionletAnnuity, displacement_, optionletStDevs_[i, j], accuracy_,
                                                                                     maxIter_);
                        }
                        else if (volatilityType_ == VolatilityType.Normal)
                        {
                            optionletStDevs_[i, j] = Math.Sqrt(optionletTimes_[i]) *
                                                     Utils.bachelierBlackFormulaImpliedVol(
                                optionletType, strikes[j], atmOptionletRate_[i],
                                optionletTimes_[i], optionletPrices_[i, j],
                                optionletAnnuity);
                        }
                        else
                        {
                            Utils.QL_FAIL("Unknown volatility type: " + volatilityType_);
                        }
                    }
                    catch (Exception e)
                    {
                        if (dontThrow_)
                        {
                            optionletStDevs_[i, j] = 0.0;
                        }
                        else
                        {
                            Utils.QL_FAIL("could not bootstrap optionlet:" +
                                          "\n type:    " + optionletType +
                                          "\n strike:  " + (strikes[j]) +
                                          "\n atm:     " + (atmOptionletRate_[i]) +
                                          "\n price:   " + optionletPrices_[i, j] +
                                          "\n annuity: " + optionletAnnuity +
                                          "\n expiry:  " + optionletDates_[i] +
                                          "\n error:   " + e.Message);
                        }
                    }
                    optionletVolatilities_[i][j] = optionletStDevs_[i, j] / Math.Sqrt(optionletTimes_[i]);
                }
            }
        }