Example #1
0
        // 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)
                    {
                        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]);
                }
            }
        }
Example #2
0
 public YoYInflationCapFloor makeYoYCapFloor(CapFloorType type,
     List<CashFlow> leg,
     double strike,
     double volatility,
     int which)
 {
     YoYInflationCapFloor result = null;
     switch (type)
     {
         case CapFloorType.Cap:
             result = new YoYInflationCap(leg, new List<double>(){strike});
             break;
         case CapFloorType.Floor:
             result = new YoYInflationFloor( leg, new List<double>() { strike } );
             break;
         default:
             Utils.QL_FAIL("unknown YoYInflation cap/floor type");
             break;
     }
     result.setPricingEngine(makeEngine(volatility, which));
     return result;
 }
Example #3
0
        public override void calculate()
        {
            if (model_ == null)
            {
                throw new ArgumentException("null model");
            }

            Date       referenceDate = new Date();
            DayCounter dayCounter    = new DayCounter();

            try{
                TermStructureConsistentModel tsmodel = (TermStructureConsistentModel)model_.link;
                ///if (tsmodel != null)
                referenceDate = tsmodel.termStructure().link.referenceDate();
                dayCounter    = tsmodel.termStructure().link.dayCounter();
            }
            //else
            catch
            {
                referenceDate = termStructure_.link.referenceDate();
                dayCounter    = termStructure_.link.dayCounter();
            }

            double       value    = 0.0;
            CapFloorType type     = arguments_.type;
            int          nPeriods = arguments_.endDates.Count;

            for (int i = 0; i < nPeriods; i++)
            {
                double fixingTime =
                    dayCounter.yearFraction(referenceDate,
                                            arguments_.fixingDates[i]);
                double paymentTime =
                    dayCounter.yearFraction(referenceDate,
                                            arguments_.endDates[i]);
                #if QL_TODAYS_PAYMENTS
                if (paymentTime >= 0.0)
                {
                #else
                if (paymentTime > 0.0)
                {
                #endif
                    double tenor  = arguments_.accrualTimes[i];
                    double fixing = (double)arguments_.forwards[i];
                    if (fixingTime <= 0.0)
                    {
                        if (type == CapFloorType.Cap || type == CapFloorType.Collar)
                        {
                            double discount = model_.link.discount(paymentTime);
                            double strike   = (double)arguments_.capRates[i];
                            value += discount * arguments_.nominals[i] * tenor
                                     * arguments_.gearings[i]
                                     * Math.Max(0.0, fixing - strike);
                        }
                        if (type == CapFloorType.Floor || type == CapFloorType.Collar)
                        {
                            double discount = model_.link.discount(paymentTime);
                            double strike   = (double)arguments_.floorRates[i];
                            double mult     = (type == CapFloorType.Floor) ? 1.0 : -1.0;
                            value += discount * arguments_.nominals[i] * tenor
                                     * mult * arguments_.gearings[i]
                                     * Math.Max(0.0, strike - fixing);
                        }
                    }
                    else
                    {
                        double maturity =
                            dayCounter.yearFraction(referenceDate,
                                                    arguments_.startDates[i]);
                        if (type == CapFloorType.Cap || type == CapFloorType.Collar)
                        {
                            double temp = 1.0 + (double)arguments_.capRates[i] * tenor;
                            value += arguments_.nominals[i] *
                                     arguments_.gearings[i] * temp *
                                     model_.link.discountBondOption(Option.Type.Put, 1.0 / temp,
                                                                    maturity, paymentTime);
                        }
                        if (type == CapFloorType.Floor || type == CapFloorType.Collar)
                        {
                            double temp = 1.0 + (double)arguments_.floorRates[i] * tenor;
                            double mult = (type == CapFloorType.Floor) ? 1.0 : -1.0;
                            value += arguments_.nominals[i] *
                                     arguments_.gearings[i] * temp *mult *
                                     model_.link.discountBondOption(Option.Type.Call, 1.0 / temp,
                                                                    maturity, paymentTime);
                        }
                    }
                }
            }
            results_.value = value;
        }
    }
        public override void calculate()
        {
            // copy black version then adapt to others

            double value      = 0.0;
            int    optionlets = arguments_.startDates.Count;
            InitializedList <double> values   = new InitializedList <double>(optionlets, 0.0);
            InitializedList <double> stdDevs  = new InitializedList <double>(optionlets, 0.0);
            InitializedList <double> forwards = new InitializedList <double> (optionlets, 0.0);
            CapFloorType             type     = arguments_.type;

            Handle <YoYInflationTermStructure> yoyTS
                = index().yoyInflationTermStructure();
            Handle <YieldTermStructure> nominalTS
                = yoyTS.link.nominalTermStructure();
            Date settlement = nominalTS.link.referenceDate();


            for (int i = 0; i < optionlets; ++i)
            {
                Date paymentDate = arguments_.payDates[i];
                if (paymentDate > settlement)
                {
                    // discard expired caplets
                    double d = arguments_.nominals[i] *
                               arguments_.gearings[i] *
                               nominalTS.link.discount(paymentDate) *
                               arguments_.accrualTimes[i];

                    // We explicitly have the index and assume that
                    // the fixing is natural, i.e. no convexity adjustment.
                    // If that was required then we would also need
                    // nominal vols in the pricing engine, i.e. a different engine.
                    // This also means that we do not need the coupon to have
                    // a pricing engine to return the swaplet rate and then
                    // the adjusted fixing in the instrument.
                    forwards[i] = yoyTS.link.yoyRate(arguments_.fixingDates[i], new Period(0, TimeUnit.Days));
                    double forward = forwards[i];

                    Date   fixingDate = arguments_.fixingDates[i];
                    double sqrtTime   = 0.0;
                    if (fixingDate > volatility_.link.baseDate())
                    {
                        sqrtTime = Math.Sqrt(volatility_.link.timeFromBase(fixingDate));
                    }

                    if (type == CapFloorType.Cap || type == CapFloorType.Collar)
                    {
                        double strike = arguments_.capRates[i].Value;
                        if (sqrtTime > 0.0)
                        {
                            stdDevs[i] = Math.Sqrt(volatility_.link.totalVariance(fixingDate, strike, new Period(0, TimeUnit.Days)));
                        }

                        // sttDev=0 for already-fixed dates so everything on forward
                        values[i] = optionletImpl(Option.Type.Call, strike, forward, stdDevs[i], d);
                    }
                    if (type == CapFloorType.Floor || type == CapFloorType.Collar)
                    {
                        double strike = arguments_.floorRates[i].Value;
                        if (sqrtTime > 0.0)
                        {
                            stdDevs[i] = Math.Sqrt(volatility_.link.totalVariance(fixingDate, strike, new Period(0, TimeUnit.Days)));
                        }
                        double floorlet = optionletImpl(Option.Type.Put, strike, forward, stdDevs[i], d);
                        if (type == CapFloorType.Floor)
                        {
                            values[i] = floorlet;
                        }
                        else
                        {
                            // a collar is long a cap and short a floor
                            values[i] -= floorlet;
                        }
                    }
                    value += values[i];
                }
            }
            results_.value = value;

            results_.additionalResults["optionletsPrice"]      = values;
            results_.additionalResults["optionletsAtmForward"] = forwards;
            if (type != CapFloorType.Collar)
            {
                results_.additionalResults["optionletsStdDev"] = stdDevs;
            }
        }
Example #5
0
 public CapFloor makeCapFloor(CapFloorType type,
     List<CashFlow> leg,
     double strike,
     double volatility)
 {
     CapFloor result;
     switch (type) {
         case CapFloorType.Cap:
             result = (CapFloor)new Cap(leg, new List<double>() { strike });
             break;
         case CapFloorType.Floor:
             result = (CapFloor)new Floor(leg, new List<double>() { strike });
             break;
         default:
             throw new ArgumentException("unknown cap/floor type");
     }
     result.setPricingEngine(makeEngine(volatility));
     return result;
 }
Example #6
0
 string typeToString(CapFloorType type)
 {
     switch (type) {
         case CapFloorType.Cap:
             return "cap";
         case CapFloorType.Floor:
             return "floor";
         case CapFloorType.Collar:
             return "collar";
         default:
             throw new ArgumentException("unknown cap/floor type");
     }
 }
Example #7
0
        public override void calculate()
        {
            double        value      = 0.0;
            double        vega       = 0.0;
            int           optionlets = arguments_.startDates.Count;
            List <double> values     = new InitializedList <double>(optionlets, 0.0);
            List <double> vegas      = new InitializedList <double>(optionlets, 0.0);
            List <double> stdDevs    = new InitializedList <double>(optionlets, 0.0);
            CapFloorType  type       = arguments_.type;
            Date          today      = vol_.link.referenceDate();
            Date          settlement = discountCurve_.link.referenceDate();

            for (int i = 0; i < optionlets; ++i)
            {
                Date paymentDate = arguments_.endDates[i];
                // handling of settlementDate, npvDate and includeSettlementFlows
                // should be implemented.
                // For the double being just discard expired caplets
                if (paymentDate > settlement)
                {
                    double d = arguments_.nominals[i] *
                               arguments_.gearings[i] *
                               discountCurve_.link.discount(paymentDate) *
                               arguments_.accrualTimes[i];

                    double forward = arguments_.forwards[i].Value;

                    Date   fixingDate = arguments_.fixingDates[i];
                    double sqrtTime   = 0.0;
                    if (fixingDate > today)
                    {
                        sqrtTime = Math.Sqrt(vol_.link.timeFromReference(fixingDate));
                    }

                    if (type == CapFloorType.Cap || type == CapFloorType.Collar)
                    {
                        double strike = arguments_.capRates[i].Value;
                        if (sqrtTime > 0.0)
                        {
                            stdDevs[i] = Math.Sqrt(vol_.link.blackVariance(fixingDate, strike));
                            vegas[i]   = Utils.bachelierBlackFormulaStdDevDerivative(strike, forward, stdDevs[i], d) * sqrtTime;
                        }
                        // include caplets with past fixing date
                        values[i] = Utils.bachelierBlackFormula(Option.Type.Call, strike, forward, stdDevs[i], d);
                    }
                    if (type == CapFloorType.Floor || type == CapFloorType.Collar)
                    {
                        double strike       = arguments_.floorRates[i].Value;
                        double floorletVega = 0.0;
                        if (sqrtTime > 0.0)
                        {
                            stdDevs[i]   = Math.Sqrt(vol_.link.blackVariance(fixingDate, strike));
                            floorletVega = Utils.bachelierBlackFormulaStdDevDerivative(strike, forward, stdDevs[i], d) * sqrtTime;
                        }
                        double floorlet = Utils.bachelierBlackFormula(Option.Type.Put, strike, forward, stdDevs[i], d);
                        if (type == CapFloorType.Floor)
                        {
                            values[i] = floorlet;
                            vegas[i]  = floorletVega;
                        }
                        else
                        {
                            // a collar is long a cap and short a floor
                            values[i] -= floorlet;
                            vegas[i]  -= floorletVega;
                        }
                    }
                    value += values[i];
                    vega  += vegas[i];
                }
            }
            results_.value = value;
            results_.additionalResults["vega"] = vega;

            results_.additionalResults["optionletsPrice"]      = values;
            results_.additionalResults["optionletsVega"]       = vegas;
            results_.additionalResults["optionletsAtmForward"] = arguments_.forwards;
            if (type != CapFloorType.Collar)
            {
                results_.additionalResults["optionletsStdDev"] = stdDevs;
            }
        }