//------------------------------------------------------------------------- /// <summary> /// Calculates the present value of the Ibor caplet/floorlet period. /// <para> /// The result is expressed using the currency of the period. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the present value </returns> public virtual CurrencyAmount presentValue(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { validate(volatilities); Currency currency = period.Currency; if (ratesProvider.ValuationDate.isAfter(period.PaymentDate)) { return(CurrencyAmount.of(currency, 0d)); } double expiry = volatilities.relativeTime(period.FixingDateTime); double df = ratesProvider.discountFactor(currency, period.PaymentDate); PutCall putCall = period.PutCall; double strike = period.Strike; double indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); if (expiry < 0d) { // Option has expired already double sign = putCall.Call ? 1d : -1d; double payoff = Math.Max(sign * (indexRate - strike), 0d); return(CurrencyAmount.of(currency, df * payoff * period.YearFraction * period.Notional)); } double volatility = volatilities.volatility(expiry, strike, indexRate); double price = df * period.YearFraction * volatilities.price(expiry, putCall, strike, indexRate, volatility); return(CurrencyAmount.of(currency, price * period.Notional)); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value rates sensitivity of the Ibor caplet/floorlet. /// <para> /// The present value rates sensitivity of the caplet/floorlet is the sensitivity /// of the present value to the underlying curves. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the present value curve sensitivity </returns> public virtual PointSensitivityBuilder presentValueSensitivityRates(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { validate(volatilities); Currency currency = period.Currency; if (ratesProvider.ValuationDate.isAfter(period.PaymentDate)) { return(PointSensitivityBuilder.none()); } double expiry = volatilities.relativeTime(period.FixingDateTime); PutCall putCall = period.PutCall; double strike = period.Strike; double indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); PointSensitivityBuilder dfSensi = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(period.PaymentDate); if (expiry < 0d) { // Option has expired already double sign = putCall.Call ? 1d : -1d; double payoff = Math.Max(sign * (indexRate - strike), 0d); return(dfSensi.multipliedBy(payoff * period.YearFraction * period.Notional)); } PointSensitivityBuilder indexRateSensiSensi = ratesProvider.iborIndexRates(period.Index).ratePointSensitivity(period.IborRate.Observation); double volatility = volatilities.volatility(expiry, strike, indexRate); double df = ratesProvider.discountFactor(currency, period.PaymentDate); double factor = period.Notional * period.YearFraction; double fwdPv = factor * volatilities.price(expiry, putCall, strike, indexRate, volatility); double fwdDelta = factor * volatilities.priceDelta(expiry, putCall, strike, indexRate, volatility); return(dfSensi.multipliedBy(fwdPv).combinedWith(indexRateSensiSensi.multipliedBy(fwdDelta * df))); }
public virtual void test_builder_fail() { // rate observation missing assertThrowsIllegalArg(() => IborCapletFloorletPeriod.builder().notional(NOTIONAL).caplet(STRIKE).build()); // cap and floor missing assertThrowsIllegalArg(() => IborCapletFloorletPeriod.builder().notional(NOTIONAL).iborRate(RATE_COMP).build()); // cap and floor present assertThrowsIllegalArg(() => IborCapletFloorletPeriod.builder().notional(NOTIONAL).caplet(STRIKE).floorlet(STRIKE).iborRate(RATE_COMP).build()); }
public virtual void test_builder_fail() { // two currencies IborCapletFloorletPeriod periodGbp = IborCapletFloorletPeriod.builder().caplet(STRIKE).notional(NOTIONAL).currency(GBP).startDate(LocalDate.of(2011, 6, 17)).endDate(LocalDate.of(2011, 9, 19)).unadjustedStartDate(LocalDate.of(2011, 6, 17)).unadjustedEndDate(LocalDate.of(2011, 9, 17)).paymentDate(LocalDate.of(2011, 9, 21)).iborRate(IborRateComputation.of(EUR_EURIBOR_3M, LocalDate.of(2011, 9, 15), REF_DATA)).yearFraction(0.2611).build(); assertThrowsIllegalArg(() => ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(PERIOD_1, periodGbp).payReceive(RECEIVE).build()); // two indices IborCapletFloorletPeriod periodLibor = IborCapletFloorletPeriod.builder().caplet(STRIKE).notional(NOTIONAL).currency(EUR).startDate(LocalDate.of(2011, 6, 17)).endDate(LocalDate.of(2011, 9, 19)).unadjustedStartDate(LocalDate.of(2011, 6, 17)).unadjustedEndDate(LocalDate.of(2011, 9, 17)).paymentDate(LocalDate.of(2011, 9, 21)).iborRate(IborRateComputation.of(GBP_LIBOR_3M, LocalDate.of(2011, 9, 15), REF_DATA)).yearFraction(0.2611).build(); assertThrowsIllegalArg(() => ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(PERIOD_1, periodLibor).payReceive(RECEIVE).build()); }
//------------------------------------------------------------------------- /// <summary> /// Computes the implied volatility of the Ibor caplet/floorlet. /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the implied volatility </returns> public virtual double impliedVolatility(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { validate(volatilities); double expiry = volatilities.relativeTime(period.FixingDateTime); ArgChecker.isTrue(expiry >= 0d, "Option must be before expiry to compute an implied volatility"); double forward = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); double strike = period.Strike; return(volatilities.volatility(expiry, strike, forward)); }
public virtual void test_resolve_floor() { IborCapFloorLeg @base = IborCapFloorLeg.builder().calculation(RATE_CALCULATION).floorSchedule(FLOOR).currency(GBP).notional(NOTIONAL).paymentDateOffset(PAYMENT_OFFSET).paymentSchedule(SCHEDULE).payReceive(PAY).build(); LocalDate[] unadjustedDates = new LocalDate[] { START, START.plusMonths(3), START.plusMonths(6), START.plusMonths(9), START.plusMonths(12) }; IborCapletFloorletPeriod[] periods = new IborCapletFloorletPeriod[4]; for (int i = 0; i < 4; ++i) { LocalDate start = BUSS_ADJ.adjust(unadjustedDates[i], REF_DATA); LocalDate end = BUSS_ADJ.adjust(unadjustedDates[i + 1], REF_DATA); double yearFraction = EUR_EURIBOR_3M.DayCount.relativeYearFraction(start, end); LocalDate fixingDate = RATE_CALCULATION.FixingDateOffset.adjust(start, REF_DATA); periods[i] = IborCapletFloorletPeriod.builder().floorlet(STRIKES[i]).currency(GBP).startDate(start).endDate(end).unadjustedStartDate(unadjustedDates[i]).unadjustedEndDate(unadjustedDates[i + 1]).paymentDate(PAYMENT_OFFSET.adjust(end, REF_DATA)).notional(-NOTIONALS[i]).iborRate(IborRateComputation.of(EUR_EURIBOR_3M, fixingDate, REF_DATA)).yearFraction(yearFraction).build(); } ResolvedIborCapFloorLeg expected = ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(periods).payReceive(PAY).build(); ResolvedIborCapFloorLeg computed = @base.resolve(REF_DATA); assertEquals(computed, expected); }
public virtual void test_resolve_cap() { IborRateCalculation rateCalc = IborRateCalculation.builder().index(EUR_EURIBOR_3M).fixingRelativeTo(FixingRelativeTo.PERIOD_END).fixingDateOffset(EUR_EURIBOR_3M.FixingDateOffset).build(); IborCapFloorLeg @base = IborCapFloorLeg.builder().calculation(rateCalc).capSchedule(CAP).notional(NOTIONAL).paymentDateOffset(PAYMENT_OFFSET).paymentSchedule(SCHEDULE).payReceive(RECEIVE).build(); LocalDate[] unadjustedDates = new LocalDate[] { START, START.plusMonths(3), START.plusMonths(6), START.plusMonths(9), START.plusMonths(12) }; IborCapletFloorletPeriod[] periods = new IborCapletFloorletPeriod[4]; for (int i = 0; i < 4; ++i) { LocalDate start = BUSS_ADJ.adjust(unadjustedDates[i], REF_DATA); LocalDate end = BUSS_ADJ.adjust(unadjustedDates[i + 1], REF_DATA); double yearFraction = EUR_EURIBOR_3M.DayCount.relativeYearFraction(start, end); periods[i] = IborCapletFloorletPeriod.builder().caplet(CAP.InitialValue).currency(EUR).startDate(start).endDate(end).unadjustedStartDate(unadjustedDates[i]).unadjustedEndDate(unadjustedDates[i + 1]).paymentDate(PAYMENT_OFFSET.adjust(end, REF_DATA)).notional(NOTIONALS[i]).iborRate(IborRateComputation.of(EUR_EURIBOR_3M, rateCalc.FixingDateOffset.adjust(end, REF_DATA), REF_DATA)).yearFraction(yearFraction).build(); } ResolvedIborCapFloorLeg expected = ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(periods).payReceive(RECEIVE).build(); ResolvedIborCapFloorLeg computed = @base.resolve(REF_DATA); assertEquals(computed, expected); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value theta of the Ibor caplet/floorlet period. /// <para> /// The present value theta is given by the minus of the present value sensitivity to the {@code timeToExpiry} /// parameter of the model. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the present value theta </returns> public virtual CurrencyAmount presentValueTheta(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { validate(volatilities); double expiry = volatilities.relativeTime(period.FixingDateTime); Currency currency = period.Currency; if (expiry < 0d) { // Option has expired already return(CurrencyAmount.of(currency, 0d)); } double forward = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); double strike = period.Strike; double volatility = volatilities.volatility(expiry, strike, forward); PutCall putCall = period.PutCall; double df = ratesProvider.discountFactor(currency, period.PaymentDate); double priceTheta = df * period.YearFraction * volatilities.priceTheta(expiry, putCall, strike, forward, volatility); return(CurrencyAmount.of(currency, priceTheta * period.Notional)); }
public virtual void test_builder_full() { IborCapletFloorletPeriod test = IborCapletFloorletPeriod.builder().notional(NOTIONAL).startDate(START).endDate(END).unadjustedStartDate(START_UNADJ).unadjustedEndDate(END_UNADJ).paymentDate(PAYMENT).yearFraction(YEAR_FRACTION).currency(GBP).floorlet(STRIKE).iborRate(RATE_COMP).build(); assertEquals(test.Floorlet.Value, STRIKE); assertEquals(test.Caplet.HasValue, false); assertEquals(test.Strike, STRIKE); assertEquals(test.StartDate, START); assertEquals(test.EndDate, END); assertEquals(test.UnadjustedStartDate, START_UNADJ); assertEquals(test.UnadjustedEndDate, END_UNADJ); assertEquals(test.PaymentDate, PAYMENT); assertEquals(test.Currency, GBP); assertEquals(test.Notional, NOTIONAL); assertEquals(test.IborRate, RATE_COMP); assertEquals(test.Index, EUR_EURIBOR_3M); assertEquals(test.FixingDateTime, FIXING_TIME_ZONE); assertEquals(test.PutCall, PutCall.PUT); assertEquals(test.YearFraction, YEAR_FRACTION); }
//------------------------------------------------------------------------- public ResolvedIborCapFloorLeg resolve(ReferenceData refData) { Schedule adjustedSchedule = paymentSchedule.createSchedule(refData); DoubleArray cap = CapSchedule.Present ? capSchedule.resolveValues(adjustedSchedule) : null; DoubleArray floor = FloorSchedule.Present ? floorSchedule.resolveValues(adjustedSchedule) : null; DoubleArray notionals = notional.resolveValues(adjustedSchedule); DateAdjuster fixingDateAdjuster = calculation.FixingDateOffset.resolve(refData); DateAdjuster paymentDateAdjuster = paymentDateOffset.resolve(refData); System.Func <LocalDate, IborIndexObservation> obsFn = calculation.Index.resolve(refData); ImmutableList.Builder <IborCapletFloorletPeriod> periodsBuild = ImmutableList.builder(); for (int i = 0; i < adjustedSchedule.size(); i++) { SchedulePeriod period = adjustedSchedule.getPeriod(i); LocalDate paymentDate = paymentDateAdjuster.adjust(period.EndDate); LocalDate fixingDate = fixingDateAdjuster.adjust((calculation.FixingRelativeTo.Equals(FixingRelativeTo.PERIOD_START)) ? period.StartDate : period.EndDate); double signedNotional = payReceive.normalize(notionals.get(i)); periodsBuild.add(IborCapletFloorletPeriod.builder().unadjustedStartDate(period.UnadjustedStartDate).unadjustedEndDate(period.UnadjustedEndDate).startDate(period.StartDate).endDate(period.EndDate).iborRate(IborRateComputation.of(obsFn(fixingDate))).paymentDate(paymentDate).notional(signedNotional).currency(currency).yearFraction(period.yearFraction(calculation.DayCount, adjustedSchedule)).caplet(cap != null ? cap.get(i) : null).floorlet(floor != null ? floor.get(i) : null).build()); } return(ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(periodsBuild.build()).payReceive(payReceive).build()); }
internal static IborCapletFloorletPeriod sut2() { return(IborCapletFloorletPeriod.builder().notional(-NOTIONAL).startDate(START.plusDays(1)).endDate(END.plusDays(1)).floorlet(STRIKE).iborRate(IborRateComputation.of(USD_LIBOR_6M, LocalDate.of(2013, 2, 15), REF_DATA)).build()); }
//------------------------------------------------------------------------- internal static IborCapletFloorletPeriod sut() { return(IborCapletFloorletPeriod.builder().notional(NOTIONAL).startDate(START).endDate(END).caplet(STRIKE).iborRate(RATE_COMP).build()); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity of the Ibor caplet/floorlet to the rate curves. /// <para> /// The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the /// curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential /// re-calibration of the model parameters to the raw market data. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the point sensitivity to the rate curves </returns> public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyModel(IborCapletFloorletPeriod period, RatesProvider ratesProvider, SabrIborCapletFloorletVolatilities volatilities) { Currency currency = period.Currency; if (ratesProvider.ValuationDate.isAfter(period.PaymentDate)) { return(PointSensitivityBuilder.none()); } double expiry = volatilities.relativeTime(period.FixingDateTime); PutCall putCall = period.PutCall; double strike = period.Strike; double indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); PointSensitivityBuilder dfSensi = ratesProvider.discountFactors(currency).zeroRatePointSensitivity(period.PaymentDate); double factor = period.Notional * period.YearFraction; if (expiry < 0d) { // option expired already, but not yet paid double sign = putCall.Call ? 1d : -1d; double payoff = Math.Max(sign * (indexRate - strike), 0d); return(dfSensi.multipliedBy(payoff * factor)); } ValueDerivatives volatilityAdj = volatilities.volatilityAdjoint(expiry, strike, indexRate); PointSensitivityBuilder indexRateSensiSensi = ratesProvider.iborIndexRates(period.Index).ratePointSensitivity(period.IborRate.Observation); double df = ratesProvider.discountFactor(currency, period.PaymentDate); double fwdPv = factor * volatilities.price(expiry, putCall, strike, indexRate, volatilityAdj.Value); double fwdDelta = factor * volatilities.priceDelta(expiry, putCall, strike, indexRate, volatilityAdj.Value); double fwdVega = factor * volatilities.priceVega(expiry, putCall, strike, indexRate, volatilityAdj.Value); return(dfSensi.multipliedBy(fwdPv).combinedWith(indexRateSensiSensi.multipliedBy(fwdDelta * df + fwdVega * volatilityAdj.getDerivative(0) * df))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value sensitivity to the SABR model parameters of the Ibor caplet/floorlet. /// <para> /// The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the point sensitivity to the SABR model parameters </returns> public virtual PointSensitivityBuilder presentValueSensitivityModelParamsSabr(IborCapletFloorletPeriod period, RatesProvider ratesProvider, SabrIborCapletFloorletVolatilities volatilities) { double expiry = volatilities.relativeTime(period.FixingDateTime); if (expiry < 0d) { // option expired already return(PointSensitivityBuilder.none()); } Currency currency = period.Currency; PutCall putCall = period.PutCall; double strike = period.Strike; double indexRate = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); double factor = period.Notional * period.YearFraction; ValueDerivatives volatilityAdj = volatilities.volatilityAdjoint(expiry, strike, indexRate); DoubleArray derivative = volatilityAdj.Derivatives; double df = ratesProvider.discountFactor(currency, period.PaymentDate); double vega = df * factor * volatilities.priceVega(expiry, putCall, strike, indexRate, volatilityAdj.Value); IborCapletFloorletVolatilitiesName name = volatilities.Name; return(PointSensitivityBuilder.of(IborCapletFloorletSabrSensitivity.of(name, expiry, ALPHA, currency, vega * derivative.get(2)), IborCapletFloorletSabrSensitivity.of(name, expiry, BETA, currency, vega * derivative.get(3)), IborCapletFloorletSabrSensitivity.of(name, expiry, RHO, currency, vega * derivative.get(4)), IborCapletFloorletSabrSensitivity.of(name, expiry, NU, currency, vega * derivative.get(5)))); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the present value volatility sensitivity of the Ibor caplet/floorlet. /// <para> /// The present value volatility sensitivity of the caplet/floorlet is the sensitivity /// of the present value to the implied volatility. /// </para> /// <para> /// The sensitivity to the implied volatility is also called vega. /// /// </para> /// </summary> /// <param name="period"> the Ibor caplet/floorlet period </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the point sensitivity to the volatility </returns> public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(IborCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { validate(volatilities); double expiry = volatilities.relativeTime(period.FixingDateTime); double strike = period.Strike; Currency currency = period.Currency; if (expiry <= 0d) { // Option has expired already or at expiry return(PointSensitivityBuilder.none()); } double forward = ratesProvider.iborIndexRates(period.Index).rate(period.IborRate.Observation); double volatility = volatilities.volatility(expiry, strike, forward); PutCall putCall = period.PutCall; double df = ratesProvider.discountFactor(currency, period.PaymentDate); double vega = df * period.YearFraction * volatilities.priceVega(expiry, putCall, strike, forward, volatility); return(IborCapletFloorletSensitivity.of(volatilities.Name, expiry, strike, forward, currency, vega * period.Notional)); }