1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 3 /* 4 Copyright (C) 2006 Mark Joshi 5 6 This file is part of QuantLib, a free-software/open-source library 7 for financial quantitative analysts and developers - http://quantlib.org/ 8 9 QuantLib is free software: you can redistribute it and/or modify it 10 under the terms of the QuantLib license. You should have received a 11 copy of the license along with this program; if not, please email 12 <quantlib-dev@lists.sf.net>. The license is also available online at 13 <http://quantlib.org/license.shtml>. 14 15 This program is distributed in the hope that it will be useful, but WITHOUT 16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 FOR A PARTICULAR PURPOSE. See the license for more details. 18 */ 19 20 #include <ql/models/marketmodels/callability/collectnodedata.hpp> 21 #include <ql/models/marketmodels/discounter.hpp> 22 #include <ql/models/marketmodels/utilities.hpp> 23 #include <ql/models/marketmodels/multiproduct.hpp> 24 #include <ql/models/marketmodels/evolver.hpp> 25 #include <ql/models/marketmodels/callability/nodedataprovider.hpp> 26 #include <ql/models/marketmodels/callability/exercisevalue.hpp> 27 #include <ql/models/marketmodels/evolutiondescription.hpp> 28 #include <ql/models/marketmodels/curvestate.hpp> 29 #include <ql/methods/montecarlo/nodedata.hpp> 30 #include <ql/errors.hpp> 31 32 namespace QuantLib { 33 34 typedef MarketModelMultiProduct::CashFlow CashFlow; 35 collectNodeData(MarketModelEvolver & evolver,MarketModelMultiProduct & product,MarketModelNodeDataProvider & dataProvider,MarketModelExerciseValue & rebate,MarketModelExerciseValue & control,Size numberOfPaths,std::vector<std::vector<NodeData>> & collectedData)36 void collectNodeData(MarketModelEvolver& evolver, 37 MarketModelMultiProduct& product, 38 MarketModelNodeDataProvider& dataProvider, 39 MarketModelExerciseValue& rebate, 40 MarketModelExerciseValue& control, 41 Size numberOfPaths, 42 std::vector<std::vector<NodeData> >& collectedData) { 43 44 std::vector<Real> numerairesHeld; 45 46 QL_REQUIRE(product.numberOfProducts() == 1, 47 "a single product is required"); 48 49 // TODO: check that all objects have compatible evolutions 50 // (same rate times; evolution times for product, basis 51 // system, rebate and control must be subsets of the passed 52 // evolution times; rebate, control and basis system must have 53 // the same exercise---not evolution---times) 54 55 std::vector<Size> numberCashFlowsThisStep(1); 56 std::vector<std::vector<CashFlow> > cashFlowsGenerated(1); 57 cashFlowsGenerated[0].resize( 58 product.maxNumberOfCashFlowsPerProductPerStep()); 59 60 61 std::vector<Time> rateTimes = product.evolution().rateTimes(); 62 63 std::vector<Time> cashFlowTimes = product.possibleCashFlowTimes(); 64 std::vector<Time> rebateTimes = rebate.possibleCashFlowTimes(); 65 std::vector<Time> controlTimes = control.possibleCashFlowTimes(); 66 67 Size i, n; 68 69 n = cashFlowTimes.size(); 70 std::vector<MarketModelDiscounter> productDiscounters; 71 productDiscounters.reserve(n); 72 for (i=0; i<n; ++i) 73 productDiscounters.push_back( 74 MarketModelDiscounter(cashFlowTimes[i], 75 rateTimes)); 76 77 n = rebateTimes.size(); 78 std::vector<MarketModelDiscounter> rebateDiscounters; 79 rebateDiscounters.reserve(n); 80 for (i=0; i<n; ++i) 81 rebateDiscounters.push_back( 82 MarketModelDiscounter(rebateTimes[i], 83 rateTimes)); 84 n = controlTimes.size(); 85 std::vector<MarketModelDiscounter> controlDiscounters; 86 controlDiscounters.reserve(n); 87 for (i=0; i<n; ++i) 88 controlDiscounters.push_back( 89 MarketModelDiscounter(controlTimes[i], 90 rateTimes)); 91 92 EvolutionDescription evolution = product.evolution(); 93 const std::vector<Size>& numeraires = evolver.numeraires(); 94 95 const std::vector<Time>& evolutionTimes = evolution.evolutionTimes(); 96 97 std::valarray<bool> isProductTime = 98 isInSubset(evolutionTimes, 99 product.evolution().evolutionTimes()); 100 std::valarray<bool> isRebateTime = 101 isInSubset(evolutionTimes, 102 rebate.evolution().evolutionTimes()); 103 std::valarray<bool> isControlTime = 104 isInSubset(evolutionTimes, 105 control.evolution().evolutionTimes()); 106 std::valarray<bool> isBasisTime = 107 isInSubset(evolutionTimes, 108 dataProvider.evolution().evolutionTimes()); 109 std::valarray<bool> isExerciseTime(false,evolutionTimes.size()); 110 std::valarray<bool> v = rebate.isExerciseTime(); 111 Size exercises = 0, idx = 0; 112 for (i=0; i<evolutionTimes.size(); ++i) { 113 if (isRebateTime[i]) { 114 if(v[idx++]) { 115 isExerciseTime[i] = true; 116 exercises++; 117 } 118 } 119 } 120 121 collectedData.resize(exercises+1); 122 for (i=0; i<collectedData.size(); ++i) 123 collectedData[i].resize(numberOfPaths); 124 125 126 for (i=0; i<numberOfPaths; ++i) { 127 evolver.startNewPath(); 128 product.reset(); 129 rebate.reset(); 130 control.reset(); 131 dataProvider.reset(); 132 Real principalInNumerairePortfolio = 1.0; 133 134 bool done = false; 135 Size nextExercise = 0; 136 collectedData[0][i].cumulatedCashFlows = 0.0; 137 do { 138 Size currentStep = evolver.currentStep(); 139 evolver.advanceStep(); 140 const CurveState& currentState = evolver.currentState(); 141 Size numeraire = numeraires[currentStep]; 142 143 if (isRebateTime[currentStep]) 144 rebate.nextStep(currentState); 145 if (isControlTime[currentStep]) 146 control.nextStep(currentState); 147 if (isBasisTime[currentStep]) 148 dataProvider.nextStep(currentState); 149 150 if (isExerciseTime[currentStep]) { 151 NodeData& data = collectedData[nextExercise+1][i]; 152 153 CashFlow exerciseValue = rebate.value(currentState); 154 data.exerciseValue = 155 exerciseValue.amount * 156 rebateDiscounters[exerciseValue.timeIndex] 157 .numeraireBonds(currentState, numeraire) / 158 principalInNumerairePortfolio; 159 160 dataProvider.values(currentState, 161 data.values); 162 163 CashFlow controlValue = control.value(currentState); 164 data.controlValue = 165 controlValue.amount * 166 controlDiscounters[controlValue.timeIndex] 167 .numeraireBonds(currentState, numeraire) / 168 principalInNumerairePortfolio; 169 170 data.cumulatedCashFlows = 0.0; 171 172 data.isValid = true; 173 174 ++nextExercise; 175 } 176 177 if (isProductTime[currentStep]) { 178 done = product.nextTimeStep(currentState, 179 numberCashFlowsThisStep, 180 cashFlowsGenerated); 181 182 for (Size j=0; j<numberCashFlowsThisStep[0]; ++j) { 183 const CashFlow& cf = cashFlowsGenerated[0][j]; 184 collectedData[nextExercise][i].cumulatedCashFlows += 185 cf.amount * 186 productDiscounters[cf.timeIndex] 187 .numeraireBonds(currentState, numeraire) / 188 principalInNumerairePortfolio; 189 } 190 } 191 192 if (!done) { 193 Size nextNumeraire = numeraires[currentStep+1]; 194 principalInNumerairePortfolio *= 195 currentState.discountRatio(numeraire, 196 nextNumeraire); 197 } 198 } 199 while (!done); 200 201 // fill the remaining (un)collected data with nulls 202 for (Size j = nextExercise; j < exercises; ++j) { 203 NodeData& data = collectedData[j+1][i]; 204 data.exerciseValue = data.controlValue = 0.0; 205 data.cumulatedCashFlows = 0.0; 206 data.isValid = false; 207 } 208 } 209 } 210 211 } 212