Пример #1
0
        public static double zSpread(Bond bond, double cleanPrice, YieldTermStructure discount, DayCounter dayCounter, Compounding compounding,
                                     Frequency frequency, Date settlementDate = null, double accuracy = 1.0e-10, int maxIterations = 100,
                                     double guess = 0.0)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")",
                             QLNetExceptionEnum.NotTradableException);

            double dirtyPrice = cleanPrice + bond.accruedAmount(settlementDate);

            dirtyPrice /= 100.0 / bond.notional(settlementDate);

            return(CashFlows.zSpread(bond.cashflows(),
                                     discount,
                                     dirtyPrice,
                                     dayCounter, compounding, frequency,
                                     false, settlementDate, settlementDate,
                                     accuracy, maxIterations, guess));
        }
Пример #2
0
        protected override void performCalculations()
        {
            Utils.QL_REQUIRE(!bondHelpers_.empty(), () => "no bondHelpers given");

            maxDate_ = Date.minDate();
            Date refDate = referenceDate();

            // double check bond quotes still valid and/or instruments not expired
            for (int i = 0; i < bondHelpers_.Count; ++i)
            {
                Bond bond = bondHelpers_[i].bond();
                Utils.QL_REQUIRE(bondHelpers_[i].quote().link.isValid(), () =>
                                 (i + 1) + " bond (maturity: " +
                                 bond.maturityDate() + ") has an invalid price quote");
                Date bondSettlement = bond.settlementDate();
                Utils.QL_REQUIRE(bondSettlement >= refDate, () =>
                                 (i + 1) + " bond settlemente date (" +
                                 bondSettlement + ") before curve reference date (" +
                                 refDate + ")");
                Utils.QL_REQUIRE(BondFunctions.isTradable(bond, bondSettlement), () =>
                                 (i + 1) + " bond non tradable at " +
                                 bondSettlement + " settlement date (maturity" +
                                 " being " + bond.maturityDate() + ")",
                                 QLNetExceptionEnum.NotTradableException);
                maxDate_ = Date.Max(maxDate_, bondHelpers_[i].pillarDate());
                bondHelpers_[i].setTermStructure(this);
            }
            fittingMethod_.init();
            fittingMethod_.calculate();
        }
Пример #3
0
        public static double nextCouponRate(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            return(CashFlows.nextCouponRate(bond.cashflows(), false, settlementDate));
        }
Пример #4
0
        public static bool isTradable(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            return(bond.notional(settlementDate).IsNotEqual(0.0));
        }
Пример #5
0
        public static CashFlow previousCashFlow(Bond bond, Date refDate = null)
        {
            if (refDate == null)
            {
                refDate = bond.settlementDate();
            }

            return(CashFlows.previousCashFlow(bond.cashflows(), false, refDate));
        }
Пример #6
0
        public static Date nextCashFlowDate(Bond bond, Date refDate = null)
        {
            if (refDate == null)
            {
                refDate = bond.settlementDate();
            }

            return(CashFlows.nextCashFlowDate(bond.cashflows(), false, refDate));
        }
Пример #7
0
            //! rerun every time instruments/referenceDate changes
            internal virtual void init()
            {
                // yield conventions
                DayCounter  yieldDC   = curve_.dayCounter();
                Compounding yieldComp = Compounding.Compounded;
                Frequency   yieldFreq = Frequency.Annual;

                int n = curve_.bondHelpers_.Count;

                costFunction_ = new FittingCost(this);
                costFunction_.firstCashFlow_ = new InitializedList <int>(n);

                for (int i = 0; i < curve_.bondHelpers_.Count; ++i)
                {
                    Bond            bond           = curve_.bondHelpers_[i].bond();
                    List <CashFlow> cf             = bond.cashflows();
                    Date            bondSettlement = bond.settlementDate();
                    for (int k = 0; k < cf.Count; ++k)
                    {
                        if (!cf[k].hasOccurred(bondSettlement, false))
                        {
                            costFunction_.firstCashFlow_[i] = k;
                            break;
                        }
                    }
                }

                if (calculateWeights_)
                {
                    //if (weights_.empty())
                    weights_ = new Vector(n);

                    double squaredSum = 0.0;
                    for (int i = 0; i < curve_.bondHelpers_.Count; ++i)
                    {
                        Bond bond = curve_.bondHelpers_[i].bond();

                        double cleanPrice = curve_.bondHelpers_[i].quote().link.value();

                        Date   bondSettlement = bond.settlementDate();
                        double ytm            = BondFunctions.yield(bond, cleanPrice, yieldDC, yieldComp, yieldFreq, bondSettlement);

                        double dur = BondFunctions.duration(bond, ytm, yieldDC, yieldComp, yieldFreq,
                                                            Duration.Type.Modified, bondSettlement);
                        weights_[i] = 1.0 / dur;
                        squaredSum += weights_[i] * weights_[i];
                    }
                    weights_ /= Math.Sqrt(squaredSum);
                }

                Utils.QL_REQUIRE(weights_.size() == n, () =>
                                 "Given weights do not cover all boostrapping helpers");
            }
Пример #8
0
        public static Date referencePeriodEnd(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.referencePeriodEnd(bond.cashflows(), false, settlementDate));
        }
Пример #9
0
        public static int accrualDays(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate),
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.accrualDays(bond.cashflows(), false, settlementDate));
        }
Пример #10
0
        public static double convexity(Bond bond, InterestRate yield, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.convexity(bond.cashflows(), yield, false, settlementDate));
        }
Пример #11
0
        public static double accruedAmount(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.accruedAmount(bond.cashflows(), false, settlementDate) * 100.0 / bond.notional(settlementDate));
        }
Пример #12
0
        public static double bps(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.bps(bond.cashflows(), discountCurve, false, settlementDate) * 100.0 / bond.notional(settlementDate));
        }
Пример #13
0
        public static double accruedDays(Bond bond, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")",
                             QLNetExceptionEnum.NotTradableException);

            return(CashFlows.accruedDays(bond.cashflows(), false, settlementDate));
        }
Пример #14
0
        public static double duration(Bond bond, InterestRate yield, Duration.Type type = Duration.Type.Modified,
                                      Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate),
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            return(CashFlows.duration(bond.cashflows(), yield, type, false, settlementDate));
        }
Пример #15
0
        public static double yieldValueBasisPoint(Bond bond, InterestRate yield, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")",
                             QLNetExceptionEnum.NotTradableException);

            return(CashFlows.yieldValueBasisPoint(bond.cashflows(), yield,
                                                  false, settlementDate));
        }
Пример #16
0
        public static double dirtyPrice(Bond bond, InterestRate yield, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            double dirtyPrice = CashFlows.npv(bond.cashflows(), yield, false, settlementDate) *
                                100.0 / bond.notional(settlementDate);

            return(dirtyPrice);
        }
Пример #17
0
        public static double cleanPrice(Bond bond, YieldTermStructure discount, double zSpread, DayCounter dayCounter, Compounding compounding,
                                        Frequency frequency, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            double dirtyPrice = CashFlows.npv(bond.cashflows(), discount, zSpread, dayCounter, compounding, frequency, false, settlementDate) *
                                100.0 / bond.notional(settlementDate);

            return(dirtyPrice - bond.accruedAmount(settlementDate));
        }
Пример #18
0
        public static double atmRate(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null, double?cleanPrice = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " (maturity being " + bond.maturityDate() + ")");

            double?dirtyPrice      = cleanPrice == null ? null : cleanPrice + bond.accruedAmount(settlementDate);
            double currentNotional = bond.notional(settlementDate);
            double?npv             = dirtyPrice / 100.0 * currentNotional;

            return(CashFlows.atmRate(bond.cashflows(), discountCurve, false, settlementDate, settlementDate, npv));
        }
Пример #19
0
        public static double cleanPrice(Bond bond, YieldTermStructure discountCurve, Date settlementDate = null)
        {
            if (settlementDate == null)
            {
                settlementDate = bond.settlementDate();
            }

            Utils.QL_REQUIRE(BondFunctions.isTradable(bond, settlementDate), () =>
                             "non tradable at " + settlementDate +
                             " settlementDate date (maturity being " +
                             bond.maturityDate() + ")");

            double dirtyPrice = CashFlows.npv(bond.cashflows(), discountCurve, false, settlementDate) *
                                100.0 / bond.notional(settlementDate);

            return(dirtyPrice - bond.accruedAmount(settlementDate));
        }
Пример #20
0
                public override Vector values(Vector x)
                {
                    Date       refDate = fittingMethod_.curve_.referenceDate();
                    DayCounter dc      = fittingMethod_.curve_.dayCounter();
                    int        n       = fittingMethod_.curve_.bondHelpers_.Count;
                    Vector     values  = new Vector(n);

                    for (int i = 0; i < n; ++i)
                    {
                        BondHelper helper = fittingMethod_.curve_.bondHelpers_[i];

                        Bond bond           = helper.bond();
                        Date bondSettlement = bond.settlementDate();

                        // CleanPrice_i = sum( cf_k * d(t_k) ) - accruedAmount
                        double          modelPrice = 0.0;
                        List <CashFlow> cf         = bond.cashflows();
                        for (int k = firstCashFlow_[i]; k < cf.Count; ++k)
                        {
                            double tenor = dc.yearFraction(refDate, cf[k].date());
                            modelPrice += cf[k].amount() * fittingMethod_.discountFunction(x, tenor);
                        }
                        if (helper.useCleanPrice())
                        {
                            modelPrice -= bond.accruedAmount(bondSettlement);
                        }

                        // adjust price (NPV) for forward settlement
                        if (bondSettlement != refDate)
                        {
                            double tenor = dc.yearFraction(refDate, bondSettlement);
                            modelPrice /= fittingMethod_.discountFunction(x, tenor);
                        }
                        double marketPrice   = helper.quote().link.value();
                        double error         = modelPrice - marketPrice;
                        double weightedError = fittingMethod_.weights_[i] * error;
                        values[i] = weightedError * weightedError;
                    }
                    return(values);
                }
Пример #21
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;
            }
        }
Пример #22
0
        public AssetSwap(bool payBondCoupon,
                         Bond bond,
                         double bondCleanPrice,
                         IborIndex iborIndex,
                         double spread,
                         Schedule floatSchedule      = null,
                         DayCounter floatingDayCount = null,
                         bool parAssetSwap           = true)
            : base(2)
        {
            bond_            = bond;
            bondCleanPrice_  = bondCleanPrice;
            nonParRepayment_ = 100;
            spread_          = spread;
            parSwap_         = parAssetSwap;

            Schedule schedule = floatSchedule;

            if (floatSchedule == null)
            {
                schedule = new Schedule(bond_.settlementDate(),
                                        bond_.maturityDate(),
                                        iborIndex.tenor(),
                                        iborIndex.fixingCalendar(),
                                        iborIndex.businessDayConvention(),
                                        iborIndex.businessDayConvention(),
                                        DateGeneration.Rule.Backward,
                                        false); // endOfMonth
            }
            // the following might become an input parameter
            BusinessDayConvention paymentAdjustment = BusinessDayConvention.Following;

            Date finalDate           = schedule.calendar().adjust(schedule.endDate(), paymentAdjustment);
            Date adjBondMaturityDate = schedule.calendar().adjust(bond_.maturityDate(), paymentAdjustment);

            Utils.QL_REQUIRE(finalDate == adjBondMaturityDate, () =>
                             "adjusted schedule end date (" +
                             finalDate +
                             ") must be equal to adjusted bond maturity date (" +
                             adjBondMaturityDate + ")");

            // 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)
                           .withNotionals(notional)
                           .withPaymentAdjustment(paymentAdjustment);
            }
            else
            {
                legs_[1] = new IborLeg(schedule, iborIndex)
                           .withSpreads(spread)
                           .withPaymentDayCounter(floatingDayCount)
                           .withNotionals(notional)
                           .withPaymentAdjustment(paymentAdjustment);
            }

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

            List <CashFlow> bondLeg = bond_.cashflows();

            foreach (CashFlow c in bondLeg)
            {
                // whatever might be the choice for the discounting engine
                // bond flows on upfrontDate_ must be discarded
                bool upfrontDateBondFlows = false;
                if (!(c.hasOccurred(upfrontDate_, upfrontDateBondFlows)))
                {
                    legs_[0].Add(c);
                }
            }

            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;
            }
        }