264 {
265
266 QuantLib::ext::shared_ptr<Portfolio> portfolio(
new Portfolio());
267
268 vector<string> ccys = {"EUR", "USD", "GBP", "JPY", "CHF"};
269
270 map<string, vector<string>> indices = {{"EUR", {"EUR-EURIBOR-6M"}},
271 {"USD", {"USD-LIBOR-3M"}},
272 {"GBP", {"GBP-LIBOR-6M"}},
273 {"CHF", {"CHF-LIBOR-6M"}},
274 {"JPY", {"JPY-LIBOR-6M"}}};
275
276 vector<string> fixedTenors = {"6M", "1Y"};
277
278 Size minTerm = 2;
279 Size maxTerm = 30;
280
281 Size minFixedBps = 10;
282 Size maxFixedBps = 400;
283
284 Size seed = 5;
285 MersenneTwisterUniformRng rng(seed);
286
287 Date today = Settings::instance().evaluationDate();
288 Calendar cal = TARGET();
289 string calStr = "TARGET";
290 string conv = "MF";
291 string rule = "Forward";
292 Size days = 2;
293 string fixDC = "30/360";
294 string floatDC = "ACT/365";
295
296 vector<double> notional(1, 1000000);
297 vector<double> spread(1, 0);
298
299 for (Size i = 0; i < portfolioSize; i++) {
300 Size term = portfolioSize == 1 ? 20 :
randInt(rng, minTerm, maxTerm);
301
302
303 Date startDate = portfolioSize == 1 ? cal.adjust(today) : cal.adjust(today - 365 +
randInt(rng, 0, 730));
304 Date endDate = cal.adjust(startDate + term * Years);
305
306
307 std::ostringstream oss;
308 oss << io::iso_date(startDate);
309 string start(oss.str());
310 oss.str("");
311 oss.clear();
312 oss << io::iso_date(endDate);
313 string end(oss.str());
314
315
316 string ccy = portfolioSize == 1 ?
"EUR" :
randString(rng, ccys);
317 string index = portfolioSize == 1 ?
"EUR-EURIBOR-6M" :
randString(rng, indices[ccy]);
318 string floatFreq = portfolioSize == 1 ? "6M" : index.substr(index.find('-', 4) + 1);
319
320
321 Real fixedRate = portfolioSize == 1 ? 0.02 :
randInt(rng, minFixedBps, maxFixedBps) / 100.0;
322 string fixFreq = portfolioSize == 1 ?
"1Y" :
randString(rng, fixedTenors);
323
324
326
327
330
332
333
334 LegData fixedLeg(QuantLib::ext::make_shared<FixedLegData>(vector<double>(1, fixedRate)), isPayer, ccy, fixedSchedule,
335 fixDC, notional);
336
337
338 vector<double> spreads(1, 0);
339 LegData floatingLeg(QuantLib::ext::make_shared<FloatingLegData>(index, days,
false, spread), !isPayer, ccy,
340 floatSchedule, floatDC, notional);
341
342 QuantLib::ext::shared_ptr<Trade> swap(
new ore::data::Swap(env, floatingLeg, fixedLeg));
343
344
345 oss.clear();
346 oss.str("");
347 oss << "Trade_" << i + 1;
348 swap->id() = oss.str();
349
350 portfolio->add(swap);
351 }
352
353
354 portfolio->build(factory);
355
356 if (portfolio->size() != portfolioSize)
357 BOOST_ERROR("Failed to build portfolio (got " << portfolio->size() << " expected " << portfolioSize << ")");
358
359
361 DayCounter dc = ActualActual(ActualActual::ISDA);
362 map<string, Size> fixedFreqs;
363 map<string, Size> floatFreqs;
364 for (const auto& [tradeId, trade] : portfolio->trades()) {
365 maturity += dc.yearFraction(today, trade->maturity());
366
367
368 QuantLib::ext::shared_ptr<ore::data::Swap> swap = QuantLib::ext::dynamic_pointer_cast<ore::data::Swap>(trade);
369 string floatFreq = swap->legData()[0].schedule().rules().front().tenor();
370 string fixFreq = swap->legData()[1].schedule().rules().front().tenor();
371 QL_REQUIRE(swap->legData()[0].legType() == "Floating" && swap->legData()[1].legType() == "Fixed", "Leg mixup");
372 if (fixedFreqs.find(fixFreq) == fixedFreqs.end())
373 fixedFreqs[fixFreq] = 1;
374 else
375 fixedFreqs[fixFreq]++;
376 if (floatFreqs.find(floatFreq) == floatFreqs.end())
377 floatFreqs[floatFreq] = 1;
378 else
379 floatFreqs[floatFreq]++;
380 }
382 BOOST_TEST_MESSAGE("Portfolio Size : " << portfolioSize);
383 BOOST_TEST_MESSAGE("Average Maturity : " << maturity);
384 std::ostringstream oss;
385 for (Size i = 0; i < ccys.size(); i++)
386 oss << ccys[i] << " ";
387 BOOST_TEST_MESSAGE("Currencies : " << oss.str());
388
389 map<string, Size>::iterator it;
390 BOOST_TEST_MESSAGE("Fixed Tenors : ");
391 for (it = fixedFreqs.begin(); it != fixedFreqs.end(); ++it) {
392 Real perc = 100 * it->second / (Real)portfolioSize;
393 BOOST_TEST_MESSAGE(" " << it->first << " " << perc << " %");
394 }
395 BOOST_TEST_MESSAGE("Floating Tenors : ");
396 for (it = floatFreqs.begin(); it != floatFreqs.end(); ++it) {
397 Real perc = 100 * it->second / (Real)portfolioSize;
398 BOOST_TEST_MESSAGE(" " << it->first << " " << perc << " %");
399 }
400
401 return portfolio;
402}
bool randBoolean(MersenneTwisterUniformRng &rng)
const string & randString(MersenneTwisterUniformRng &rng, const vector< string > &strs)