27#include <boost/range/adaptor/indexed.hpp>
36using QuantLib::io::iso_date;
46 const string& baseCurrency,
const QuantLib::ext::shared_ptr<Portfolio>& portfolio,
47 const QuantLib::ext::shared_ptr<ScenarioSimMarket>& simMarket,
48 const QuantLib::ext::shared_ptr<HistoricalScenarioGenerator>& hisScenGen,
const QuantLib::ext::shared_ptr<NPVCube>& cube,
49 const set<std::pair<
string, QuantLib::ext::shared_ptr<QuantExt::ModelBuilder>>>& modelBuilders,
bool dryRun)
50 : useSingleThreadedEngine_(true), portfolio_(portfolio), simMarket_(simMarket), hisScenGen_(hisScenGen),
51 cube_(cube), dryRun_(dryRun),
52 npvCalculator_([&baseCurrency]() -> std::vector<
QuantLib::ext::shared_ptr<ValuationCalculator>> {
53 return {QuantLib::ext::make_shared<NPVCalculator>(baseCurrency)};
58 QL_REQUIRE(cube_->asof() == simMarket_->asofDate(),
59 "The cube's as of date (" << iso_date(cube_->asof()) <<
") should equal that of the simulation market ("
60 << iso_date(simMarket_->asofDate()) <<
")");
62 std::set<std::string> cubeIds;
63 for (
const auto& [
id, pos] : cube->idsAndIndexes()) {
66 QL_REQUIRE(cubeIds == portfolio_->ids(),
"The cube ids should equal the portfolio ids");
67 QL_REQUIRE(cube_->samples() == hisScenGen_->numScenarios(),
68 "The cube sample size (" << cube_->samples() <<
") should equal the number of historical scenarios ("
69 << hisScenGen_->numScenarios() <<
")");
70 QL_REQUIRE(cube_->numDates() == 1,
"The cube should have exactly one date");
71 QL_REQUIRE(cube_->depth() == 1,
"The cube should have a depth of one");
73 simMarket_->scenarioGenerator() = hisScenGen_;
75 auto grid = QuantLib::ext::make_shared<DateGrid>();
76 valuationEngine_ = QuantLib::ext::make_shared<ValuationEngine>(simMarket_->asofDate(), grid, simMarket_, modelBuilders);
79HistoricalPnlGenerator::HistoricalPnlGenerator(
80 const string& baseCurrency,
const QuantLib::ext::shared_ptr<Portfolio>& portfolio,
81 const QuantLib::ext::shared_ptr<HistoricalScenarioGenerator>& hisScenGen,
const QuantLib::ext::shared_ptr<EngineData>& engineData,
82 const Size nThreads,
const Date& today,
const QuantLib::ext::shared_ptr<ore::data::Loader>& loader,
83 const QuantLib::ext::shared_ptr<ore::data::CurveConfigurations>& curveConfigs,
84 const QuantLib::ext::shared_ptr<ore::data::TodaysMarketParameters>& todaysMarketParams,
const std::string& configuration,
85 const QuantLib::ext::shared_ptr<ore::analytics::ScenarioSimMarketParameters>& simMarketData,
86 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceData,
const IborFallbackConfig& iborFallbackConfig,
87 bool dryRun,
const std::string& context)
88 : useSingleThreadedEngine_(false), portfolio_(portfolio), hisScenGen_(hisScenGen), engineData_(engineData),
89 nThreads_(nThreads), today_(today), loader_(loader), curveConfigs_(
curveConfigs),
90 todaysMarketParams_(todaysMarketParams), configuration_(configuration), simMarketData_(simMarketData),
91 referenceData_(referenceData), iborFallbackConfig_(iborFallbackConfig), dryRun_(dryRun),
context_(context),
92 npvCalculator_([&baseCurrency]() -> std::vector<
QuantLib::ext::shared_ptr<ValuationCalculator>> {
93 return {QuantLib::ext::make_shared<NPVCalculator>(baseCurrency)};
96void HistoricalPnlGenerator::generateCube(
const QuantLib::ext::shared_ptr<ScenarioFilter>& filter) {
98 DLOG(
"Filling historical P&L cube for " << portfolio_->size() <<
" trades and " << hisScenGen_->numScenarios()
101 if (useSingleThreadedEngine_) {
103 valuationEngine_->unregisterAllProgressIndicators();
104 for (
auto const& i : this->progressIndicators()) {
106 valuationEngine_->registerProgressIndicator(i);
109 hisScenGen_->reset();
110 simMarket_->filter() =
filter;
112 simMarket_->scenarioGenerator() = hisScenGen_;
113 hisScenGen_->baseScenario() = simMarket_->baseScenario();
114 valuationEngine_->buildCube(portfolio_, cube_, npvCalculator_(),
true,
nullptr,
nullptr, {}, dryRun_);
118 nThreads_, today_, QuantLib::ext::make_shared<ore::analytics::DateGrid>(), hisScenGen_->numScenarios(), loader_,
119 hisScenGen_, engineData_, curveConfigs_, todaysMarketParams_, configuration_, simMarketData_,
false,
false,
120 filter, referenceData_, iborFallbackConfig_,
true,
true,
true, {}, {}, {},
context_);
121 for (
auto const& i : this->progressIndicators()) {
125 engine.
buildCube(portfolio_, npvCalculator_, {},
true, dryRun_);
126 cube_ = QuantLib::ext::make_shared<JointNPVCube>(engine.
outputCubes(), portfolio_->ids(),
true);
129 DLOG(
"Historical P&L cube generated");
132vector<Real> HistoricalPnlGenerator::pnl(
const TimePeriod& period,
const set<pair<string, Size>>& tradeIds)
const {
136 pnls.reserve(cube_->samples());
139 Size dateIdx = indexAsof();
141 for (Size s = 0; s < cube_->samples(); ++s) {
143 Date start = hisScenGen_->startDates()[s];
144 Date end = hisScenGen_->endDates()[s];
148 for (
const auto& tradeId : tradeIds) {
149 pnl -= cube_->getT0(tradeId.second);
150 pnl += cube_->get(tradeId.second, dateIdx, s);
156 pnls.shrink_to_fit();
161vector<Real> HistoricalPnlGenerator::pnl(
const TimePeriod& period)
const {
return pnl(period, tradeIdIndexPairs()); }
163vector<Real> HistoricalPnlGenerator::pnl(
const set<pair<string, Size>>& tradeIds)
const {
164 return pnl(timePeriod(), tradeIds);
167vector<Real> HistoricalPnlGenerator::pnl()
const {
return pnl(timePeriod()); }
172 const set<pair<string, Size>>& tradeIds)
const {
176 pnls.reserve(cube_->samples());
179 Size dateIdx = indexAsof();
183 t0Npvs.reserve(tradeIds.size());
185 for (Size s = 0; s < cube_->samples(); ++s) {
188 Date start = hisScenGen_->startDates()[s];
189 Date end = hisScenGen_->endDates()[s];
194 if (t0Npvs.empty()) {
195 for (
const auto& p : tradeIds) {
196 t0Npvs.push_back(cube_->getT0(p.second));
201 pnls.push_back(vector<Real>(tradeIds.size(), 0.0));
204 for (
const auto elem : tradeIds | boost::adaptors::indexed(0)) {
205 auto idx = elem.index();
206 pnls.back()[idx] = cube_->get(elem.value().second, dateIdx, s) - t0Npvs[idx];
211 pnls.shrink_to_fit();
217 return tradeLevelPnl(period, tradeIdIndexPairs());
220TradePnlStore HistoricalPnlGenerator::tradeLevelPnl(
const set<pair<string, Size>>& tradeIds)
const {
221 return tradeLevelPnl(timePeriod(), tradeIds);
224TradePnlStore HistoricalPnlGenerator::tradeLevelPnl()
const {
return tradeLevelPnl(timePeriod()); }
226const QuantLib::ext::shared_ptr<NPVCube>& HistoricalPnlGenerator::cube()
const {
return cube_; }
228set<pair<string, Size>> HistoricalPnlGenerator::tradeIdIndexPairs()
const {
229 set<pair<string, Size>> res;
231 for (
const auto& [
id, trade]: portfolio_->trades())
232 res.insert(std::make_pair(
id, i++));
237 vector<Date> dates{hisScenGen_->
startDates().front(), hisScenGen_->endDates().back()};
241Size HistoricalPnlGenerator::indexAsof()
const {
242 Date
asof = useSingleThreadedEngine_ ? simMarket_->asofDate() : today_;
243 const auto& dates = cube_->dates();
244 auto it = std::find(dates.begin(), dates.end(),
asof);
245 QL_REQUIRE(it != dates.end(),
"Can't find an index for asof date " <<
asof <<
" in cube");
246 return std::distance(dates.begin(), it);
std::vector< std::vector< QuantLib::Real > > TradePnlStore
HistoricalPnlGenerator(const std::string &baseCurrency, const QuantLib::ext::shared_ptr< ore::data::Portfolio > &portfolio, const QuantLib::ext::shared_ptr< ScenarioSimMarket > &simMarket, const QuantLib::ext::shared_ptr< HistoricalScenarioGenerator > &hisScenGen, const QuantLib::ext::shared_ptr< NPVCube > &cube, const set< std::pair< string, QuantLib::ext::shared_ptr< QuantExt::ModelBuilder > > > &modelBuilders={}, bool dryRun=false)
std::vector< QuantLib::ext::shared_ptr< ore::analytics::NPVCube > > outputCubes() const
void buildCube(const QuantLib::ext::shared_ptr< ore::data::Portfolio > &portfolio, const std::function< std::vector< QuantLib::ext::shared_ptr< ore::analytics::ValuationCalculator > >()> &calculators, const std::function< std::vector< QuantLib::ext::shared_ptr< ore::analytics::CounterpartyCalculator > >()> &cptyCalculators={}, bool mporStickyDate=true, bool dryRun=false)
void registerProgressIndicator(const QuantLib::ext::shared_ptr< ProgressIndicator > &indicator)
const std::vector< Date > & startDates() const
bool contains(const Date &d) const
SafeStack< Filter > filter
Class for generating portfolio P&Ls based on historical scenarios.
A cube implementation that stores the cube in memory.
join n cubes in terms of stored ids
multi-threaded valuation engine
HistoricalPnlGenerator::TradePnlStore TradePnlStore
vector< string > curveConfigs
The counterparty cube calculator interface.