1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2006 Ferdinando Ametrano
5  Copyright (C) 2006 Mark Joshi
6 
7  This file is part of QuantLib, a free-software/open-source library
8  for financial quantitative analysts and developers - http://quantlib.org/
9 
10  QuantLib is free software: you can redistribute it and/or modify it
11  under the terms of the QuantLib license.  You should have received a
12  copy of the license along with this program; if not, please email
13  <quantlib-dev@lists.sf.net>. The license is also available online at
14  <http://quantlib.org/license.shtml>.
15 
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the license for more details.
19 */
20 
21 #include <ql/models/marketmodels/evolvers/lognormalfwdrateeuler.hpp>
22 #include <ql/models/marketmodels/marketmodel.hpp>
23 #include <ql/models/marketmodels/evolutiondescription.hpp>
24 #include <ql/models/marketmodels/browniangenerator.hpp>
25 #include <ql/models/marketmodels/driftcomputation/lmmdriftcalculator.hpp>
26 
27 namespace QuantLib {
28 
LogNormalFwdRateEuler(const ext::shared_ptr<MarketModel> & marketModel,const BrownianGeneratorFactory & factory,const std::vector<Size> & numeraires,Size initialStep)29     LogNormalFwdRateEuler::LogNormalFwdRateEuler(
30                            const ext::shared_ptr<MarketModel>& marketModel,
31                            const BrownianGeneratorFactory& factory,
32                            const std::vector<Size>& numeraires,
33                            Size initialStep)
34     : marketModel_(marketModel),
35       numeraires_(numeraires),
36       initialStep_(initialStep),
37       numberOfRates_(marketModel->numberOfRates()),
38       numberOfFactors_(marketModel_->numberOfFactors()),
39       curveState_(marketModel->evolution().rateTimes()),
40       forwards_(marketModel->initialRates()),
41       displacements_(marketModel->displacements()),
42       logForwards_(numberOfRates_), initialLogForwards_(numberOfRates_),
43       drifts1_(numberOfRates_), initialDrifts_(numberOfRates_),
44       brownians_(numberOfFactors_), correlatedBrownians_(numberOfRates_),
45       alive_(marketModel->evolution().firstAliveRate())
46     {
47         checkCompatibility(marketModel->evolution(), numeraires);
48 
49         Size steps = marketModel->evolution().numberOfSteps();
50 
51         generator_ = factory.create(numberOfFactors_, steps-initialStep_);
52 
53         currentStep_ = initialStep_;
54 
55         calculators_.reserve(steps);
56         fixedDrifts_.reserve(steps);
57         for (Size j=0; j<steps; ++j) {
58             const Matrix& A = marketModel_->pseudoRoot(j);
59             calculators_.push_back(LMMDriftCalculator(A,
60                                                    displacements_,
61                                                    marketModel->evolution().rateTaus(),
62                                                    numeraires[j],
63                                                    alive_[j]));
64             std::vector<Real> fixed(numberOfRates_);
65             for (Size k=0; k<numberOfRates_; ++k) {
66                 Real variance =
67                     std::inner_product(A.row_begin(k), A.row_end(k),
68                                        A.row_begin(k), 0.0);
69                 fixed[k] = -0.5*variance;
70             }
71             fixedDrifts_.push_back(fixed);
72         }
73 
74         setForwards(marketModel_->initialRates());
75     }
76 
numeraires() const77     const std::vector<Size>& LogNormalFwdRateEuler::numeraires() const {
78         return numeraires_;
79     }
80 
setForwards(const std::vector<Real> & forwards)81     void LogNormalFwdRateEuler::setForwards(const std::vector<Real>& forwards)
82     {
83         QL_REQUIRE(forwards.size()==numberOfRates_,
84                    "mismatch between forwards and rateTimes");
85         for (Size i=0; i<numberOfRates_; ++i)
86             initialLogForwards_[i] = std::log(forwards[i] +
87                                               displacements_[i]);
88         calculators_[initialStep_].compute(forwards, initialDrifts_);
89     }
90 
setInitialState(const CurveState & cs)91     void LogNormalFwdRateEuler::setInitialState(const CurveState& cs) {
92         setForwards(cs.forwardRates());
93     }
94 
startNewPath()95     Real LogNormalFwdRateEuler::startNewPath() {
96         currentStep_ = initialStep_;
97         std::copy(initialLogForwards_.begin(), initialLogForwards_.end(),
98                   logForwards_.begin());
99         return generator_->nextPath();
100     }
101 
advanceStep()102     Real LogNormalFwdRateEuler::advanceStep()
103     {
104         // we're going from T1 to T2
105 
106         // a) compute drifts D1 at T1;
107         if (currentStep_ > initialStep_) {
108             calculators_[currentStep_].compute(forwards_, drifts1_);
109         } else {
110             std::copy(initialDrifts_.begin(), initialDrifts_.end(),
111                       drifts1_.begin());
112         }
113 
114         // b) evolve forwards up to T2 using D1;
115         Real weight = generator_->nextStep(brownians_);
116         const Matrix& A = marketModel_->pseudoRoot(currentStep_);
117         const std::vector<Real>& fixedDrift = fixedDrifts_[currentStep_];
118 
119         Size alive = alive_[currentStep_];
120         for (Size i=alive; i<numberOfRates_; i++) {
121             logForwards_[i] += drifts1_[i] + fixedDrift[i];
122             logForwards_[i] +=
123                 std::inner_product(A.row_begin(i), A.row_end(i),
124                                    brownians_.begin(), 0.0);
125             forwards_[i] = std::exp(logForwards_[i]) - displacements_[i];
126         }
127 
128         // same as PC evolver with two steps dropped
129 
130         // c) update curve state
131         curveState_.setOnForwardRates(forwards_);
132 
133         ++currentStep_;
134 
135         return weight;
136     }
137 
currentStep() const138     Size LogNormalFwdRateEuler::currentStep() const {
139         return currentStep_;
140     }
141 
currentState() const142     const CurveState& LogNormalFwdRateEuler::currentState() const {
143         return curveState_;
144     }
145 
146 }
147