/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2007 Ferdinando Ametrano Copyright (C) 2006, 2007 Cristina Duminuco Copyright (C) 2006, 2007 Giorgio Facchinetti Copyright (C) 2006 Mario Pucci Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl Copyright (C) 2003, 2004, 2005 StatPro Italia srl This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ #include #include #include #include namespace QuantLib { namespace { Real get(const std::vector& v, Size i, Real defaultValue) { if (v.empty()) { return defaultValue; } else if (i < v.size()) { return v[i]; } else { return v.back(); } } Rate effectiveFixedRate(const std::vector& spreads, const std::vector& caps, const std::vector& floors, Size i) { Rate result = get(spreads, i, 0.0); Rate floor = get(floors, i, Null()); if (floor!=Null()) result = std::max(floor, result); Rate cap = get(caps, i, Null()); if (cap!=Null()) result = std::min(cap, result); return result; } bool noOption(const std::vector& caps, const std::vector& floors, Size i) { return (get(caps, i, Null()) == Null()) && (get(floors, i, Null()) == Null()); } } Leg FixedRateLeg(const std::vector& nominals, const Schedule& schedule, const std::vector& couponRates, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, const DayCounter& firstPeriodDayCount) { QL_REQUIRE(!couponRates.empty(), "coupon rates not specified"); QL_REQUIRE(!nominals.empty(), "nominals not specified"); Leg leg; // the following is not always correct Calendar calendar = schedule.calendar(); // first period might be short or long Date start = schedule.date(0), end = schedule.date(1); Date paymentDate = calendar.adjust(end, paymentAdj); Rate rate = couponRates[0]; Real nominal = nominals[0]; if (schedule.isRegular(1)) { QL_REQUIRE(firstPeriodDayCount.empty() || firstPeriodDayCount == paymentDayCounter, "regular first coupon " "does not allow a first-period day count"); leg.push_back(boost::shared_ptr(new FixedRateCoupon(nominal, paymentDate, rate, paymentDayCounter, start, end, start, end))); } else { Date ref = end - schedule.tenor(); ref = calendar.adjust(ref, schedule.businessDayConvention()); DayCounter dc = firstPeriodDayCount.empty() ? paymentDayCounter : firstPeriodDayCount; leg.push_back(boost::shared_ptr(new FixedRateCoupon(nominal, paymentDate, rate, dc, start, end, ref, end))); } // regular periods for (Size i=2; i(new FixedRateCoupon(nominal, paymentDate, rate, paymentDayCounter, start, end, start, end))); } if (schedule.size() > 2) { // last period might be short or long Size N = schedule.size(); start = end; end = schedule.date(N-1); paymentDate = calendar.adjust(end,paymentAdj); if ((N-2) < couponRates.size()) rate = couponRates[N-2]; else rate = couponRates.back(); if ((N-2) < nominals.size()) nominal = nominals[N-2]; else nominal = nominals.back(); if (schedule.isRegular(N-1)) { leg.push_back(boost::shared_ptr(new FixedRateCoupon(nominal, paymentDate, rate, paymentDayCounter, start, end, start, end))); } else { Date ref = start + schedule.tenor(); ref = calendar.adjust(ref, schedule.businessDayConvention()); leg.push_back(boost::shared_ptr(new FixedRateCoupon(nominal, paymentDate, rate, paymentDayCounter, start, end, start, ref))); } } return leg; } template Leg FloatingLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors, bool isInArrears) { QL_REQUIRE(!nominals.empty(), "no nominal given"); Size n = schedule.size()-1; QL_REQUIRE(nominals.size() <= n, "too many nominals (" << nominals.size() << "), only " << n << " required"); QL_REQUIRE(gearings.size()<=n, "too many gearings (" << gearings.size() << "), only " << n << " required"); QL_REQUIRE(spreads.size()<=n, "too many spreads (" << spreads.size() << "), only " << n << " required"); QL_REQUIRE(caps.size()<=n, "too many caps (" << caps.size() << "), only " << n << " required"); QL_REQUIRE(floors.size()<=n, "too many floors (" << floors.size() << "), only " << n << " required"); Leg leg; leg.reserve(n); // the following is not always correct Calendar calendar = schedule.calendar(); Date refStart, start, refEnd, end; Date paymentDate; for (Size i=0; i(new FixedRateCoupon(get(nominals, i, Null()), paymentDate, effectiveFixedRate(spreads, caps, floors, i), paymentDayCounter, start, end, refStart, refEnd))); } else { // floating coupon if (noOption(caps, floors, i)) leg.push_back(boost::shared_ptr(new FloatingCouponType(paymentDate, get(nominals, i, Null()), start, end, fixingDays, index, get(gearings, i, 1.0), get(spreads, i, 0.0), refStart, refEnd, paymentDayCounter, isInArrears))); else { leg.push_back(boost::shared_ptr(new CappedFlooredCouponType(paymentDate, get(nominals, i, Null()), start, end, fixingDays, index, get(gearings, i, 1.0), get(spreads, i, 0.0), get(caps, i, Null()), get(floors, i, Null()), refStart, refEnd, paymentDayCounter, isInArrears))); } } } return leg; } Leg IborLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors, bool isInArrears) { return FloatingLeg( nominals, schedule, index, paymentDayCounter, paymentAdj, fixingDays, gearings, spreads, caps, floors, isInArrears); } Leg CmsLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors, bool isInArrears) { return FloatingLeg( nominals, schedule, index, paymentDayCounter, paymentAdj, fixingDays, gearings, spreads, caps, floors, isInArrears); } template Leg FloatingZeroLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors) { QL_REQUIRE(!nominals.empty(), "no nominal given"); Size n = schedule.size()-1; QL_REQUIRE(nominals.size() <= n, "too many nominals (" << nominals.size() << "), only " << n << " required"); QL_REQUIRE(gearings.size()<=n, "too many gearings (" << gearings.size() << "), only " << n << " required"); QL_REQUIRE(spreads.size()<=n, "too many spreads (" << spreads.size() << "), only " << n << " required"); QL_REQUIRE(caps.size()<=n, "too many caps (" << caps.size() << "), only " << n << " required"); QL_REQUIRE(floors.size()<=n, "too many floors (" << floors.size() << "), only " << n << " required"); Leg leg; leg.reserve(n); // the following is not always correct Calendar calendar = schedule.calendar(); Date refStart, start, refEnd, end; // All payment dates at the end!! in arrears fixing makes no sense Date paymentDate = calendar.adjust(schedule.date(n), paymentAdj); bool isInArrears = false; for (Size i=0; i(new FixedRateCoupon(get(nominals, i, Null()), paymentDate, effectiveFixedRate(spreads, caps, floors, i), paymentDayCounter, start, end, refStart, refEnd))); } else { // floating coupon if (noOption(caps, floors, i)) { leg.push_back(boost::shared_ptr(new FloatingCouponType(paymentDate, // diff get(nominals, i, Null()), start, end, fixingDays, index, get(gearings, i, 1.0), get(spreads, i, 0.0), refStart, refEnd, paymentDayCounter, isInArrears))); } else { leg.push_back(boost::shared_ptr(new CappedFlooredFloatingCouponType(paymentDate, // diff get(nominals, i, Null()), start, end, fixingDays, index, get(gearings, i, 1.0), get(spreads, i, 0.0), get(caps, i, Null()), get(floors, i, Null()), refStart, refEnd, paymentDayCounter, isInArrears))); } } } return leg; } Leg IborZeroLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors) { return FloatingZeroLeg ( nominals, schedule, index, paymentDayCounter, paymentAdj, fixingDays, gearings, spreads, caps, floors); } Leg CmsZeroLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentAdj, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& caps, const std::vector& floors) { return FloatingZeroLeg ( nominals, schedule, index, paymentDayCounter, paymentAdj, fixingDays, gearings, spreads, caps, floors); } Leg RangeAccrualLeg(const std::vector& nominals, const Schedule& schedule, const boost::shared_ptr& index, const DayCounter& paymentDayCounter, BusinessDayConvention paymentConvention, Natural fixingDays, const std::vector& gearings, const std::vector& spreads, const std::vector& lowerTriggers, const std::vector& upperTriggers, const Period& observationTenor, BusinessDayConvention observationConvention) { QL_REQUIRE(!nominals.empty(), "no nominal given"); Size n = schedule.size()-1; QL_REQUIRE(nominals.size() <= n, "too many nominals (" << nominals.size() << "), only " << n << " required"); QL_REQUIRE(gearings.size()<=n, "too many gearings (" << gearings.size() << "), only " << n << " required"); QL_REQUIRE(spreads.size()<=n, "too many spreads (" << spreads.size() << "), only " << n << " required"); QL_REQUIRE(lowerTriggers.size()<=n, "too many lowerTriggers (" << lowerTriggers.size() << "), only " << n << " required"); QL_REQUIRE(upperTriggers.size()<=n, "too many upperTriggers (" << upperTriggers.size() << "), only " << n << " required"); Leg leg; leg.reserve(n); // the following is not always correct Calendar calendar = schedule.calendar(); Date refStart, start, refEnd, end; Date paymentDate; std::vector > observationsSchedules; for (Size i=0; i(new FixedRateCoupon(get(nominals, i, Null()), paymentDate, get(spreads, i, 0.0), paymentDayCounter, start, end, refStart, refEnd))); } else { // floating coupon observationsSchedules.push_back( boost::shared_ptr( new Schedule(start, end, observationTenor, calendar, observationConvention, observationConvention, false, false))); leg.push_back(boost::shared_ptr(new RangeAccrualFloatersCoupon( get(nominals, i, Null()), paymentDate, index, start, end, fixingDays, paymentDayCounter, get(gearings, i, 1.0), get(spreads, i, 0.0), refStart, refEnd, observationsSchedules.back(), get(lowerTriggers, i, Null()), get(upperTriggers, i, Null())))); } } return leg; } }