Exemplo n.º 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));
            }
        }
Exemplo n.º 2
0
        public override double value(double k)
        {
            double x1 = vega(k) / vegas[0]
                        * (Math.Log(xBegin_[1] / k) * Math.Log(xBegin_[2] / k))
                        / (Math.Log(xBegin_[1] / xBegin_[0]) * Math.Log(xBegin_[2] / xBegin_[0]));
            double x2 = vega(k) / vegas[1]
                        * (Math.Log(k / xBegin_[0]) * Math.Log(xBegin_[2] / k))
                        / (Math.Log(xBegin_[1] / xBegin_[0]) * Math.Log(xBegin_[2] / xBegin_[1]));
            double x3 = vega(k) / vegas[2]
                        * (Math.Log(k / xBegin_[0]) * Math.Log(k / xBegin_[1]))
                        / (Math.Log(xBegin_[2] / xBegin_[0]) * Math.Log(xBegin_[2] / xBegin_[1]));

            double cBS = Utils.blackFormula(Option.Type.Call, k, fwd_, atmVol_ * Math.Sqrt(T_), dDiscount_);
            double c   = cBS + x1 * (premiaMKT[0] - premiaBS[0]) + x2 * (premiaMKT[1] - premiaBS[1]) + x3 * (premiaMKT[2] - premiaBS[2]);
            double std = Utils.blackFormulaImpliedStdDev(Option.Type.Call, k, fwd_, c, dDiscount_);

            return(std / Math.Sqrt(T_));
        }
Exemplo n.º 3
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]);
                }
            }
        }