Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Functions
crossassetmodel2.cpp File Reference
#include "toplevelfixture.hpp"
#include "utilities.hpp"
#include <boost/test/unit_test.hpp>
#include <qle/methods/multipathgeneratorbase.hpp>
#include <qle/models/cdsoptionhelper.hpp>
#include <qle/models/cpicapfloorhelper.hpp>
#include <qle/models/crlgm1fparametrization.hpp>
#include <qle/models/crossassetanalytics.hpp>
#include <qle/models/crossassetanalyticsbase.hpp>
#include <qle/models/crossassetmodel.hpp>
#include <qle/models/crossassetmodelimpliedeqvoltermstructure.hpp>
#include <qle/models/crossassetmodelimpliedfxvoltermstructure.hpp>
#include <qle/models/dkimpliedyoyinflationtermstructure.hpp>
#include <qle/models/dkimpliedzeroinflationtermstructure.hpp>
#include <qle/models/eqbsconstantparametrization.hpp>
#include <qle/models/eqbsparametrization.hpp>
#include <qle/models/eqbspiecewiseconstantparametrization.hpp>
#include <qle/models/fxbsconstantparametrization.hpp>
#include <qle/models/fxbsparametrization.hpp>
#include <qle/models/fxbspiecewiseconstantparametrization.hpp>
#include <qle/models/fxeqoptionhelper.hpp>
#include <qle/models/gaussian1dcrossassetadaptor.hpp>
#include <qle/models/infdkparametrization.hpp>
#include <qle/models/irlgm1fconstantparametrization.hpp>
#include <qle/models/irlgm1fparametrization.hpp>
#include <qle/models/irlgm1fpiecewiseconstanthullwhiteadaptor.hpp>
#include <qle/models/irlgm1fpiecewiseconstantparametrization.hpp>
#include <qle/models/irlgm1fpiecewiselinearparametrization.hpp>
#include <qle/models/lgm.hpp>
#include <qle/models/lgmimplieddefaulttermstructure.hpp>
#include <qle/models/lgmimpliedyieldtermstructure.hpp>
#include <qle/models/linkablecalibratedmodel.hpp>
#include <qle/models/parametrization.hpp>
#include <qle/models/piecewiseconstanthelper.hpp>
#include <qle/models/pseudoparameter.hpp>
#include <qle/pricingengines/analyticcclgmfxoptionengine.hpp>
#include <qle/pricingengines/analyticdkcpicapfloorengine.hpp>
#include <qle/pricingengines/analyticlgmcdsoptionengine.hpp>
#include <qle/pricingengines/analyticlgmswaptionengine.hpp>
#include <qle/pricingengines/analyticxassetlgmeqoptionengine.hpp>
#include <qle/pricingengines/blackcdsoptionengine.hpp>
#include <qle/pricingengines/crossccyswapengine.hpp>
#include <qle/pricingengines/depositengine.hpp>
#include <qle/pricingengines/discountingcommodityforwardengine.hpp>
#include <qle/pricingengines/discountingcurrencyswapengine.hpp>
#include <qle/pricingengines/discountingequityforwardengine.hpp>
#include <qle/pricingengines/discountingfxforwardengine.hpp>
#include <qle/pricingengines/discountingriskybondengine.hpp>
#include <qle/pricingengines/discountingswapenginemulticurve.hpp>
#include <qle/pricingengines/numericlgmmultilegoptionengine.hpp>
#include <qle/pricingengines/oiccbasisswapengine.hpp>
#include <qle/pricingengines/paymentdiscountingengine.hpp>
#include <ql/currencies/all.hpp>
#include <ql/indexes/ibor/euribor.hpp>
#include <ql/instruments/vanillaoption.hpp>
#include <ql/math/matrixutilities/symmetricschurdecomposition.hpp>
#include <ql/math/optimization/levenbergmarquardt.hpp>
#include <ql/math/randomnumbers/rngtraits.hpp>
#include <ql/math/statistics/incrementalstatistics.hpp>
#include <ql/methods/montecarlo/multipathgenerator.hpp>
#include <ql/methods/montecarlo/pathgenerator.hpp>
#include <ql/quotes/simplequote.hpp>
#include <ql/termstructures/yield/flatforward.hpp>
#include <ql/time/calendars/target.hpp>
#include <ql/time/daycounters/actual360.hpp>
#include <ql/time/daycounters/actualactual.hpp>
#include <ql/time/daycounters/thirty360.hpp>
#include <boost/make_shared.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/covariance.hpp>
#include <boost/accumulators/statistics/error_of_mean.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/variates/covariate.hpp>

Go to the source code of this file.

Functions

 BOOST_AUTO_TEST_CASE (testLgm31fPositiveCovariance)
 
 BOOST_AUTO_TEST_CASE (testLgm31fMoments)
 
 BOOST_AUTO_TEST_CASE (testLgm31fMartingaleProperty)
 

Function Documentation

◆ BOOST_AUTO_TEST_CASE() [1/3]

BOOST_AUTO_TEST_CASE ( testLgm31fPositiveCovariance  )

Definition at line 1052 of file crossassetmodel2.cpp.

1052 {
1053
1054 BOOST_TEST_MESSAGE("Testing for positive semidefinite covariance matrices "
1055 "in Ccy LGM 31F model...");
1056
1057 Lgm31fTestData d;
1058
1059 // check eigenvalues of rho (this check is done in the model constructor
1060 // as well, we cross check this here)
1061
1062 SymmetricSchurDecomposition ssd(d.rho);
1063 for (Size i = 0; i < ssd.eigenvalues().size(); ++i) {
1064 if (ssd.eigenvalues()[i] < 0.0) {
1065 BOOST_ERROR("negative eigenvalue in input matrix (#" << i << ", " << ssd.eigenvalues()[i]);
1066 }
1067 }
1068
1069 // =========================================
1070 // time grid for RFE
1071 // =========================================
1072
1073 std::vector<Time> simTimes_;
1074 simTimes_.push_back(0.0);
1075 for (Size i = 1; i <= 118; ++i) {
1076 Date tmp = TARGET().advance(d.refDate, i * Months);
1077 simTimes_.push_back(ActualActual(ActualActual::ISDA).yearFraction(d.refDate, tmp));
1078 }
1079 for (Size i = 1; i <= 40; ++i) {
1080 Date tmp = TARGET().advance(d.refDate, (117 + 3 * i) * Months);
1081 simTimes_.push_back(ActualActual(ActualActual::ISDA).yearFraction(d.refDate, tmp));
1082 }
1083 for (Size i = 1; i <= 31; ++i) {
1084 Date tmp = TARGET().advance(d.refDate, (19 + i) * Years);
1085 simTimes_.push_back(ActualActual(ActualActual::ISDA).yearFraction(d.refDate, tmp));
1086 }
1087 for (Size i = 1; i <= 10; ++i) {
1088 Date tmp = TARGET().advance(d.refDate, (50 + i * 5) * Years);
1089 simTimes_.push_back(ActualActual(ActualActual::ISDA).yearFraction(d.refDate, tmp));
1090 }
1091
1092 QuantLib::ext::shared_ptr<StochasticProcess> p_exact = d.xmodelExact->stateProcess();
1093 QuantLib::ext::shared_ptr<StochasticProcess> p_euler = d.xmodelEuler->stateProcess();
1094
1095 // check that covariance matrices are positive semidefinite
1096
1097 Array x0 = p_exact->initialValues();
1098 for (Size i = 1; i < simTimes_.size(); ++i) {
1099 // x0 does not matter, since covariance does not depend on it
1100 Matrix cov = p_exact->covariance(simTimes_[i - 1], x0, simTimes_[i] - simTimes_[i - 1]);
1101 SymmetricSchurDecomposition ssd(cov);
1102 for (Size j = 0; j < ssd.eigenvalues().size(); ++j) {
1103 if (ssd.eigenvalues()[j] < 0.0) {
1104 BOOST_ERROR("negative eigenvalue at " << j << " in covariance matrix at t=" << simTimes_[i] << " ("
1105 << ssd.eigenvalues()[j] << ")");
1106 }
1107 }
1108 }
1109
1110 // check positive semidefiniteness for one super-large step
1111 Matrix cov = p_exact->covariance(0.0, x0, simTimes_.back());
1112 SymmetricSchurDecomposition ssd2(cov);
1113 for (Size i = 0; i < ssd2.eigenvalues().size(); ++i) {
1114 if (ssd2.eigenvalues()[i] < 0.0) {
1115 BOOST_ERROR("negative eigenvalue at " << i << " in covariance matrix at t=0.0 for dt=100.0"
1116 << " (" << ssd2.eigenvalues()[i] << ")");
1117 }
1118 }
1119
1120} // testLgm31fPositiveCovariance

◆ BOOST_AUTO_TEST_CASE() [2/3]

BOOST_AUTO_TEST_CASE ( testLgm31fMoments  )

Definition at line 1122 of file crossassetmodel2.cpp.

1122 {
1123
1124 BOOST_TEST_MESSAGE("Check analytical moments against Euler simulation in "
1125 "Ccy LGM 31F model...");
1126
1127 Lgm31fTestData d;
1128
1129 QuantLib::ext::shared_ptr<StochasticProcess> p_exact = d.xmodelExact->stateProcess();
1130 QuantLib::ext::shared_ptr<StochasticProcess> p_euler = d.xmodelEuler->stateProcess();
1131
1132 Array x0 = p_exact->initialValues();
1133
1134 // check the expectation and covariance over 0...T against euler
1135 Real T = 2.0;
1136 Size steps = static_cast<Size>(T * 10.0);
1137 Size paths = 25000;
1138 Size seed = 42;
1139 TimeGrid grid(T, steps);
1140
1141 Array e_an = p_exact->expectation(0.0, x0, T);
1142 Matrix v_an = p_exact->covariance(0.0, x0, T);
1143
1144 const Size dim = 31;
1145
1146 if (auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(p_euler)) {
1147 tmp->resetCache(grid.size() - 1 - 1);
1148 }
1149 MultiPathGeneratorSobolBrownianBridge pgen(p_euler, grid, SobolBrownianGenerator::Steps, seed);
1150
1151 accumulator_set<double, stats<tag::mean, tag::error_of<tag::mean> > > e_eu[dim];
1152 accumulator_set<double, stats<tag::covariance<double, tag::covariate1> > > v_eu[dim][dim];
1153
1154 for (Size i = 0; i < paths; ++i) {
1155 Sample<MultiPath> path = pgen.next();
1156 for (Size ii = 0; ii < dim; ++ii) {
1157 Real cii = path.value[ii].back();
1158 e_eu[ii](cii);
1159 for (Size jj = 0; jj <= ii; ++jj) {
1160 Real cjj = path.value[jj].back();
1161 v_eu[ii][jj](cii, covariate1 = cjj);
1162 }
1163 }
1164 }
1165
1166 Real tol1 = 2.0E-4; // ir
1167 Real tol2 = 15.0E-4; // fx
1168 Real tol3 = 2.0E-4; // ir-ir
1169 Real tol4 = 2.0E-4; // ir-fx
1170 Real tol5 = 15.0E-4; // fx-fx
1171
1172 // error checks and output is in new indexes !
1173 Real tol;
1174 // the test cases involving the CPI indices are broken
1175 // this is because of extreme values for H, which seem
1176 // to cause problems in the Euler discretization
1177 for (Size i = 0; i < 28 /*dim*/; ++i) {
1178 if (i < 16) {
1179 tol = tol1;
1180 } else {
1181 tol = tol2;
1182 }
1183 if (std::fabs(mean(e_eu[i]) - e_an[i]) > tol) {
1184 BOOST_ERROR("analytical expectation at " << i << " (" << e_an[i]
1185 << ") is inconsistent with numerical value (Euler "
1186 "discretization, "
1187 << mean(e_eu[i]) << ") error is " << e_an[i] - mean(e_eu[i])
1188 << " tolerance is " << tol);
1189 }
1190 for (Size j = 0; j <= i; ++j) {
1191 if (i < 16) {
1192 tol = tol3;
1193 } else {
1194 if (j < 16) {
1195 tol = tol4;
1196 } else {
1197 tol = tol5;
1198 }
1199 }
1200 if (std::fabs(boost::accumulators::covariance(v_eu[i][j]) - v_an[i][j]) > tol) {
1201 BOOST_ERROR("analytical covariance at ("
1202 << i << "," << j << ") (" << v_an[i][j]
1203 << ") is inconsistent with numerical "
1204 "value (Euler discretization, "
1205 << boost::accumulators::covariance(v_eu[i][j]) << "), error is "
1206 << v_an[i][j] - boost::accumulators::covariance(v_eu[i][j]) << " tolerance is " << tol);
1207 }
1208 }
1209 }
1210
1211 // debug output
1212 // std::clog << "EXACT and error expectation" << std::endl;
1213 // for (Size ii = 0; ii < dim; ++ii) {
1214 // std::clog << "#" << ii << " " << e_an[mapping[ii]] << " "
1215 // << mean(e_eu[mapping[ii]]) << " "
1216 // << mean(e_eu[mapping[ii]]) - e_an[mapping[ii]] << " +- "
1217 // << error_of<tag::mean>(e_eu[mapping[ii]]) << " => mult "
1218 // << (mean(e_eu[mapping[ii]]) - e_an[mapping[ii]]) /
1219 // error_of<tag::mean>(e_eu[mapping[ii]])
1220 // << std::endl;
1221 // }
1222
1223 // std::clog << "EXACT covariance" << std::endl;
1224 // for (Size ii = 0; ii < dim; ++ii) {
1225 // std::clog << "| ";
1226 // for (Size jj = 0; jj < ii; ++jj) {
1227 // std::clog << v_an[mapping[ii]][mapping[jj]] << " ";
1228 // }
1229 // std::clog << " |" << std::endl;
1230 // }
1231 // std::clog << std::endl;
1232
1233 // std::clog << "EULER covariance error" << std::endl;
1234 // for (Size ii = 0; ii < dim; ++ii) {
1235 // std::clog << "| ";
1236 // for (Size jj = 0; jj <= ii; ++jj) {
1237 // std::clog << covariance(v_eu[mapping[ii]][mapping[jj]]) -
1238 // v_an[mapping[ii]][mapping[jj]]
1239 // << " ";
1240 // }
1241 // std::clog << " |" << std::endl;
1242 // }
1243 // std::clog << std::endl;
1244 // end debug output
1245
1246} // testLgm31fMoments
Instantiation using SobolBrownianGenerator from models/marketmodels/browniangenerators.
std::vector< Size > steps
+ Here is the call graph for this function:

◆ BOOST_AUTO_TEST_CASE() [3/3]

BOOST_AUTO_TEST_CASE ( testLgm31fMartingaleProperty  )

Definition at line 1248 of file crossassetmodel2.cpp.

1248 {
1249
1250 BOOST_TEST_MESSAGE("Check martingale property in Ccy LGM 31F model...");
1251
1252 Lgm31fTestData d;
1253
1254 QuantLib::ext::shared_ptr<StochasticProcess> p_exact = d.xmodelExact->stateProcess();
1255 QuantLib::ext::shared_ptr<StochasticProcess> p_euler = d.xmodelEuler->stateProcess();
1256
1257 Real T = 2.0;
1258 Size steps = static_cast<Size>(T * 10.0);
1259 Size paths = 25000;
1260 Size seed = 42;
1261 TimeGrid grid(T, steps);
1262
1263 const Size dim = 31, nIr = 13 + 3;
1264
1265 if (auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(p_euler)) {
1266 tmp->resetCache(grid.size() - 1);
1267 }
1268 if (auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(p_exact)) {
1269 tmp->resetCache(grid.size() - 1);
1270 }
1271 MultiPathGeneratorSobolBrownianBridge pgen(p_euler, grid, SobolBrownianGenerator::Steps, seed);
1272 MultiPathGeneratorSobolBrownianBridge pgen2(p_exact, grid, SobolBrownianGenerator::Steps, seed);
1273
1274 accumulator_set<double, stats<tag::mean, tag::error_of<tag::mean> > > e_eu2[dim];
1275
1276 for (Size i = 0; i < paths; ++i) {
1277 Sample<MultiPath> path = pgen.next();
1278 for (Size ii = 0; ii < nIr; ++ii) {
1279 if (ii == 0) {
1280 // domestic currency
1281 e_eu2[ii](1.0 / d.xmodelExact->numeraire(0, T, path.value[0].back()));
1282 } else {
1283 // foreign currencies
1284 e_eu2[ii](std::exp(path.value[nIr + (ii - 1)].back()) /
1285 d.xmodelExact->numeraire(0, T, path.value[0].back()));
1286 }
1287 }
1288 }
1289
1290 // as before we have to exclude the inflation indices
1291 Real tol = 0.5E-4;
1292 for (Size ii = 0; ii < nIr - 3; ++ii) {
1293 if (std::fabs(-std::log(mean(e_eu2[ii])) / T + std::log(d.yts->discount(T)) / T) > tol) {
1294 BOOST_ERROR("failed to verify martingale property for ccy "
1295 << ii << ", equivalent simulated zero yield is " << -std::log(mean(e_eu2[ii])) / T
1296 << " while theoretical value is " << -std::log(d.yts->discount(T)) / T << " difference is "
1297 << -std::log(mean(e_eu2[ii])) / T + std::log(d.yts->discount(T)) / T << ", tolerance is "
1298 << tol);
1299 }
1300 }
1301
1302} // testLgm13fMartingaleProperty
+ Here is the call graph for this function: