20#include <boost/test/unit_test.hpp>
21#include <boost/timer/timer.hpp>
50#include <oret/toplevelfixture.hpp>
51#include <ql/math/randomnumbers/mt19937uniformrng.hpp>
52#include <ql/time/calendars/target.hpp>
53#include <ql/time/date.hpp>
54#include <ql/time/daycounters/actualactual.hpp>
61using namespace boost::unit_test_framework;
65using boost::timer::cpu_timer;
66using boost::timer::default_places;
71 QuantLib::ext::shared_ptr<data::Conventions> conventions(
new data::Conventions());
73 QuantLib::ext::shared_ptr<data::Convention> swapIndexConv(
75 conventions->add(swapIndexConv);
77 QuantLib::ext::shared_ptr<data::Convention> swapConv(
78 new data::IRSwapConvention(
"EUR-6M-SWAP-CONVENTIONS",
"TARGET",
"Annual",
"MF",
"30/360",
"EUR-EURIBOR-6M"));
79 conventions->add(swapConv);
81 InstrumentConventions::instance().setConventions(conventions);
84QuantLib::ext::shared_ptr<Portfolio>
buildPortfolio(QuantLib::ext::shared_ptr<EngineFactory>& factory) {
86 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
89 string index =
"EUR-EURIBOR-6M";
90 string floatFreq =
"6M";
91 Real fixedRate = 0.02;
92 string fixFreq =
"1Y";
96 Date today = Settings::instance().evaluationDate();
97 Calendar cal = TARGET();
98 string calStr =
"TARGET";
100 string rule =
"Forward";
102 string fixDC =
"30/360";
103 string floatDC =
"ACT/360";
105 vector<double> notional(1, 1000000);
106 vector<double> spread(1, 0);
108 Date startDate = cal.adjust(today + 1 * Months);
109 Date endDate = cal.adjust(startDate + term * Years);
113 oss << io::iso_date(startDate);
114 string start(oss.str());
117 oss << io::iso_date(endDate);
118 string end(oss.str());
128 LegData fixedLeg(QuantLib::ext::make_shared<FixedLegData>(vector<double>(1, fixedRate)), isPayer, ccy, fixedSchedule, fixDC,
132 vector<double> spreads(1, 0);
133 LegData floatingLeg(QuantLib::ext::make_shared<FloatingLegData>(index, days,
false, spread), !isPayer, ccy, floatSchedule,
136 QuantLib::ext::shared_ptr<Trade> swap(
new data::Swap(env, floatingLeg, fixedLeg));
140 portfolio->add(swap);
142 portfolio->build(factory);
148 SavedSettings backup;
153 Date today = Date(14, April, 2016);
154 Settings::instance().evaluationDate() = today;
157 QuantLib::ext::shared_ptr<DateGrid> dg = QuantLib::ext::make_shared<DateGrid>(dateGridString);
160 BOOST_TEST_MESSAGE(
"Date Grid : " << dateGridString);
163 string baseCcy =
"EUR";
165 ccys.push_back(baseCcy);
166 ccys.push_back(
"GBP");
167 ccys.push_back(
"CHF");
168 ccys.push_back(
"USD");
169 ccys.push_back(
"JPY");
172 QuantLib::ext::shared_ptr<Market> initMarket = QuantLib::ext::make_shared<TestMarket>(today);
176 parameters->baseCcy() =
"EUR";
177 parameters->setDiscountCurveNames({
"EUR",
"GBP",
"USD",
"CHF",
"JPY"});
178 parameters->setYieldCurveTenors(
"",
179 {1 * Months, 6 * Months, 1 * Years, 2 * Years, 5 * Years, 10 * Years, 20 * Years});
180 parameters->setIndices({
"EUR-EURIBOR-6M",
"USD-LIBOR-3M",
"GBP-LIBOR-6M",
"CHF-LIBOR-6M",
"JPY-LIBOR-6M"});
181 parameters->interpolation() =
"LogLinear";
183 parameters->setSwapVolTerms(
"", {6 * Months, 1 * Years});
184 parameters->setSwapVolExpiries(
"", {1 * Years, 2 * Years});
185 parameters->setSwapVolKeys(ccys);
186 parameters->swapVolDecayMode() =
"ForwardVariance";
187 parameters->setSimulateSwapVols(
false);
189 parameters->setFxVolExpiries(
"",
190 vector<Period>{1 * Months, 3 * Months, 6 * Months, 2 * Years, 3 * Years, 4 * Years, 5 * Years});
191 parameters->setFxVolDecayMode(
string(
"ConstantVariance"));
192 parameters->setSimulateFXVols(
false);
194 parameters->setFxVolCcyPairs({
"USDEUR",
"GBPEUR",
"CHFEUR",
"JPYEUR"});
196 parameters->setFxCcyPairs({
"USDEUR",
"GBPEUR",
"CHFEUR",
"JPYEUR"});
198 parameters->additionalScenarioDataIndices() = {
"EUR-EURIBOR-6M",
"USD-LIBOR-3M",
"GBP-LIBOR-6M",
"CHF-LIBOR-6M",
200 parameters->additionalScenarioDataCcys() = {
"EUR",
"GBP",
"USD",
"CHF",
"JPY"};
208 vector<string> swaptionExpiries = {
"1Y",
"2Y",
"3Y",
"5Y",
"7Y",
"10Y",
"15Y",
"20Y",
"30Y"};
209 vector<string> swaptionTerms = {
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y",
"5Y"};
210 vector<string> swaptionStrikes(swaptionExpiries.size(),
"ATM");
211 vector<Time> hTimes = {};
212 vector<Time> aTimes = {};
214 std::vector<QuantLib::ext::shared_ptr<IrModelData>> irConfigs;
216 vector<Real> hValues = {0.02};
217 vector<Real> aValues = {0.008};
218 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
219 "EUR", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
220 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
224 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
225 "USD", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
226 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
230 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
231 "GBP", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
232 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
236 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
237 "CHF", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
238 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
242 irConfigs.push_back(QuantLib::ext::make_shared<IrLgmData>(
243 "JPY", calibrationType, revType, volType,
false, ParamType::Constant, hTimes, hValues,
true,
244 ParamType::Piecewise, aTimes, aValues, 0.0, 1.0, swaptionExpiries, swaptionTerms, swaptionStrikes));
247 vector<string> optionExpiries = {
"1Y",
"2Y",
"3Y",
"5Y",
"7Y",
"10Y"};
248 vector<string> optionStrikes(optionExpiries.size(),
"ATMF");
249 vector<Time> sigmaTimes = {};
251 std::vector<QuantLib::ext::shared_ptr<FxBsData>> fxConfigs;
252 vector<Real> sigmaValues = {0.15};
253 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"USD",
"EUR", calibrationType,
true, ParamType::Piecewise,
254 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
256 sigmaValues = {0.20};
257 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"GBP",
"EUR", calibrationType,
true, ParamType::Piecewise,
258 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
260 sigmaValues = {0.20};
261 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"CHF",
"EUR", calibrationType,
true, ParamType::Piecewise,
262 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
264 sigmaValues = {0.20};
265 fxConfigs.push_back(QuantLib::ext::make_shared<FxBsData>(
"JPY",
"EUR", calibrationType,
true, ParamType::Piecewise,
266 sigmaTimes, sigmaValues, optionExpiries, optionStrikes));
268 map<CorrelationKey, Handle<Quote>> corr;
271 corr[make_pair(f_1, f_2)] = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(0.6));
273 QuantLib::ext::shared_ptr<CrossAssetModelData> config(QuantLib::ext::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, corr));
277 QuantLib::ext::shared_ptr<CrossAssetModelBuilder> modelBuilder(
new CrossAssetModelBuilder(initMarket, config));
278 QuantLib::ext::shared_ptr<QuantExt::CrossAssetModel> model = *modelBuilder->model();
283 bool antithetic =
false;
284 if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<CrossAssetStateProcess>(model->stateProcess())) {
285 tmp->resetCache(dg->timeGrid().size() - 1);
287 QuantLib::ext::shared_ptr<QuantExt::MultiPathGeneratorBase> pathGen =
288 QuantLib::ext::make_shared<MultiPathGeneratorMersenneTwister>(model->stateProcess(), dg->timeGrid(), seed, antithetic);
291 QuantLib::ext::shared_ptr<analytics::ScenarioSimMarket> simMarket =
292 QuantLib::ext::make_shared<analytics::ScenarioSimMarket>(initMarket, parameters);
295 QuantLib::ext::shared_ptr<ScenarioFactory> scenarioFactory =
296 QuantLib::ext::make_shared<SimpleScenarioFactory>(
true);
297 QuantLib::ext::shared_ptr<ScenarioGenerator> scenarioGenerator = QuantLib::ext::make_shared<CrossAssetModelScenarioGenerator>(
298 model, pathGen, scenarioFactory, parameters, today, dg, initMarket);
299 simMarket->scenarioGenerator() = scenarioGenerator;
302 QuantLib::ext::shared_ptr<EngineData>
data = QuantLib::ext::make_shared<EngineData>();
303 data->model(
"Swap") =
"DiscountedCashflows";
304 data->engine(
"Swap") =
"DiscountingSwapEngine";
305 QuantLib::ext::shared_ptr<EngineFactory> factory = QuantLib::ext::make_shared<EngineFactory>(
data, simMarket);
307 QuantLib::ext::shared_ptr<Portfolio> portfolio =
buildPortfolio(factory);
311 QuantLib::ext::shared_ptr<InMemoryAggregationScenarioData> inMemoryScenarioData =
312 QuantLib::ext::make_shared<InMemoryAggregationScenarioData>(dg->size(), samples);
314 simMarket->aggregationScenarioData() = inMemoryScenarioData;
322 QuantLib::ext::shared_ptr<NPVCube> cube =
323 QuantLib::ext::make_shared<DoublePrecisionInMemoryCube>(today, portfolio->ids(), dg->dates(), samples);
324 vector<QuantLib::ext::shared_ptr<ValuationCalculator>> calculators;
325 calculators.push_back(QuantLib::ext::make_shared<NPVCalculator>(baseCcy));
326 valEngine.
buildCube(portfolio, cube, calculators);
329 BOOST_TEST_MESSAGE(
"Cube generated in " << t.format(default_places,
"%w") <<
" seconds");
331 map<string, vector<Real>> referenceFixings;
333 referenceFixings[
"11,1Y"] = {0.00739033, 0.0281673, 0.0344399, 0.03362, 0.0325276, 0.030573,
334 0.00895957, 0.0165584, 0.0194418, 0.0112834, 0.0239227};
337 referenceFixings[
"10,1Y"] = {0.00739033, 0.0296998, 0.0339535, 0.012449, 0.0134939, 0.0148095,
338 0.0188541, 0.0277254, 0.035063, 0.0105228, 0.0103237};
340 if (simMarket->aggregationScenarioData()) {
341 QL_REQUIRE(dateGridString ==
"10,1Y" || dateGridString ==
"11,1Y",
342 "date grid string " << dateGridString <<
" unexpected");
346 string qualifier =
"EUR-EURIBOR-6M";
347 Real tolerance = 1.0e-6;
348 for (Size sampleIndex = 0; sampleIndex <= maxSample; ++sampleIndex) {
349 Real fix = simMarket->aggregationScenarioData()->get(dateIndex, sampleIndex,
350 AggregationScenarioDataType::IndexFixing, qualifier);
351 Real ref = referenceFixings[dateGridString][sampleIndex];
352 if (fabs(fix - ref) > tolerance)
353 BOOST_FAIL(
"Stored fixing differs from reference value, found " << fix <<
", expected " << ref);
360BOOST_AUTO_TEST_SUITE(ObservationModeTest)
363 ObservationMode::instance().setMode(ObservationMode::Mode::Disable);
366 BOOST_TEST_MESSAGE(
"Testing Observation Mode Disable, Short Grid, No Fixing Checks");
369 BOOST_TEST_MESSAGE(
"Testing Observation Mode Disable, Short Grid, With Fixing Checks");
374 ObservationMode::instance().setMode(ObservationMode::Mode::Disable);
377 BOOST_TEST_MESSAGE(
"Testing Observation Mode Disable, Long Grid, No Fixing Checks");
380 BOOST_TEST_MESSAGE(
"Testing Observation Mode Disable, Long Grid, With Fixing Checks");
385 ObservationMode::instance().setMode(ObservationMode::Mode::None);
388 BOOST_TEST_MESSAGE(
"Testing Observation Mode None, Short Grid, No Fixing Checks");
391 BOOST_TEST_MESSAGE(
"Testing Observation Mode None, Short Grid, With Fixing Checks");
394 BOOST_TEST_MESSAGE(
"Testing Observation Mode None, Long Grid, No Fixing Checks");
397 BOOST_TEST_MESSAGE(
"Testing Observation Mode None, Long Grid, With Fixing Checks");
402 ObservationMode::instance().setMode(ObservationMode::Mode::Unregister);
405 BOOST_TEST_MESSAGE(
"Testing Observation Mode Unregister, Long Grid, No Fixing Checks");
408 BOOST_TEST_MESSAGE(
"Testing Observation Mode Unregister, Long Grid, With Fixing Checks");
411 BOOST_TEST_MESSAGE(
"Testing Observation Mode Unregister, Short Grid, No Fixing Checks");
414 BOOST_TEST_MESSAGE(
"Testing Observation Mode Unregister, Short Grid, With Fixing Checks");
419 ObservationMode::instance().setMode(ObservationMode::Mode::Defer);
422 BOOST_TEST_MESSAGE(
"Testing Observation Mode Defer, Long Grid, No Fixing Checks");
425 BOOST_TEST_MESSAGE(
"Testing Observation Mode Defer, Long Grid, With Fixing Checks");
428 BOOST_TEST_MESSAGE(
"Testing Observation Mode Defer, Short Grid, No Fixing Checks");
431 BOOST_TEST_MESSAGE(
"Testing Observation Mode Defer, Short Grid, With Fixing Checks");
435BOOST_AUTO_TEST_SUITE_END()
437BOOST_AUTO_TEST_SUITE_END()
ScenarioSimMarket description.
void buildCube(const QuantLib::ext::shared_ptr< data::Portfolio > &portfolio, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCube, std::vector< QuantLib::ext::shared_ptr< ValuationCalculator > > calculators, bool mporStickyDate=true, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCubeNettingSet=nullptr, QuantLib::ext::shared_ptr< analytics::NPVCube > outputCptyCube=nullptr, std::vector< QuantLib::ext::shared_ptr< CounterpartyCalculator > > cptyCalculators={}, bool dryRun=false)
Build NPV cube.
OREAnalytics Top level fixture.
Simple flat market setup to be used in the test suite.
Scenario generation using cross asset model paths.
Class that wraps a sensitivity stream and filters out negligible records.
A cube implementation that stores the cube in memory.
BOOST_AUTO_TEST_CASE(testDisableShort)
void simulation(string dateGridString, bool checkFixings)
QuantLib::ext::shared_ptr< Portfolio > buildPortfolio(QuantLib::ext::shared_ptr< EngineFactory > &factory)
Singleton class to hold global Observation Mode.
Fixture that can be used at top level of OREAnalytics test suites.
Perform parametric var calculation for a given portfolio.
risk class and type filter
A Market class that can be updated by Scenarios.
A class to hold Scenario parameters for scenarioSimMarket.
Class for aggregating SensitivityRecords.
Perform sensitivity analysis for a given portfolio.
Class for streaming SensitivityRecords from a SensitivityCube.
Class for streaming SensitivityRecords from file.
Class for streaming SensitivityRecords from in-memory container.
Struct for holding a sensitivity record.
Base class for sensitivity record streamer.
factory classes for simple scenarios
perform a stress testing analysis for a given portfolio.
The counterparty cube calculator interface.