Skip to content

Commit 4030879

Browse files
rolandlichtersjenkins
authored andcommitted
QPR-11618 american swaption pt 1/2 (add FD pricer for Bermudan swaption)
1 parent e19bd6a commit 4030879

16 files changed

Lines changed: 470 additions & 50 deletions

OREData/ored/portfolio/builders/swaption.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ boost::shared_ptr<PricingEngine> LGMGridBermudanSwaptionEngineBuilder::engineImp
206206
const std::vector<Date>& expiries,
207207
const Date& maturity,
208208
const std::vector<Real>& strikes) {
209-
DLOG("Building Bermudan Swaption engine for trade " << id);
209+
DLOG("Building LGM Grid Bermudan Swaption engine for trade " << id);
210210

211211
boost::shared_ptr<QuantExt::LGM> lgm = model(id, key, expiries, maturity, strikes);
212212

@@ -224,6 +224,30 @@ boost::shared_ptr<PricingEngine> LGMGridBermudanSwaptionEngineBuilder::engineImp
224224
lgm, sy, ny, sx, nx, market_->discountCurve(ccy, configuration(MarketContext::pricing)));
225225
}
226226

227+
boost::shared_ptr<PricingEngine> LGMFDBermudanSwaptionEngineBuilder::engineImpl(const string& id, const string& key,
228+
const std::vector<Date>& expiries,
229+
const Date& maturity,
230+
const std::vector<Real>& strikes) {
231+
DLOG("Building LGM FD Bermudan Swaption engine for trade " << id);
232+
233+
boost::shared_ptr<QuantExt::LGM> lgm = model(id, key, expiries, maturity, strikes);
234+
235+
DLOG("Get engine data");
236+
QuantLib::FdmSchemeDesc scheme = parseFdmSchemeDesc(engineParameter("Scheme"));
237+
Size stateGridPoints = parseInteger(engineParameter("StateGridPoints"));
238+
Size timeStepsPerYear = parseInteger(engineParameter("TimeStepsPerYear"));
239+
Real mesherEpsilon = parseReal(engineParameter("MesherEpsilon"));
240+
241+
Real maxTime = lgm->termStructure()->timeFromReference(maturity);
242+
243+
DLOG("Build engine (configuration " << configuration(MarketContext::pricing) << ")");
244+
boost::shared_ptr<IborIndex> index;
245+
std::string ccy = tryParseIborIndex(key, index) ? index->currency().code() : key;
246+
return boost::make_shared<QuantExt::NumericLgmMultiLegOptionEngine>(
247+
lgm, maxTime, scheme, stateGridPoints, timeStepsPerYear, mesherEpsilon,
248+
market_->discountCurve(ccy, configuration(MarketContext::pricing)));
249+
}
250+
227251
boost::shared_ptr<PricingEngine> LgmMcBermudanSwaptionEngineBuilder::engineImpl(const string& id, const string& key,
228252
const std::vector<Date>& expiries,
229253
const Date& maturity,

OREData/ored/portfolio/builders/swaption.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,27 @@ class LGMGridBermudanSwaptionEngineBuilder : public LGMBermudanSwaptionEngineBui
111111
const std::vector<Real>& strikes) override;
112112
};
113113

114+
//! Implementation of BermudanSwaptionEngineBuilder using LGM FD pricer
115+
/*! \ingroup builders
116+
*/
117+
class LGMFDBermudanSwaptionEngineBuilder : public LGMBermudanSwaptionEngineBuilder {
118+
public:
119+
LGMFDBermudanSwaptionEngineBuilder() : LGMBermudanSwaptionEngineBuilder("FD") {}
120+
121+
protected:
122+
virtual boost::shared_ptr<PricingEngine> engineImpl(
123+
//! a unique (trade) id, for caching
124+
const string& id,
125+
//! the key (index or ccy)
126+
const string& key,
127+
//! Excercise dates
128+
const std::vector<Date>& dates,
129+
//! maturity of the underlying
130+
const Date& maturity,
131+
//! Fixed rate (null means ATM)
132+
const std::vector<Real>& strikes) override;
133+
};
134+
114135
//! Implementation of LGMBermudanSwaptionEngineBuilder using MC pricer
115136
/*! \ingroup portfolio
116137
*/

OREData/ored/portfolio/swaption.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <ql/cashflows/simplecashflow.hpp>
2121
#include <ql/exercise.hpp>
2222
#include <ql/instruments/compositeinstrument.hpp>
23-
#include <ql/instruments/nonstandardswaption.hpp>
2423
#include <ql/instruments/swaption.hpp>
2524
#include <ql/time/daycounters/actualactual.hpp>
2625

OREData/ored/utilities/initbuilders.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ void initBuilders() {
418418
ORE_REGISTER_ENGINE_BUILDER(FxTouchOptionEngineBuilder, false)
419419
ORE_REGISTER_ENGINE_BUILDER(EuropeanSwaptionEngineBuilder, false)
420420
ORE_REGISTER_ENGINE_BUILDER(LGMGridBermudanSwaptionEngineBuilder, false)
421+
ORE_REGISTER_ENGINE_BUILDER(LGMFDBermudanSwaptionEngineBuilder, false)
421422
ORE_REGISTER_ENGINE_BUILDER(LgmMcBermudanSwaptionEngineBuilder, false)
422423
ORE_REGISTER_ENGINE_BUILDER(VarSwapEngineBuilder, false)
423424
ORE_REGISTER_ENGINE_BUILDER(FxDoubleTouchOptionAnalyticEngineBuilder, false)

OREData/ored/utilities/parsers.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -685,11 +685,15 @@ QuantLib::CPI::InterpolationType parseObservationInterpolation(const std::string
685685
}
686686

687687
FdmSchemeDesc parseFdmSchemeDesc(const std::string& s) {
688-
static std::map<std::string, FdmSchemeDesc> m = {
689-
{"Hundsdorfer", FdmSchemeDesc::Hundsdorfer()}, {"Douglas", FdmSchemeDesc::Douglas()},
690-
{"CraigSneyd", FdmSchemeDesc::CraigSneyd()}, {"ModifiedCraigSneyd", FdmSchemeDesc::ModifiedCraigSneyd()},
691-
{"ImplicitEuler", FdmSchemeDesc::ImplicitEuler()}, {"ExplicitEuler", FdmSchemeDesc::ExplicitEuler()},
692-
{"MethodOfLines", FdmSchemeDesc::MethodOfLines()}, {"TrBDF2", FdmSchemeDesc::TrBDF2()}};
688+
static std::map<std::string, FdmSchemeDesc> m = {{"CrankNicolson", FdmSchemeDesc::CrankNicolson()},
689+
{"Hundsdorfer", FdmSchemeDesc::Hundsdorfer()},
690+
{"Douglas", FdmSchemeDesc::Douglas()},
691+
{"CraigSneyd", FdmSchemeDesc::CraigSneyd()},
692+
{"ModifiedCraigSneyd", FdmSchemeDesc::ModifiedCraigSneyd()},
693+
{"ImplicitEuler", FdmSchemeDesc::ImplicitEuler()},
694+
{"ExplicitEuler", FdmSchemeDesc::ExplicitEuler()},
695+
{"MethodOfLines", FdmSchemeDesc::MethodOfLines()},
696+
{"TrBDF2", FdmSchemeDesc::TrBDF2()}};
693697

694698
auto it = m.find(s);
695699
if (it != m.end())

QuantExt/qle/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ methods/fdmblackscholesmesher.cpp
167167
methods/fdmblackscholesop.cpp
168168
methods/fdmdefaultableequityjumpdiffusionfokkerplanckop.cpp
169169
methods/fdmdefaultableequityjumpdiffusionop.cpp
170+
methods/fdmlgmop.cpp
170171
methods/fdmquantohelper.cpp
171172
methods/multipathgeneratorbase.cpp
172173
methods/multipathvariategenerator.cpp
@@ -209,6 +210,7 @@ models/jyimpliedzeroinflationtermstructure.cpp
209210
models/lgm.cpp
210211
models/lgmcalibrationinfo.cpp
211212
models/lgmconvolutionsolver2.cpp
213+
models/lgmfdsolver.cpp
212214
models/lgmimplieddefaulttermstructure.cpp
213215
models/lgmimpliedyieldtermstructure.cpp
214216
models/lgmvectorised.cpp
@@ -642,6 +644,7 @@ methods/fdmblackscholesmesher.hpp
642644
methods/fdmblackscholesop.hpp
643645
methods/fdmdefaultableequityjumpdiffusionfokkerplanckop.hpp
644646
methods/fdmdefaultableequityjumpdiffusionop.hpp
647+
methods/fdmlgmop.hpp
645648
methods/fdmquantohelper.hpp
646649
methods/multipathgeneratorbase.hpp
647650
methods/multipathvariategenerator.hpp
@@ -710,8 +713,10 @@ models/irmodel.hpp
710713
models/jyimpliedyoyinflationtermstructure.hpp
711714
models/jyimpliedzeroinflationtermstructure.hpp
712715
models/lgm.hpp
716+
models/lgmbackwardsolver.hpp
713717
models/lgmcalibrationinfo.hpp
714718
models/lgmconvolutionsolver2.hpp
719+
models/lgmfdsolver.hpp
715720
models/lgmimplieddefaulttermstructure.hpp
716721
models/lgmimpliedyieldtermstructure.hpp
717722
models/lgmvectorised.hpp

QuantExt/qle/methods/fdmlgmop.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
Copyright (C) 2024 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
5+
This file is part of ORE, a free-software/open-source library
6+
for transparent pricing and risk analysis - http://opensourcerisk.org
7+
8+
ORE is free software: you can redistribute it and/or modify it
9+
under the terms of the Modified BSD License. You should have received a
10+
copy of the license along with this program.
11+
The license is also available online at <http://opensourcerisk.org>
12+
13+
This program is distributed on the basis that it will form a useful
14+
contribution to risk analytics and model standardisation, but WITHOUT
15+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17+
*/
18+
19+
#include <qle/methods/fdmlgmop.hpp>
20+
21+
#include <ql/methods/finitedifferences/meshers/fdmmesher.hpp>
22+
#include <ql/methods/finitedifferences/operators/fdmlinearoplayout.hpp>
23+
#include <ql/methods/finitedifferences/operators/secondderivativeop.hpp>
24+
25+
namespace QuantExt {
26+
27+
FdmLgmOp::FdmLgmOp(const ext::shared_ptr<FdmMesher>& mesher, const ext::shared_ptr<StochasticProcess1D>& process)
28+
: mesher_(mesher), process_(process), dxMap_(FirstDerivativeOp(0, mesher)), dxxMap_(SecondDerivativeOp(0, mesher)),
29+
mapT_(0, mesher) {}
30+
31+
void FdmLgmOp::setTime(Time t1, Time t2) {
32+
Real v = process_->variance(t1, 0.0, t2 - t1) / (t2 - t1);
33+
mapT_.axpyb(Array(), dxMap_, dxxMap_.mult(0.5 * Array(mesher_->layout()->size(), v)), Array(1, 0));
34+
}
35+
36+
Size FdmLgmOp::size() const { return 1u; }
37+
38+
Array FdmLgmOp::apply(const Array& u) const { return mapT_.apply(u); }
39+
40+
Array FdmLgmOp::apply_direction(Size direction, const Array& r) const {
41+
if (direction == 0)
42+
return mapT_.apply(r);
43+
else {
44+
Array retVal(r.size(), 0.0);
45+
return retVal;
46+
}
47+
}
48+
49+
Array FdmLgmOp::apply_mixed(const Array& r) const {
50+
Array retVal(r.size(), 0.0);
51+
return retVal;
52+
}
53+
54+
Array FdmLgmOp::solve_splitting(Size direction, const Array& r, Real dt) const {
55+
if (direction == 0)
56+
return mapT_.solve_splitting(r, dt, 1.0);
57+
else {
58+
Array retVal(r);
59+
return retVal;
60+
}
61+
}
62+
63+
Array FdmLgmOp::preconditioner(const Array& r, Real dt) const { return solve_splitting(0, r, dt); }
64+
65+
#if !defined(QL_NO_UBLAS_SUPPORT)
66+
std::vector<QuantLib::SparseMatrix> FdmLgmOp::toMatrixDecomp() const {
67+
std::vector<QuantLib::SparseMatrix> retVal(1, mapT_.toMatrix());
68+
return retVal;
69+
}
70+
#endif
71+
} // namespace QuantExt

QuantExt/qle/methods/fdmlgmop.hpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Copyright (C) 2024 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
5+
This file is part of ORE, a free-software/open-source library
6+
for transparent pricing and risk analysis - http://opensourcerisk.org
7+
8+
ORE is free software: you can redistribute it and/or modify it
9+
under the terms of the Modified BSD License. You should have received a
10+
copy of the license along with this program.
11+
The license is also available online at <http://opensourcerisk.org>
12+
13+
This program is distributed on the basis that it will form a useful
14+
contribution to risk analytics and model standardisation, but WITHOUT
15+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17+
*/
18+
19+
/*! \file fdmlgmop.hpp
20+
\brief finite difference operator LGM model
21+
22+
*/
23+
24+
#pragma once
25+
26+
#include <ql/methods/finitedifferences/operators/fdmlinearopcomposite.hpp>
27+
#include <ql/methods/finitedifferences/operators/firstderivativeop.hpp>
28+
#include <ql/methods/finitedifferences/operators/triplebandlinearop.hpp>
29+
#include <ql/stochasticprocess.hpp>
30+
31+
namespace QuantExt {
32+
using namespace QuantLib;
33+
34+
class FdmLgmOp : public FdmLinearOpComposite {
35+
public:
36+
FdmLgmOp(const ext::shared_ptr<FdmMesher>& mesher, const ext::shared_ptr<StochasticProcess1D>& process);
37+
38+
Size size() const override;
39+
void setTime(Time t1, Time t2) override;
40+
41+
Array apply(const Array& r) const override;
42+
Array apply_mixed(const Array& r) const override;
43+
Array apply_direction(Size direction, const Array& r) const override;
44+
Array solve_splitting(Size direction, const Array& r, Real s) const override;
45+
Array preconditioner(const Array& r, Real s) const override;
46+
47+
#if !defined(QL_NO_UBLAS_SUPPORT)
48+
std::vector<QuantLib::SparseMatrix> toMatrixDecomp() const override;
49+
#endif
50+
private:
51+
ext::shared_ptr<FdmMesher> mesher_;
52+
ext::shared_ptr<StochasticProcess1D> process_;
53+
FirstDerivativeOp dxMap_;
54+
TripleBandLinearOp dxxMap_;
55+
TripleBandLinearOp mapT_;
56+
};
57+
} // namespace QuantExt
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
Copyright (C) 2024 Quaternion Risk Management Ltd
3+
All rights reserved.
4+
5+
This file is part of ORE, a free-software/open-source library
6+
for transparent pricing and risk analysis - http://opensourcerisk.org
7+
8+
ORE is free software: you can redistribute it and/or modify it
9+
under the terms of the Modified BSD License. You should have received a
10+
copy of the license along with this program.
11+
The license is also available online at <http://opensourcerisk.org>
12+
13+
This program is distributed on the basis that it will form a useful
14+
contribution to risk analytics and model standardisation, but WITHOUT
15+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16+
FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17+
*/
18+
19+
/*! \file lgmbackwardsolver.hpp
20+
\brief interface for LGM1F backward solver
21+
22+
\ingroup engines
23+
*/
24+
25+
#pragma once
26+
27+
#include <qle/math/randomvariable.hpp>
28+
#include <qle/models/lgm.hpp>
29+
30+
namespace QuantExt {
31+
32+
//! Interface for LGM1F backward solver
33+
class LgmBackwardSolver {
34+
public:
35+
virtual ~LgmBackwardSolver() {}
36+
37+
/* get grid size */
38+
virtual Size gridSize() const = 0;
39+
40+
/* get discretised states grid at time t */
41+
virtual RandomVariable stateGrid(const Real t) const = 0;
42+
43+
/* roll back an deflated NPV array from t1 to t0 using the given number of steps or,
44+
if the number of steps is not given, an appropriate number of steps which will
45+
generally depend on the numerical method that is used. */
46+
virtual RandomVariable rollback(const RandomVariable& v, const Real t1, const Real t0,
47+
Size steps = Null<Size>()) const = 0;
48+
49+
/* the underlying model */
50+
virtual const boost::shared_ptr<LinearGaussMarkovModel>& model() const = 0;
51+
};
52+
53+
} // namespace QuantExt

QuantExt/qle/models/lgmconvolutionsolver2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ RandomVariable LgmConvolutionSolver2::stateGrid(const Real t) const {
6868
return x;
6969
}
7070

71-
RandomVariable LgmConvolutionSolver2::rollback(const RandomVariable& v, const Real t1, const Real t0) const {
71+
RandomVariable LgmConvolutionSolver2::rollback(const RandomVariable& v, const Real t1, const Real t0, Size) const {
7272
if (QuantLib::close_enough(t0, t1) || v.deterministic())
7373
return v;
7474
QL_REQUIRE(t0 < t1, "LgmConvolutionSolver2::rollback(): t0 (" << t0 << ") < t1 (" << t1 << ") required.");

0 commit comments

Comments
 (0)