/// <summary> /// Computes cash flow equivalent of Ibor leg. /// <para> /// The return type is {@code ResolvedSwapLeg} in which individual payments are /// represented in terms of {@code NotionalExchange}. /// /// </para> /// </summary> /// <param name="iborLeg"> the Ibor leg </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the cash flow equivalent </returns> public static ResolvedSwapLeg cashFlowEquivalentIborLeg(ResolvedSwapLeg iborLeg, RatesProvider ratesProvider) { ArgChecker.isTrue(iborLeg.Type.Equals(SwapLegType.IBOR), "Leg type should be IBOR"); ArgChecker.isTrue(iborLeg.PaymentEvents.Empty, "PaymentEvent should be empty"); IList <NotionalExchange> paymentEvents = new List <NotionalExchange>(); foreach (SwapPaymentPeriod paymentPeriod in iborLeg.PaymentPeriods) { ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "rate payment should be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod; ArgChecker.isTrue(ratePaymentPeriod.AccrualPeriods.size() == 1, "rate payment should not be compounding"); RateAccrualPeriod rateAccrualPeriod = ratePaymentPeriod.AccrualPeriods.get(0); CurrencyAmount notional = ratePaymentPeriod.NotionalAmount; LocalDate paymentDate = ratePaymentPeriod.PaymentDate; IborIndexObservation obs = ((IborRateComputation)rateAccrualPeriod.RateComputation).Observation; IborIndex index = obs.Index; LocalDate fixingStartDate = obs.EffectiveDate; double fixingYearFraction = obs.YearFraction; double beta = (1d + fixingYearFraction * ratesProvider.iborIndexRates(index).rate(obs)) * ratesProvider.discountFactor(paymentPeriod.Currency, paymentPeriod.PaymentDate) / ratesProvider.discountFactor(paymentPeriod.Currency, fixingStartDate); double ycRatio = rateAccrualPeriod.YearFraction / fixingYearFraction; NotionalExchange payStart = NotionalExchange.of(notional.multipliedBy(beta * ycRatio), fixingStartDate); NotionalExchange payEnd = NotionalExchange.of(notional.multipliedBy(-ycRatio), paymentDate); paymentEvents.Add(payStart); paymentEvents.Add(payEnd); } ResolvedSwapLeg leg = ResolvedSwapLeg.builder().paymentEvents(paymentEvents).payReceive(PayReceive.RECEIVE).type(SwapLegType.OTHER).build(); return(leg); }
/// <summary> /// Computes cash flow equivalent of swap. /// <para> /// The swap should be a fix-for-Ibor swap without compounding, and its swap legs /// should not involve {@code PaymentEvent}. /// </para> /// <para> /// The return type is {@code ResolvedSwapLeg} in which individual payments are /// represented in terms of {@code NotionalExchange}. /// /// </para> /// </summary> /// <param name="swap"> the swap product </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the cash flow equivalent </returns> public static ResolvedSwapLeg cashFlowEquivalentSwap(ResolvedSwap swap, RatesProvider ratesProvider) { validateSwap(swap); ResolvedSwapLeg cfFixed = cashFlowEquivalentFixedLeg(swap.getLegs(SwapLegType.FIXED).get(0), ratesProvider); ResolvedSwapLeg cfIbor = cashFlowEquivalentIborLeg(swap.getLegs(SwapLegType.IBOR).get(0), ratesProvider); ResolvedSwapLeg leg = ResolvedSwapLeg.builder().paymentEvents(Stream.concat(cfFixed.PaymentEvents.stream(), cfIbor.PaymentEvents.stream()).collect(Collectors.toList())).payReceive(PayReceive.RECEIVE).type(SwapLegType.OTHER).build(); return(leg); }
/// <summary> /// Computes cash flow equivalent of fixed leg. /// <para> /// The return type is {@code ResolvedSwapLeg} in which individual payments are /// represented in terms of {@code NotionalExchange}. /// /// </para> /// </summary> /// <param name="fixedLeg"> the fixed leg </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the cash flow equivalent </returns> public static ResolvedSwapLeg cashFlowEquivalentFixedLeg(ResolvedSwapLeg fixedLeg, RatesProvider ratesProvider) { ArgChecker.isTrue(fixedLeg.Type.Equals(SwapLegType.FIXED), "Leg type should be FIXED"); ArgChecker.isTrue(fixedLeg.PaymentEvents.Empty, "PaymentEvent should be empty"); IList <NotionalExchange> paymentEvents = new List <NotionalExchange>(); foreach (SwapPaymentPeriod paymentPeriod in fixedLeg.PaymentPeriods) { ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "rate payment should be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod; ArgChecker.isTrue(ratePaymentPeriod.AccrualPeriods.size() == 1, "rate payment should not be compounding"); RateAccrualPeriod rateAccrualPeriod = ratePaymentPeriod.AccrualPeriods.get(0); double factor = rateAccrualPeriod.YearFraction * ((FixedRateComputation)rateAccrualPeriod.RateComputation).Rate; CurrencyAmount notional = ratePaymentPeriod.NotionalAmount.multipliedBy(factor); LocalDate paymentDate = ratePaymentPeriod.PaymentDate; NotionalExchange pay = NotionalExchange.of(notional, paymentDate); paymentEvents.Add(pay); } ResolvedSwapLeg leg = ResolvedSwapLeg.builder().paymentEvents(paymentEvents).payReceive(PayReceive.RECEIVE).type(SwapLegType.OTHER).build(); return(leg); }