| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2006, 2011 Ferdinando Ametrano |
| 5 | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl |
| 6 | Copyright (C) 2003, 2004, 2005, 2007, 2008 StatPro Italia srl |
| 7 | |
| 8 | This file is part of QuantLib, a free-software/open-source library |
| 9 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 10 | |
| 11 | QuantLib is free software: you can redistribute it and/or modify it |
| 12 | under the terms of the QuantLib license. You should have received a |
| 13 | copy of the license along with this program; if not, please email |
| 14 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 15 | <http://quantlib.org/license.shtml>. |
| 16 | |
| 17 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 18 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 19 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 20 | */ |
| 21 | |
| 22 | #include <ql/instruments/swap.hpp> |
| 23 | #include <ql/cashflows/cashflows.hpp> |
| 24 | #include <ql/cashflows/floatingratecoupon.hpp> |
| 25 | #include <ql/termstructures/yieldtermstructure.hpp> |
| 26 | #include <ostream> |
| 27 | |
| 28 | namespace QuantLib { |
| 29 | |
| 30 | Swap::Swap(const Leg& firstLeg, |
| 31 | const Leg& secondLeg) |
| 32 | : legs_(2), payer_(2), |
| 33 | legNPV_(2, 0.0), legBPS_(2, 0.0), |
| 34 | startDiscounts_(2, 0.0), endDiscounts_(2, 0.0), |
| 35 | npvDateDiscount_(0.0) { |
| 36 | legs_[0] = firstLeg; |
| 37 | legs_[1] = secondLeg; |
| 38 | payer_[0] = -1.0; |
| 39 | payer_[1] = 1.0; |
| 40 | for (auto& i : legs_[0]) |
| 41 | registerWith(h: i); |
| 42 | for (auto& i : legs_[1]) |
| 43 | registerWith(h: i); |
| 44 | } |
| 45 | |
| 46 | Swap::Swap(const std::vector<Leg>& legs, |
| 47 | const std::vector<bool>& payer) |
| 48 | : legs_(legs), payer_(legs.size(), 1.0), |
| 49 | legNPV_(legs.size(), 0.0), legBPS_(legs.size(), 0.0), |
| 50 | startDiscounts_(legs.size(), 0.0), endDiscounts_(legs.size(), 0.0), |
| 51 | npvDateDiscount_(0.0) { |
| 52 | QL_REQUIRE(payer.size()==legs_.size(), |
| 53 | "size mismatch between payer (" << payer.size() << |
| 54 | ") and legs (" << legs_.size() << ")" ); |
| 55 | for (Size j=0; j<legs_.size(); ++j) { |
| 56 | if (payer[j]) payer_[j]=-1.0; |
| 57 | for (auto& i : legs_[j]) |
| 58 | registerWith(h: i); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | Swap::Swap(Size legs) |
| 63 | : legs_(legs), payer_(legs), |
| 64 | legNPV_(legs, 0.0), legBPS_(legs, 0.0), |
| 65 | startDiscounts_(legs, 0.0), endDiscounts_(legs, 0.0), |
| 66 | npvDateDiscount_(0.0) {} |
| 67 | |
| 68 | bool Swap::isExpired() const { |
| 69 | for (const auto& leg : legs_) { |
| 70 | Leg::const_iterator i; |
| 71 | for (i = leg.begin(); i != leg.end(); ++i) |
| 72 | if (!(*i)->hasOccurred()) |
| 73 | return false; |
| 74 | } |
| 75 | return true; |
| 76 | } |
| 77 | |
| 78 | void Swap::setupExpired() const { |
| 79 | Instrument::setupExpired(); |
| 80 | std::fill(first: legBPS_.begin(), last: legBPS_.end(), value: 0.0); |
| 81 | std::fill(first: legNPV_.begin(), last: legNPV_.end(), value: 0.0); |
| 82 | std::fill(first: startDiscounts_.begin(), last: startDiscounts_.end(), value: 0.0); |
| 83 | std::fill(first: endDiscounts_.begin(), last: endDiscounts_.end(), value: 0.0); |
| 84 | npvDateDiscount_ = 0.0; |
| 85 | } |
| 86 | |
| 87 | void Swap::setupArguments(PricingEngine::arguments* args) const { |
| 88 | auto* arguments = dynamic_cast<Swap::arguments*>(args); |
| 89 | QL_REQUIRE(arguments != nullptr, "wrong argument type" ); |
| 90 | |
| 91 | arguments->legs = legs_; |
| 92 | arguments->payer = payer_; |
| 93 | } |
| 94 | |
| 95 | void Swap::fetchResults(const PricingEngine::results* r) const { |
| 96 | Instrument::fetchResults(r); |
| 97 | |
| 98 | const auto* results = dynamic_cast<const Swap::results*>(r); |
| 99 | QL_REQUIRE(results != nullptr, "wrong result type" ); |
| 100 | |
| 101 | if (!results->legNPV.empty()) { |
| 102 | QL_REQUIRE(results->legNPV.size() == legNPV_.size(), |
| 103 | "wrong number of leg NPV returned" ); |
| 104 | legNPV_ = results->legNPV; |
| 105 | } else { |
| 106 | std::fill(first: legNPV_.begin(), last: legNPV_.end(), value: Null<Real>()); |
| 107 | } |
| 108 | |
| 109 | if (!results->legBPS.empty()) { |
| 110 | QL_REQUIRE(results->legBPS.size() == legBPS_.size(), |
| 111 | "wrong number of leg BPS returned" ); |
| 112 | legBPS_ = results->legBPS; |
| 113 | } else { |
| 114 | std::fill(first: legBPS_.begin(), last: legBPS_.end(), value: Null<Real>()); |
| 115 | } |
| 116 | |
| 117 | if (!results->startDiscounts.empty()) { |
| 118 | QL_REQUIRE(results->startDiscounts.size() == startDiscounts_.size(), |
| 119 | "wrong number of leg start discounts returned" ); |
| 120 | startDiscounts_ = results->startDiscounts; |
| 121 | } else { |
| 122 | std::fill(first: startDiscounts_.begin(), last: startDiscounts_.end(), |
| 123 | value: Null<DiscountFactor>()); |
| 124 | } |
| 125 | |
| 126 | if (!results->endDiscounts.empty()) { |
| 127 | QL_REQUIRE(results->endDiscounts.size() == endDiscounts_.size(), |
| 128 | "wrong number of leg end discounts returned" ); |
| 129 | endDiscounts_ = results->endDiscounts; |
| 130 | } else { |
| 131 | std::fill(first: endDiscounts_.begin(), last: endDiscounts_.end(), |
| 132 | value: Null<DiscountFactor>()); |
| 133 | } |
| 134 | |
| 135 | if (results->npvDateDiscount != Null<DiscountFactor>()) { |
| 136 | npvDateDiscount_ = results->npvDateDiscount; |
| 137 | } else { |
| 138 | npvDateDiscount_ = Null<DiscountFactor>(); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | Size Swap::numberOfLegs() const { return legs_.size(); } |
| 143 | |
| 144 | const std::vector<Leg>& Swap::legs() const { return legs_; } |
| 145 | |
| 146 | Date Swap::startDate() const { |
| 147 | QL_REQUIRE(!legs_.empty(), "no legs given" ); |
| 148 | Date d = CashFlows::startDate(leg: legs_[0]); |
| 149 | for (Size j=1; j<legs_.size(); ++j) |
| 150 | d = std::min(a: d, b: CashFlows::startDate(leg: legs_[j])); |
| 151 | return d; |
| 152 | } |
| 153 | |
| 154 | Date Swap::maturityDate() const { |
| 155 | QL_REQUIRE(!legs_.empty(), "no legs given" ); |
| 156 | Date d = CashFlows::maturityDate(leg: legs_[0]); |
| 157 | for (Size j=1; j<legs_.size(); ++j) |
| 158 | d = std::max(a: d, b: CashFlows::maturityDate(leg: legs_[j])); |
| 159 | return d; |
| 160 | } |
| 161 | |
| 162 | void Swap::deepUpdate() { |
| 163 | for (auto& leg : legs_) { |
| 164 | for (auto& k : leg) { |
| 165 | k->deepUpdate(); |
| 166 | } |
| 167 | } |
| 168 | update(); |
| 169 | } |
| 170 | |
| 171 | void Swap::arguments::validate() const { |
| 172 | QL_REQUIRE(legs.size() == payer.size(), |
| 173 | "number of legs and multipliers differ" ); |
| 174 | } |
| 175 | |
| 176 | void Swap::results::reset() { |
| 177 | Instrument::results::reset(); |
| 178 | legNPV.clear(); |
| 179 | legBPS.clear(); |
| 180 | startDiscounts.clear(); |
| 181 | endDiscounts.clear(); |
| 182 | npvDateDiscount = Null<DiscountFactor>(); |
| 183 | } |
| 184 | |
| 185 | std::ostream& operator<<(std::ostream& out, Swap::Type t) { |
| 186 | switch (t) { |
| 187 | case Swap::Payer: |
| 188 | return out << "Payer" ; |
| 189 | case Swap::Receiver: |
| 190 | return out << "Receiver" ; |
| 191 | default: |
| 192 | QL_FAIL("unknown Swap::Type(" << Integer(t) << ")" ); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | } |
| 197 | |