final CouponCMSSABRReplicationMethod methodCms = CouponCMSSABRReplicationMethod.getInstance();
final CapFloorCMSSABRReplicationMethod methodCmsCap = CapFloorCMSSABRReplicationMethod.getDefaultInstance();
final NormalImpliedVolatilityFormula impliedVolatility = new NormalImpliedVolatilityFormula();
final NormalPriceFunction normalPrice = new NormalPriceFunction();
final ParRateCalculator parRate = ParRateCalculator.getInstance();
final CouponCMS cmsCoupon1 = CouponCMS.from(CMS_CAP_SPREAD, SWAP_1, SETTLEMENT_TIME);
final CouponCMS cmsCoupon2 = CouponCMS.from(CMS_CAP_SPREAD, SWAP_2, SETTLEMENT_TIME);
final double cmsCoupon1Price = methodCms.presentValue(cmsCoupon1, SABR_BUNDLE).getAmount();
final double cmsCoupon2Price = methodCms.presentValue(cmsCoupon2, SABR_BUNDLE).getAmount();
final double expectedRate1 = cmsCoupon1Price / discountFactorPayment / cmsCoupon1.getNotional() / cmsCoupon1.getPaymentYearFraction();
final double expectedRate2 = cmsCoupon2Price / discountFactorPayment / cmsCoupon2.getNotional() / cmsCoupon2.getPaymentYearFraction();
final double forward1 = SWAP_1.accept(parRate, CURVES);
final double forward2 = SWAP_2.accept(parRate, CURVES);
final CapFloorCMS cmsCap1 = CapFloorCMS.from(cmsCoupon1, forward1, true);
final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, forward2, true);
final double cmsCap1Price = methodCmsCap.presentValue(cmsCap1, SABR_BUNDLE).getAmount();
final double cmsCap2Price = methodCmsCap.presentValue(cmsCap2, SABR_BUNDLE).getAmount();
final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(forward1, FIXING_TIME, true);
final NormalFunctionData dataCap1 = new NormalFunctionData(expectedRate1, 1.0, 0.0);
final double cmsCap1IV = impliedVolatility.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Price / discountFactorPayment / cmsCoupon1.getNotional() / cmsCoupon1.getPaymentYearFraction());
final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(forward2, FIXING_TIME, true);
final NormalFunctionData dataCap2 = new NormalFunctionData(expectedRate2, 1.0, 0.0);
final double cmsCap2IV = impliedVolatility.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Price / discountFactorPayment / cmsCoupon2.getNotional() / cmsCoupon2.getPaymentYearFraction());
double spreadVol = cmsCap1IV * cmsCap1IV - 2 * correlation * cmsCap1IV * cmsCap2IV + cmsCap2IV * cmsCap2IV;
spreadVol = Math.sqrt(spreadVol);
final EuropeanVanillaOption optionSpread = new EuropeanVanillaOption(STRIKE, FIXING_TIME, IS_CAP);
final NormalFunctionData dataSpread = new NormalFunctionData(expectedRate1 - expectedRate2, 1.0, spreadVol);
final Function1D<NormalFunctionData, Double> priceFunction = normalPrice.getPriceFunction(optionSpread);