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