/// <summary> /// Calculates the strike. /// </summary> /// <param name="fixedLeg"> the fixed leg </param> /// <returns> the strike </returns> protected internal virtual double calculateStrike(ResolvedSwapLeg fixedLeg) { SwapPaymentPeriod paymentPeriod = fixedLeg.PaymentPeriods.get(0); ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "Payment period must be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod; // compounding is caught when par rate is computed RateComputation rateComputation = ratePaymentPeriod.AccrualPeriods.get(0).RateComputation; ArgChecker.isTrue(rateComputation is FixedRateComputation, "Swap leg must be fixed leg"); return(((FixedRateComputation)rateComputation).Rate); }
// find the notional private CurrencyAmount buildLegNotional(ResolvedSwapLeg leg) { // check for NotionalPaymentPeriod SwapPaymentPeriod firstPaymentPeriod = leg.PaymentPeriods.get(0); if (firstPaymentPeriod is NotionalPaymentPeriod) { NotionalPaymentPeriod pp = (NotionalPaymentPeriod)firstPaymentPeriod; return(pp.NotionalAmount.positive()); } return(NOT_FOUND); }
/// <summary> /// Computes the derivative of the conventional cash annuity with respect to the yield from a swap leg. /// <para> /// The computation is relevant only for standard swaps with constant notional and regular payments. /// The swap leg must be a fixed leg. However, this is not checked internally. /// /// </para> /// </summary> /// <param name="fixedLeg"> the fixed leg of the swap </param> /// <param name="yield"> the yield </param> /// <returns> the cash annuity </returns> public virtual ValueDerivatives annuityCashDerivative(ResolvedSwapLeg fixedLeg, double yield) { int nbFixedPeriod = fixedLeg.PaymentPeriods.size(); SwapPaymentPeriod paymentPeriod = fixedLeg.PaymentPeriods.get(0); ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "payment period should be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod; int nbFixedPaymentYear = (int)(long)Math.Round(1d / ratePaymentPeriod.DayCount.yearFraction(ratePaymentPeriod.StartDate, ratePaymentPeriod.EndDate), MidpointRounding.AwayFromZero); double notional = Math.Abs(ratePaymentPeriod.Notional); ValueDerivatives annuityUnit = annuityCash1(nbFixedPaymentYear, nbFixedPeriod, yield); return(ValueDerivatives.of(annuityUnit.Value * notional, annuityUnit.Derivatives.multipliedBy(notional))); }
//------------------------------------------------------------------------- /// <summary> /// Computes the conventional cash annuity from a swap leg. /// <para> /// The computation is relevant only for standard swaps with constant notional and regular payments. /// The swap leg must be a fixed leg. However, this is not checked internally. /// /// </para> /// </summary> /// <param name="fixedLeg"> the fixed leg of the swap </param> /// <param name="yield"> the yield </param> /// <returns> the cash annuity </returns> public virtual double annuityCash(ResolvedSwapLeg fixedLeg, double yield) { int nbFixedPeriod = fixedLeg.PaymentPeriods.size(); SwapPaymentPeriod paymentPeriod = fixedLeg.PaymentPeriods.get(0); ArgChecker.isTrue(paymentPeriod is RatePaymentPeriod, "payment period should be RatePaymentPeriod"); RatePaymentPeriod ratePaymentPeriod = (RatePaymentPeriod)paymentPeriod; int nbFixedPaymentYear = (int)(long)Math.Round(1d / ratePaymentPeriod.DayCount.yearFraction(ratePaymentPeriod.StartDate, ratePaymentPeriod.EndDate), MidpointRounding.AwayFromZero); double notional = Math.Abs(ratePaymentPeriod.Notional); double annuityCash = notional * this.annuityCash(nbFixedPaymentYear, nbFixedPeriod, yield); return(annuityCash); }
//------------------------------------------------------------------------- /// <summary> /// Computes the par rate for swaps with a fixed leg. /// <para> /// The par rate is the common rate on all payments of the fixed leg for which the total swap present value is 0. /// </para> /// <para> /// At least one leg must be a fixed leg. The par rate will be computed with respect to the first fixed leg /// in which all the payments are fixed payments with a unique accrual period (no compounding) and no FX reset. /// If the fixed leg is compounding, the par rate is computed only when the number of fixed coupon payments is 1 and /// accrual factor of each sub-period is 1 /// /// </para> /// </summary> /// <param name="swap"> the product </param> /// <param name="provider"> the rates provider </param> /// <returns> the par rate </returns> public virtual double parRate(ResolvedSwap swap, RatesProvider provider) { // find fixed leg ResolvedSwapLeg fixedLeg = this.fixedLeg(swap); Currency ccyFixedLeg = fixedLeg.Currency; // other payments (not fixed leg coupons) converted in fixed leg currency double otherLegsConvertedPv = 0.0; foreach (ResolvedSwapLeg leg in swap.Legs) { if (leg != fixedLeg) { double pvLocal = legPricer.presentValueInternal(leg, provider); otherLegsConvertedPv += (pvLocal * provider.fxRate(leg.Currency, ccyFixedLeg)); } } double fixedLegEventsPv = legPricer.presentValueEventsInternal(fixedLeg, provider); if (fixedLeg.PaymentPeriods.size() > 1) { // try multiperiod par-rate // PVBP double pvbpFixedLeg = legPricer.pvbp(fixedLeg, provider); // Par rate return(-(otherLegsConvertedPv + fixedLegEventsPv) / pvbpFixedLeg); } SwapPaymentPeriod firstPeriod = fixedLeg.PaymentPeriods.get(0); ArgChecker.isTrue(firstPeriod is RatePaymentPeriod, "PaymentPeriod must be instance of RatePaymentPeriod"); RatePaymentPeriod payment = (RatePaymentPeriod)firstPeriod; if (payment.AccrualPeriods.size() == 1) { // no compounding // PVBP double pvbpFixedLeg = legPricer.pvbp(fixedLeg, provider); // Par rate return(-(otherLegsConvertedPv + fixedLegEventsPv) / pvbpFixedLeg); } // try Compounding Triple <bool, int, double> fixedCompounded = checkFixedCompounded(fixedLeg); ArgChecker.isTrue(fixedCompounded.First, "Swap should have a fixed leg and for one payment it should be based on compunding witout spread."); double notional = payment.Notional; double df = provider.discountFactor(ccyFixedLeg, payment.PaymentDate); return(Math.Pow(-(otherLegsConvertedPv + fixedLegEventsPv) / (notional * df) + 1.0d, 1.0 / fixedCompounded.Second) - 1.0d); }