예제 #1
0
        public AssetSwap(bool parAssetSwap,
                         Bond bond,
                         double bondCleanPrice,
                         double nonParRepayment,
                         double gearing,
                         IborIndex iborIndex,
                         double spread = 0.0,
                         DayCounter floatingDayCount = null,
                         Date dealMaturity           = null,
                         bool payBondCoupon          = false)
            : base(2)
        {
            bond_            = bond;
            bondCleanPrice_  = bondCleanPrice;
            nonParRepayment_ = nonParRepayment;
            spread_          = spread;
            parSwap_         = parAssetSwap;

            Schedule tempSch = new Schedule(bond_.settlementDate(),
                                            bond_.maturityDate(),
                                            iborIndex.tenor(),
                                            iborIndex.fixingCalendar(),
                                            iborIndex.businessDayConvention(),
                                            iborIndex.businessDayConvention(),
                                            DateGeneration.Rule.Backward,
                                            false); // endOfMonth

            if (dealMaturity == null)
            {
                dealMaturity = bond_.maturityDate();
            }

            Utils.QL_REQUIRE(dealMaturity <= tempSch.dates().Last(), () =>
                             "deal maturity " + dealMaturity +
                             " cannot be later than (adjusted) bond maturity " +
                             tempSch.dates().Last());
            Utils.QL_REQUIRE(dealMaturity > tempSch.dates()[0], () =>
                             "deal maturity " + dealMaturity +
                             " must be later than swap start date " +
                             tempSch.dates()[0]);

            // the following might become an input parameter
            BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following;

            Date     finalDate = tempSch.calendar().adjust(dealMaturity, paymentAdjustment);
            Schedule schedule  = tempSch.until(finalDate);

            // bondCleanPrice must be the (forward) clean price
            // at the floating schedule start date
            upfrontDate_ = schedule.startDate();
            double dirtyPrice = bondCleanPrice_ +
                                bond_.accruedAmount(upfrontDate_);

            double notional = bond_.notional(upfrontDate_);

            /* In the market asset swap, the bond is purchased in return for
             * payment of the full price. The notional of the floating leg is
             * then scaled by the full price. */
            if (!parSwap_)
            {
                notional *= dirtyPrice / 100.0;
            }

            if (floatingDayCount == null)
            {
                legs_[1] = new IborLeg(schedule, iborIndex)
                           .withSpreads(spread)
                           .withGearings(gearing)
                           .withNotionals(notional)
                           .withPaymentAdjustment(paymentAdjustment);
            }
            else
            {
                legs_[1] = new IborLeg(schedule, iborIndex)
                           .withSpreads(spread)
                           .withGearings(gearing)
                           .withPaymentDayCounter(floatingDayCount)
                           .withNotionals(notional)
                           .withPaymentAdjustment(paymentAdjustment);
            }

            foreach (CashFlow c in legs_[1])
            {
                c.registerWith(update);
            }


            List <CashFlow> bondLeg = bond_.cashflows();
            // skip bond redemption
            int i;

            for (i = 0; i < bondLeg.Count && bondLeg[i].date() <= dealMaturity; ++i)
            {
                // whatever might be the choice for the discounting engine
                // bond flows on upfrontDate_ must be discarded
                bool upfrontDateBondFlows = false;
                if (!bondLeg[i].hasOccurred(upfrontDate_, upfrontDateBondFlows))
                {
                    legs_[0].Add(bondLeg[i]);
                }
            }
            // if the first skipped cashflow is not the redemption
            // and it is a coupon then add the accrued coupon
            if (i < bondLeg.Count - 1)
            {
                Coupon c = bondLeg[i] as Coupon;
                if (c != null)
                {
                    CashFlow accruedCoupon = new SimpleCashFlow(c.accruedAmount(dealMaturity), finalDate);
                    legs_[0].Add(accruedCoupon);
                }
            }
            // add the nonParRepayment_
            CashFlow nonParRepaymentFlow = new SimpleCashFlow(nonParRepayment_, finalDate);

            legs_[0].Add(nonParRepaymentFlow);

            Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg to start with");

            // special flows
            if (parSwap_)
            {
                // upfront on the floating leg
                double   upfront         = (dirtyPrice - 100.0) / 100.0 * notional;
                CashFlow upfrontCashFlow = new SimpleCashFlow(upfront, upfrontDate_);
                legs_[1].Insert(0, upfrontCashFlow);
                // backpayment on the floating leg
                // (accounts for non-par redemption, if any)
                double   backPayment         = notional;
                CashFlow backPaymentCashFlow = new SimpleCashFlow(backPayment, finalDate);
                legs_[1].Add(backPaymentCashFlow);
            }
            else
            {
                // final notional exchange
                CashFlow finalCashFlow = new SimpleCashFlow(notional, finalDate);
                legs_[1].Add(finalCashFlow);
            }

            Utils.QL_REQUIRE(!legs_[0].empty(), () => "empty bond leg");

            foreach (CashFlow c in legs_[0])
            {
                c.registerWith(update);
            }

            if (payBondCoupon)
            {
                payer_[0] = -1.0;
                payer_[1] = +1.0;
            }
            else
            {
                payer_[0] = +1.0;
                payer_[1] = -1.0;
            }
        }
예제 #2
0
 public void visit(Coupon c)
 {
     // nothing to do
 }
예제 #3
0
        public override void initialize(FloatingRateCoupon coupon)
        {
            coupon_ = coupon as CmsCoupon;
            Utils.QL_REQUIRE(coupon_ != null, () => "CMS coupon needed");
            gearing_ = coupon_.gearing();
            spread_  = coupon_.spread();

            fixingDate_  = coupon_.fixingDate();
            paymentDate_ = coupon_.date();
            swapIndex_   = coupon_.swapIndex();

            forwardCurve_ = swapIndex_.forwardingTermStructure();
            if (swapIndex_.exogenousDiscount())
            {
                discountCurve_ = swapIndex_.discountingTermStructure();
            }
            else
            {
                discountCurve_ = forwardCurve_;
            }

            // if no coupon discount curve is given just use the discounting curve
            // from the swap index. for rate calculation this curve cancels out in
            // the computation, so e.g. the discounting swap engine will produce
            // correct results, even if the couponDiscountCurve is not set here.
            // only the price member function in this class will be dependent on the
            // coupon discount curve.

            today_ = QLCore.Settings.Instance.evaluationDate();

            if (paymentDate_ > today_ && !couponDiscountCurve_.empty())
            {
                couponDiscountRatio_ = couponDiscountCurve_.link.discount(paymentDate_) /
                                       discountCurve_.link.discount(paymentDate_);
            }
            else
            {
                couponDiscountRatio_ = 1.0;
            }

            spreadLegValue_ = spread_ * coupon_.accrualPeriod() *
                              discountCurve_.link.discount(paymentDate_) *
                              couponDiscountRatio_;

            if (fixingDate_ > today_)
            {
                swapTenor_ = swapIndex_.tenor();
                swap_      = swapIndex_.underlyingSwap(fixingDate_);

                swapRateValue_ = swap_.fairRate();
                annuity_       = 1.0E4 * Math.Abs(swap_.fixedLegBPS());

                SmileSection sectionTmp = swaptionVolatility().link.smileSection(fixingDate_, swapTenor_);

                // adjust bounds by section's shift
                shiftedLowerBound_ = settings_.lowerRateBound_ - sectionTmp.shift();
                shiftedUpperBound_ = settings_.upperRateBound_ - sectionTmp.shift();

                // if the section does not provide an atm level, we enhance it to
                // have one, no need to exit with an exception ...

                if (sectionTmp.atmLevel() == null)
                {
                    smileSection_ = new AtmSmileSection(sectionTmp, swapRateValue_);
                }
                else
                {
                    smileSection_ = sectionTmp;
                }

                // compute linear model's parameters

                double gx = 0.0, gy = 0.0;
                for (int i = 0; i < swap_.fixedLeg().Count; i++)
                {
                    Coupon c  = swap_.fixedLeg()[i] as Coupon;
                    double yf = c.accrualPeriod();
                    Date   d  = c.date();
                    double pv = yf * discountCurve_.link.discount(d);
                    gx += pv * GsrG(d);
                    gy += pv;
                }

                double gamma = gx / gy;
                Date   lastd = swap_.fixedLeg().Last().date();

                a_ = discountCurve_.link.discount(paymentDate_) *
                     (gamma - GsrG(paymentDate_)) /
                     (discountCurve_.link.discount(lastd) * GsrG(lastd) +
                      swapRateValue_ * gy * gamma);

                b_ = discountCurve_.link.discount(paymentDate_) / gy -
                     a_ * swapRateValue_;
            }
        }