/** * Calculates the present value of the swaption product. * * <p>The result is expressed using the currency of the swapion. * * @param swaption the product to price * @param ratesProvider the rates provider * @param volatilityProvider the normal volatility provider * @return the present value of the swaption product */ public CurrencyAmount presentValue( SwaptionProduct swaption, RatesProvider ratesProvider, NormalVolatilitySwaptionProvider volatilityProvider) { ExpandedSwaption expanded = swaption.expand(); validate(ratesProvider, expanded, volatilityProvider); ZonedDateTime expiryDateTime = expanded.getExpiryDateTime(); double expiry = volatilityProvider.relativeTime(expiryDateTime); ExpandedSwap underlying = expanded.getUnderlying(); ExpandedSwapLeg fixedLeg = fixedLeg(underlying); if (expiry < 0.0d) { // Option has expired already return CurrencyAmount.of(fixedLeg.getCurrency(), 0.0d); } double forward = swapPricer.parRate(underlying, ratesProvider); double pvbp = swapPricer.getLegPricer().pvbp(fixedLeg, ratesProvider); double strike = swapPricer.getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp); double tenor = volatilityProvider.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate()); double volatility = volatilityProvider.getVolatility(expiryDateTime, tenor, strike, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); boolean isCall = (fixedLeg.getPayReceive() == PayReceive.PAY); // Payer at strike is exercise when rate > strike, i.e. call on rate EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, expiry, isCall ? PutCall.CALL : PutCall.PUT); // option required to pass the strike (in case the swap has non-constant coupon). Function1D<NormalFunctionData, Double> func = NORMAL.getPriceFunction(option); double pv = func.evaluate(normalData) * ((expanded.getLongShort() == LongShort.LONG) ? 1.0 : -1.0); return CurrencyAmount.of(fixedLeg.getCurrency(), pv); }
public void convertCurrencyAmount() { List<FxRate> rates = ImmutableList.of( FxRate.of(Currency.GBP, Currency.USD, 1.61), FxRate.of(Currency.GBP, Currency.USD, 1.62), FxRate.of(Currency.GBP, Currency.USD, 1.63)); CalculationEnvironment marketData = MarketEnvironment.builder() .valuationDate(date(2011, 3, 8)) .addValue(FxRateId.of(Currency.GBP, Currency.USD), rates) .build(); MarketDataMappings mappings = MarketDataMappings.of(MarketDataFeed.NONE); DefaultCalculationMarketData calculationMarketData = DefaultCalculationMarketData.of(marketData, mappings); SingleScenarioResult<CurrencyAmount> test = SingleScenarioResult.of(3, CurrencyAmount.of(Currency.GBP, 2)); ScenarioResult<?> convertedList = test.convertedTo(Currency.USD, calculationMarketData); List<CurrencyAmount> expectedValues = ImmutableList.of( CurrencyAmount.of(Currency.USD, 2 * 1.61), CurrencyAmount.of(Currency.USD, 2 * 1.62), CurrencyAmount.of(Currency.USD, 2 * 1.63)); DefaultScenarioResult<CurrencyAmount> expectedList = DefaultScenarioResult.of(expectedValues); assertThat(convertedList).isEqualTo(expectedList); }
/** * Gets the notional amount, positive if receiving, negative if paying. * * <p>This is the notional amount applicable during the period. The currency of the notional is * specified by {@code currency} unless there is the {@code fxReset} property is present. * * @return the notional as a {@code CurrencyAmount} */ @Override public CurrencyAmount getNotionalAmount() { if (fxReset != null) { return CurrencyAmount.of(fxReset.getReferenceCurrency(), notional); } return CurrencyAmount.of(currency, notional); }
// ------------------------------------------------------------------------- public void test_priceSensitivity() { PointSensitivities point = OPTION_PRICER.priceSensitivityStickyStrike( FUTURE_OPTION_PRODUCT, RATE_PROVIDER, VOL_PROVIDER); CurveCurrencyParameterSensitivities computed = RATE_PROVIDER.curveParameterSensitivity(point); CurveCurrencyParameterSensitivities expected = FD_CAL.sensitivity( RATE_PROVIDER, (p) -> CurrencyAmount.of( EUR, OPTION_PRICER.price(FUTURE_OPTION_PRODUCT, (p), VOL_PROVIDER))); double futurePrice = FUTURE_PRICER.price(FUTURE_OPTION_PRODUCT.getUnderlying(), RATE_PROVIDER); double strike = FUTURE_OPTION_PRODUCT.getStrikePrice(); double expiryTime = ACT_365F.relativeYearFraction(VALUATION_DATE, FUTURE_OPTION_PRODUCT.getExpiryDate()); double logMoneyness = Math.log(strike / futurePrice); double logMoneynessUp = Math.log(strike / (futurePrice + EPS)); double logMoneynessDw = Math.log(strike / (futurePrice - EPS)); double vol = SURFACE.zValue(expiryTime, logMoneyness); double volUp = SURFACE.zValue(expiryTime, logMoneynessUp); double volDw = SURFACE.zValue(expiryTime, logMoneynessDw); double volSensi = 0.5 * (volUp - volDw) / EPS; double vega = BlackFormulaRepository.vega(futurePrice, strike, expiryTime, vol); CurveCurrencyParameterSensitivities sensiVol = RATE_PROVIDER .curveParameterSensitivity( FUTURE_PRICER.priceSensitivity( FUTURE_OPTION_PRODUCT.getUnderlying(), RATE_PROVIDER)) .multipliedBy(-vega * volSensi); expected = expected.combinedWith(sensiVol); assertTrue(computed.equalWithTolerance(expected, 30d * EPS)); }
// ------------------------------------------------------------------------- public void test_priceSensitivity() { PointSensitivities point = FUTURE_PRICER.priceSensitivity(FUTURE_PRODUCT, PROVIDER); CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point); CurrencyParameterSensitivities expected = FD_CAL.sensitivity( PROVIDER, (p) -> CurrencyAmount.of(USD, FUTURE_PRICER.price(FUTURE_PRODUCT, (p)))); assertTrue(computed.equalWithTolerance(expected, EPS * 10.0)); }
/** Test par spread sensitivity for ISDA FRA Discounting method. */ public void test_parSpreadSensitivity_ISDA() { PointSensitivities sensi = DEFAULT_PRICER.parSpreadSensitivity(FRA, IMM_PROV); CurveCurrencyParameterSensitivities sensiComputed = IMM_PROV.curveParameterSensitivity(sensi); CurveCurrencyParameterSensitivities sensiExpected = CAL_FD.sensitivity( IMM_PROV, (p) -> CurrencyAmount.of(FRA.getCurrency(), DEFAULT_PRICER.parSpread(FRA, (p)))); assertTrue(sensiComputed.equalWithTolerance(sensiExpected, EPS_FD)); }
public void test_dirtyPriceSensitivity() { PointSensitivityBuilder point = PRICER.dirtyPriceSensitivity(BOND_SECURITY, PROVIDER); CurveCurrencyParameterSensitivities computed = PROVIDER.curveParameterSensitivity(point.build()); CurveCurrencyParameterSensitivities expected = FD_CAL.sensitivity( PROVIDER, (p) -> CurrencyAmount.of(EUR, PRICER.dirtyPriceFromCurves(BOND_SECURITY, (p)))); assertTrue(computed.equalWithTolerance(expected, NOTIONAL * EPS)); }
/** * Totals all the sensitivity values. * * <p>The result is the total of all values, as converted to the specified currency. Any FX * conversion that is required will use rates from the provider. * * @param resultCurrency the currency of the result * @param rateProvider the provider of FX rates * @return the total sensitivity * @throws RuntimeException if no FX rate could be found */ public CurrencyAmount total(Currency resultCurrency, FxRateProvider rateProvider) { CurveCurrencyParameterSensitivities converted = convertedTo(resultCurrency, rateProvider); double total = converted .sensitivities .stream() .map(CurveCurrencyParameterSensitivity::getSensitivity) .flatMapToDouble(DoubleStream::of) .sum(); return CurrencyAmount.of(resultCurrency, total); }
/** Test {@link FxSingleTrade}. */ @Test public class FxSingleTradeTest { private static final CurrencyAmount GBP_P1000 = CurrencyAmount.of(GBP, 1_000); private static final CurrencyAmount GBP_M1000 = CurrencyAmount.of(GBP, -1_000); private static final CurrencyAmount USD_P1600 = CurrencyAmount.of(USD, 1_600); private static final CurrencyAmount USD_M1600 = CurrencyAmount.of(USD, -1_600); private static final LocalDate DATE_2015_06_30 = date(2015, 6, 30); private static final FxSingle FWD1 = FxSingle.of(GBP_P1000, USD_M1600, DATE_2015_06_30); private static final FxSingle FWD2 = FxSingle.of(GBP_M1000, USD_P1600, DATE_2015_06_30); // ------------------------------------------------------------------------- public void test_builder() { FxSingleTrade test = FxSingleTrade.builder().product(FWD1).build(); assertEquals(test.getTradeInfo(), TradeInfo.EMPTY); assertEquals(test.getProduct(), FWD1); } // ------------------------------------------------------------------------- public void coverage() { FxSingleTrade test = FxSingleTrade.builder() .tradeInfo(TradeInfo.builder().tradeDate(date(2014, 6, 30)).build()) .product(FWD1) .build(); coverImmutableBean(test); FxSingleTrade test2 = FxSingleTrade.builder().product(FWD2).build(); coverBeanEquals(test, test2); } public void test_serialization() { FxSingleTrade test = FxSingleTrade.builder() .tradeInfo(TradeInfo.builder().tradeDate(date(2014, 6, 30)).build()) .product(FWD1) .build(); assertSerialization(test); } }
public void test_priceSensitivityWithZSpread_continuous() { PointSensitivities point = FUTURE_PRICER.priceSensitivityWithZSpread( FUTURE_PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0); CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point); CurrencyParameterSensitivities expected = FD_CAL.sensitivity( PROVIDER, (p) -> CurrencyAmount.of( USD, FUTURE_PRICER.priceWithZSpread(FUTURE_PRODUCT, (p), Z_SPREAD, CONTINUOUS, 0))); assertTrue(computed.equalWithTolerance(expected, EPS * 10.0)); }
public void test_dirtyPriceSensitivityWithZspread_continuous() { PointSensitivityBuilder point = PRICER.dirtyPriceSensitivityWithZspread(BOND_SECURITY, PROVIDER, Z_SPREAD, CONTINUOUS, 0); CurveCurrencyParameterSensitivities computed = PROVIDER.curveParameterSensitivity(point.build()); CurveCurrencyParameterSensitivities expected = FD_CAL.sensitivity( PROVIDER, (p) -> CurrencyAmount.of( EUR, PRICER.dirtyPriceFromCurvesWithZSpread( BOND_SECURITY, (p), Z_SPREAD, CONTINUOUS, 0))); assertTrue(computed.equalWithTolerance(expected, NOTIONAL * EPS)); }
/** Test parameter sensitivity with finite difference sensitivity calculator. No cutoff period. */ public void rateChfNoCutOffParameterSensitivity() { LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; double[] time = new double[] {0.0, 0.5, 1.0, 2.0, 5.0, 10.0}; double[] rate = new double[] {0.0100, 0.0110, 0.0115, 0.0130, 0.0135, 0.0135}; for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { Curve onCurve = InterpolatedNodalCurve.of(Curves.zeroRates("ON", ACT_ACT_ISDA), time, rate, INTERPOLATOR); ImmutableRatesProvider prov = ImmutableRatesProvider.builder() .valuationDate(valuationDate[loopvaldate]) .indexCurves(ImmutableMap.of(CHF_TOIS, onCurve)) .timeSeries(ImmutableMap.of(CHF_TOIS, TIME_SERIES_BUILDER.build())) .build(); OvernightAveragedRateObservation ro = OvernightAveragedRateObservation.of(CHF_TOIS, FIXING_START_DATE, FIXING_END_DATE, 0); ForwardOvernightAveragedRateObservationFn obsFn = ForwardOvernightAveragedRateObservationFn.DEFAULT; PointSensitivityBuilder sensitivityBuilderComputed = obsFn.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, prov); CurveCurrencyParameterSensitivities parameterSensitivityComputed = prov.curveParameterSensitivity(sensitivityBuilderComputed.build()); CurveCurrencyParameterSensitivities parameterSensitivityExpected = CAL_FD.sensitivity( prov, (p) -> CurrencyAmount.of( CHF_TOIS.getCurrency(), obsFn.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, (p)))); assertTrue( parameterSensitivityComputed.equalWithTolerance( parameterSensitivityExpected, EPS_FD * 10.0)); } }
/** Test {@link FxNdfFunctionGroups}. */ @Test public class FxNdfFunctionGroupsTest { private static final FxRate FX_RATE = FxRate.of(GBP, USD, 1.5d); private static final CurrencyAmount NOTIONAL = CurrencyAmount.of(GBP, (double) 100_000_000); private static final FxNdf PRODUCT = FxNdf.builder() .agreedFxRate(FX_RATE) .settlementCurrencyNotional(NOTIONAL) .index(GBP_USD_WM) .paymentDate(date(2015, 3, 19)) .build(); public static final FxNdfTrade TRADE = FxNdfTrade.builder() .tradeInfo(TradeInfo.builder().tradeDate(date(2015, 6, 1)).build()) .product(PRODUCT) .build(); public void test_discounting() { FunctionGroup<FxNdfTrade> test = FxNdfFunctionGroups.discounting(); assertThat(test.configuredMeasures(TRADE)) .contains( Measure.PRESENT_VALUE, Measure.PV01, Measure.BUCKETED_PV01, Measure.CURRENCY_EXPOSURE, Measure.FORWARD_FX_RATE); } public void test_presentValue() { Currency ccy1 = TRADE.getProduct().getNonDeliverableCurrency(); Currency ccy2 = TRADE.getProduct().getSettlementCurrency(); LocalDate valDate = TRADE.getProduct().getPaymentDate().plusDays(7); FunctionConfig<FxNdfTrade> config = FxNdfFunctionGroups.discounting().functionConfig(TRADE, Measure.PRESENT_VALUE).get(); CalculationSingleFunction<FxNdfTrade, ?> function = config.createFunction(); FunctionRequirements reqs = function.requirements(TRADE); assertThat(reqs.getOutputCurrencies()).containsOnly(ccy1, ccy2); assertThat(reqs.getSingleValueRequirements()) .isEqualTo(ImmutableSet.of(DiscountCurveKey.of(ccy1), DiscountCurveKey.of(ccy2))); assertThat(reqs.getTimeSeriesRequirements()).isEqualTo(ImmutableSet.of()); assertThat(function.defaultReportingCurrency(TRADE)).hasValue(GBP); DiscountFactors df1 = SimpleDiscountFactors.of( ccy1, valDate, ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99)); DiscountFactors df2 = SimpleDiscountFactors.of( ccy2, valDate, ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99)); TestMarketDataMap md = new TestMarketDataMap( valDate, ImmutableMap.of(DiscountCurveKey.of(ccy1), df1, DiscountCurveKey.of(ccy2), df2), ImmutableMap.of()); assertThat(function.execute(TRADE, md)) .isEqualTo(FxConvertibleList.of(ImmutableList.of(CurrencyAmount.zero(GBP)))); } // ------------------------------------------------------------------------- public void coverage() { coverPrivateConstructor(FxNdfFunctionGroups.class); } public void coverage_functions() { Currency ccy1 = TRADE.getProduct().getNonDeliverableCurrency(); Currency ccy2 = TRADE.getProduct().getSettlementCurrency(); LocalDate valDate = TRADE.getProduct().getPaymentDate().plusDays(7); Curve df = ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99); FxRate fxRate = FxRate.of(ccy1, ccy2, 1.6d); TestMarketDataMap md = new TestMarketDataMap( valDate, ImmutableMap.of( DiscountCurveKey.of(ccy1), df, DiscountCurveKey.of(ccy2), df, FxRateKey.of(ccy1, ccy2), fxRate), ImmutableMap.of( IndexRateKey.of(GBP_USD_WM), LocalDateDoubleTimeSeries.of(date(2015, 3, 17), 1.45d))); assertNotNull(new FxNdfBucketedPv01Function().execute(TRADE, md)); assertNotNull(new FxNdfCurrencyExposureFunction().execute(TRADE, md)); assertNotNull(new FxNdfForwardFxRateFunction().execute(TRADE, md)); assertNotNull(new FxNdfPv01Function().execute(TRADE, md)); assertNotNull(new FxNdfPvFunction().execute(TRADE, md)); } }
public void test_cashFlowEquivalent() { Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build(); ExpandedSwapLeg computed = CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER); ExpandedSwapLeg computedIborLeg = CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG.expand(), PROVIDER); ExpandedSwapLeg computedFixedLeg = CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG.expand(), PROVIDER); assertEquals(computedFixedLeg.getPaymentEvents(), computed.getPaymentEvents().subList(0, 2)); assertEquals(computedIborLeg.getPaymentEvents(), computed.getPaymentEvents().subList(2, 6)); // expected payments from fixed leg NotionalExchange fixedPayment1 = NotionalExchange.of(PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1)); NotionalExchange fixedPayment2 = NotionalExchange.of(PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2)); // expected payments from ibor leg LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1); double fixedYearFraction1 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1)); double beta1 = (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING1)) * PROVIDER.discountFactor(GBP, PAYMENT1) / PROVIDER.discountFactor(GBP, fixingSTART1); NotionalExchange iborPayment11 = NotionalExchange.of( fixingSTART1, CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1)); NotionalExchange iborPayment12 = NotionalExchange.of( PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1)); LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2); double fixedYearFraction2 = GBP_LIBOR_3M .getDayCount() .relativeYearFraction( fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2)); double beta2 = (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING2)) * PROVIDER.discountFactor(GBP, PAYMENT2) / PROVIDER.discountFactor(GBP, fixingSTART2); NotionalExchange iborPayment21 = NotionalExchange.of( fixingSTART2, CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2)); NotionalExchange iborPayment22 = NotionalExchange.of( PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2)); ExpandedSwapLeg expected = ExpandedSwapLeg.builder() .type(OTHER) .payReceive(RECEIVE) .paymentEvents( fixedPayment1, fixedPayment2, iborPayment11, iborPayment12, iborPayment21, iborPayment22) .build(); double eps = 1.0e-12; assertEquals(computed.getPaymentEvents().size(), expected.getPaymentEvents().size()); for (int i = 0; i < 6; ++i) { NotionalExchange payCmp = (NotionalExchange) computed.getPaymentEvents().get(i); NotionalExchange payExp = (NotionalExchange) expected.getPaymentEvents().get(i); assertEquals(payCmp.getCurrency(), payExp.getCurrency()); assertEquals(payCmp.getPaymentDate(), payExp.getPaymentDate()); assertTrue( DoubleMath.fuzzyEquals( payCmp.getPaymentAmount().getAmount(), payExp.getPaymentAmount().getAmount(), NOTIONAL * eps)); } }
/** Test {@link SabrExtrapolationReplicationCmsTradePricer}. */ @Test public class DiscountingCmsTradePricerTest { private static final ReferenceData REF_DATA = ReferenceData.standard(); // trades private static final LocalDate VALUATION = LocalDate.of(2015, 8, 18); private static final SwapIndex INDEX = SwapIndices.EUR_EURIBOR_1100_5Y; private static final LocalDate START = LocalDate.of(2015, 10, 21); private static final LocalDate END = LocalDate.of(2020, 10, 21); private static final Frequency FREQUENCY = Frequency.P12M; private static final BusinessDayAdjustment BUSS_ADJ_EUR = BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA); private static final PeriodicSchedule SCHEDULE_EUR = PeriodicSchedule.of( START, END, FREQUENCY, BUSS_ADJ_EUR, StubConvention.NONE, RollConventions.NONE); private static final double NOTIONAL_VALUE = 1.0e6; private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONAL_VALUE); private static final ResolvedCmsLeg CMS_LEG = CmsLeg.builder() .index(INDEX) .notional(NOTIONAL) .payReceive(RECEIVE) .paymentSchedule(SCHEDULE_EUR) .build() .resolve(REF_DATA); private static final ResolvedSwapLeg PAY_LEG = RateCalculationSwapLeg.builder() .payReceive(PAY) .accrualSchedule(SCHEDULE_EUR) .calculation(FixedRateCalculation.of(0.01, ACT_360)) .paymentSchedule( PaymentSchedule.builder() .paymentFrequency(FREQUENCY) .paymentDateOffset(DaysAdjustment.NONE) .build()) .notionalSchedule(NotionalSchedule.of(CurrencyAmount.of(EUR, NOTIONAL_VALUE))) .build() .resolve(REF_DATA); private static final ResolvedCms CMS_TWO_LEGS = ResolvedCms.of(CMS_LEG, PAY_LEG); private static final ResolvedCms CMS_ONE_LEG = ResolvedCms.of(CMS_LEG); private static final Payment PREMIUM = Payment.of(CurrencyAmount.of(EUR, -0.03 * NOTIONAL_VALUE), VALUATION); private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VALUATION).build(); private static final ResolvedCmsTrade CMS_TRADE = ResolvedCmsTrade.builder().product(CMS_TWO_LEGS).info(TRADE_INFO).build(); private static final ResolvedCmsTrade CMS_TRADE_PREMIUM = ResolvedCmsTrade.builder().product(CMS_ONE_LEG).premium(PREMIUM).build(); // providers private static final ImmutableRatesProvider RATES_PROVIDER = SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(VALUATION); // providers - valuation on payment date private static final LocalDate FIXING = LocalDate.of(2016, 10, 19); // fixing for the second period. private static final double OBS_INDEX = 0.013; private static final LocalDateDoubleTimeSeries TIME_SERIES = LocalDateDoubleTimeSeries.of(FIXING, OBS_INDEX); private static final LocalDate PAYMENT = LocalDate.of(2017, 10, 23); // payment date of the second payment private static final ImmutableRatesProvider RATES_PROVIDER_ON_PAY = SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(PAYMENT, TIME_SERIES); // pricers private static final DiscountingCmsProductPricer PRODUCT_PRICER = DiscountingCmsProductPricer.DEFAULT; private static final DiscountingPaymentPricer PREMIUM_PRICER = DiscountingPaymentPricer.DEFAULT; private static final DiscountingCmsTradePricer TRADE_PRICER = DiscountingCmsTradePricer.DEFAULT; private static final double TOL = 1.0e-13; public void test_presentValue() { MultiCurrencyAmount pv1 = TRADE_PRICER.presentValue(CMS_TRADE_PREMIUM, RATES_PROVIDER); MultiCurrencyAmount pv2 = TRADE_PRICER.presentValue(CMS_TRADE, RATES_PROVIDER); MultiCurrencyAmount pvProd1 = PRODUCT_PRICER.presentValue(CMS_ONE_LEG, RATES_PROVIDER); MultiCurrencyAmount pvProd2 = PRODUCT_PRICER.presentValue(CMS_TWO_LEGS, RATES_PROVIDER); CurrencyAmount pvPrem = PREMIUM_PRICER.presentValue(PREMIUM, RATES_PROVIDER); assertEquals(pv1, pvProd1.plus(pvPrem)); assertEquals(pv2, pvProd2); } public void test_presentValueSensitivity() { PointSensitivities pt1 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE_PREMIUM, RATES_PROVIDER); PointSensitivities pt2 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE, RATES_PROVIDER); PointSensitivityBuilder ptProd1 = PRODUCT_PRICER.presentValueSensitivity(CMS_ONE_LEG, RATES_PROVIDER); PointSensitivityBuilder ptProd2 = PRODUCT_PRICER.presentValueSensitivity(CMS_TWO_LEGS, RATES_PROVIDER); PointSensitivityBuilder ptPrem = PREMIUM_PRICER.presentValueSensitivity(PREMIUM, RATES_PROVIDER); assertEquals(pt1, ptProd1.combinedWith(ptPrem).build()); assertEquals(pt2, ptProd2.build()); } public void test_currencyExposure() { MultiCurrencyAmount computed1 = TRADE_PRICER.currencyExposure(CMS_TRADE_PREMIUM, RATES_PROVIDER); MultiCurrencyAmount computed2 = TRADE_PRICER.currencyExposure(CMS_TRADE, RATES_PROVIDER); MultiCurrencyAmount pv1 = TRADE_PRICER.presentValue(CMS_TRADE_PREMIUM, RATES_PROVIDER); PointSensitivities pt1 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE_PREMIUM, RATES_PROVIDER); MultiCurrencyAmount expected1 = RATES_PROVIDER.currencyExposure(pt1).plus(pv1); MultiCurrencyAmount pv2 = TRADE_PRICER.presentValue(CMS_TRADE, RATES_PROVIDER); PointSensitivities pt2 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE, RATES_PROVIDER); MultiCurrencyAmount expected2 = RATES_PROVIDER.currencyExposure(pt2).plus(pv2); assertEquals( computed1.getAmount(EUR).getAmount(), expected1.getAmount(EUR).getAmount(), NOTIONAL_VALUE * TOL); assertEquals( computed2.getAmount(EUR).getAmount(), expected2.getAmount(EUR).getAmount(), NOTIONAL_VALUE * TOL); } public void test_currentCash() { MultiCurrencyAmount cc1 = TRADE_PRICER.currentCash(CMS_TRADE_PREMIUM, RATES_PROVIDER); MultiCurrencyAmount cc2 = TRADE_PRICER.currentCash(CMS_TRADE, RATES_PROVIDER); assertEquals(cc1, MultiCurrencyAmount.of(PREMIUM.getValue())); assertEquals(cc2, MultiCurrencyAmount.of(CurrencyAmount.zero(EUR))); } public void test_currentCash_onPay() { MultiCurrencyAmount cc1 = TRADE_PRICER.currentCash(CMS_TRADE_PREMIUM, RATES_PROVIDER_ON_PAY); MultiCurrencyAmount cc2 = TRADE_PRICER.currentCash(CMS_TRADE, RATES_PROVIDER_ON_PAY); MultiCurrencyAmount ccProd1 = PRODUCT_PRICER.currentCash(CMS_ONE_LEG, RATES_PROVIDER_ON_PAY); MultiCurrencyAmount ccProd2 = PRODUCT_PRICER.currentCash(CMS_TWO_LEGS, RATES_PROVIDER_ON_PAY); assertEquals(cc1, ccProd1); assertEquals(cc2, ccProd2); } }
/** Test {@link BlackFxVanillaOptionTradePricer}. */ @Test public class BlackFxVanillaOptionTradePricerTest { private static final LocalDate VAL_DATE = RatesProviderDataSets.VAL_DATE_2014_01_22; private static final LocalTime VAL_TIME = LocalTime.of(13, 45); private static final ZoneId ZONE = ZoneId.of("Z"); private static final ZonedDateTime VAL_DATE_TIME = VAL_DATE.atTime(VAL_TIME).atZone(ZONE); private static final ZonedDateTime EXPIRY = ZonedDateTime.of(2014, 5, 9, 13, 10, 0, 0, ZONE); private static final FxMatrix FX_MATRIX = RatesProviderFxDataSets.fxMatrix(); private static final RatesProvider RATES_PROVIDER = RatesProviderFxDataSets.createProviderEURUSD(VAL_DATE); private static final DoubleArray TIME_TO_EXPIRY = DoubleArray.of(0.01, 0.252, 0.501, 1.0, 2.0, 5.0); private static final DoubleArray ATM = DoubleArray.of(0.175, 0.185, 0.18, 0.17, 0.16, 0.16); private static final DoubleArray DELTA = DoubleArray.of(0.10, 0.25); private static final DoubleMatrix RISK_REVERSAL = DoubleMatrix.ofUnsafe( new double[][] { {-0.010, -0.0050}, {-0.011, -0.0060}, {-0.012, -0.0070}, {-0.013, -0.0080}, {-0.014, -0.0090}, {-0.014, -0.0090} }); private static final DoubleMatrix STRANGLE = DoubleMatrix.ofUnsafe( new double[][] { {0.0300, 0.0100}, {0.0310, 0.0110}, {0.0320, 0.0120}, {0.0330, 0.0130}, {0.0340, 0.0140}, {0.0340, 0.0140} }); private static final InterpolatedStrikeSmileDeltaTermStructure SMILE_TERM = InterpolatedStrikeSmileDeltaTermStructure.of( TIME_TO_EXPIRY, DELTA, ATM, RISK_REVERSAL, STRANGLE, ACT_365F); private static final CurrencyPair CURRENCY_PAIR = CurrencyPair.of(EUR, USD); private static final BlackFxOptionSmileVolatilities VOLS = BlackFxOptionSmileVolatilities.of( FxOptionVolatilitiesName.of("Test"), CURRENCY_PAIR, VAL_DATE_TIME, SMILE_TERM); private static final LocalDate PAYMENT_DATE = LocalDate.of(2014, 5, 13); private static final double NOTIONAL = 1.0e6; private static final CurrencyAmount EUR_AMOUNT = CurrencyAmount.of(EUR, NOTIONAL); private static final CurrencyAmount USD_AMOUNT = CurrencyAmount.of(USD, -NOTIONAL * FX_MATRIX.fxRate(EUR, USD)); private static final ResolvedFxSingle FX_PRODUCT = ResolvedFxSingle.of(EUR_AMOUNT, USD_AMOUNT, PAYMENT_DATE); private static final ResolvedFxVanillaOption OPTION_PRODUCT = ResolvedFxVanillaOption.builder() .longShort(SHORT) .expiry(EXPIRY) .underlying(FX_PRODUCT) .build(); private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VAL_DATE).build(); private static final LocalDate CASH_SETTLE_DATE = LocalDate.of(2014, 1, 25); private static final Payment PREMIUM = Payment.of(EUR, NOTIONAL * 0.027, CASH_SETTLE_DATE); private static final ResolvedFxVanillaOptionTrade OPTION_TRADE = ResolvedFxVanillaOptionTrade.builder() .premium(PREMIUM) .product(OPTION_PRODUCT) .info(TRADE_INFO) .build(); private static final BlackFxVanillaOptionProductPricer PRICER_PRODUCT = BlackFxVanillaOptionProductPricer.DEFAULT; private static final BlackFxVanillaOptionTradePricer PRICER_TRADE = BlackFxVanillaOptionTradePricer.DEFAULT; private static final DiscountingPaymentPricer PRICER_PAYMENT = DiscountingPaymentPricer.DEFAULT; private static final double TOL = 1.0e-13; public void test_presentValue() { MultiCurrencyAmount pvSensiTrade = PRICER_TRADE.presentValue(OPTION_TRADE, RATES_PROVIDER, VOLS); CurrencyAmount pvSensiProduct = PRICER_PRODUCT.presentValue(OPTION_PRODUCT, RATES_PROVIDER, VOLS); CurrencyAmount pvSensiPremium = PRICER_PAYMENT.presentValue(PREMIUM, RATES_PROVIDER); assertEquals(pvSensiTrade, MultiCurrencyAmount.of(pvSensiProduct, pvSensiPremium)); } public void test_presentValueSensitivity() { PointSensitivities pvSensiTrade = PRICER_TRADE.presentValueSensitivityRates(OPTION_TRADE, RATES_PROVIDER, VOLS); PointSensitivities pvSensiProduct = PRICER_PRODUCT.presentValueSensitivityRates(OPTION_PRODUCT, RATES_PROVIDER, VOLS); PointSensitivities pvSensiPremium = PRICER_PAYMENT.presentValueSensitivity(PREMIUM, RATES_PROVIDER).build(); assertEquals(pvSensiTrade, pvSensiProduct.combinedWith(pvSensiPremium)); } public void test_presentValueSensitivityBlackVolatility() { PointSensitivities pvSensiTrade = PRICER_TRADE.presentValueSensitivityModelParamsVolatility( OPTION_TRADE, RATES_PROVIDER, VOLS); PointSensitivities pvSensiProduct = PRICER_PRODUCT .presentValueSensitivityModelParamsVolatility(OPTION_PRODUCT, RATES_PROVIDER, VOLS) .build(); assertEquals(pvSensiTrade, pvSensiProduct); } public void test_currencyExposure() { MultiCurrencyAmount ceComputed = PRICER_TRADE.currencyExposure(OPTION_TRADE, RATES_PROVIDER, VOLS); PointSensitivities point = PRICER_TRADE.presentValueSensitivityRates(OPTION_TRADE, RATES_PROVIDER, VOLS); MultiCurrencyAmount pv = PRICER_TRADE.presentValue(OPTION_TRADE, RATES_PROVIDER, VOLS); MultiCurrencyAmount ceExpected = RATES_PROVIDER.currencyExposure(point).plus(pv); assertEquals(ceComputed.size(), 2); assertEquals( ceComputed.getAmount(EUR).getAmount(), ceExpected.getAmount(EUR).getAmount(), TOL * NOTIONAL); assertEquals( ceComputed.getAmount(USD).getAmount(), ceExpected.getAmount(USD).getAmount(), TOL * NOTIONAL); } public void test_currentCash_zero() { assertEquals( PRICER_TRADE.currentCash(OPTION_TRADE, VAL_DATE), CurrencyAmount.zero(PREMIUM.getCurrency())); } public void test_currentCash_onSettle() { assertEquals(PRICER_TRADE.currentCash(OPTION_TRADE, CASH_SETTLE_DATE), PREMIUM.getValue()); } }