@@ -257,7 +257,6 @@ RiskFactorPnLSeries HistoricalPnlGenerator::riskFactorLevelPnlSeries(const ore::
257257 return series;
258258 }
259259
260- // Build per-scenario maps for scenarios within the period
261260 // Determine how many scenarios we have from any cube in the map
262261 Size samples = mapCube_.begin ()->second ->samples ();
263262 series.resize (samples);
@@ -269,29 +268,36 @@ RiskFactorPnLSeries HistoricalPnlGenerator::riskFactorLevelPnlSeries(const ore::
269268 if (!(period.contains (start) && period.contains (end))) {
270269 continue ; // leave this scenario's map empty
271270 }
272- // Aggregate PnL across trades and collapse duplicates by risk factor name
273- std::unordered_map<std::string, std::pair<RiskFactorKey, Real>> byName;
271+ // Aggregate PnL per trade and collapse duplicates by risk factor name
272+ // Map: rf name -> (representative key, per-trade pnl vector)
273+ std::unordered_map<std::string, std::pair<RiskFactorKey, std::vector<Real>>> byName;
274274 for (const auto & kv : mapCube_) {
275275 const RiskFactorKey& rfKey = kv.first ;
276276 const ext::shared_ptr<NPVCube>& rfCube = kv.second ;
277- Real pnl = 0.0 ;
278277 Size tradeCount = rfCube->numIds ();
278+ std::vector<Real> pnlVec (tradeCount, 0.0 );
279+ bool anyNonZero = false ;
279280 for (Size i = 0 ; i < tradeCount; ++i) {
280- pnl += rfCube->get (i, dateIdx, s) - rfCube->getT0 (i);
281+ Real v = rfCube->get (i, dateIdx, s) - rfCube->getT0 (i);
282+ pnlVec[i] = v;
283+ anyNonZero = anyNonZero || (v != 0.0 );
281284 }
282- if (pnl == 0.0 )
285+ if (!anyNonZero )
283286 continue ;
284287 auto it = byName.find (rfKey.name );
285288 if (it == byName.end ()) {
286- byName.emplace (rfKey.name , std::make_pair (rfKey, pnl ));
289+ byName.emplace (rfKey.name , std::make_pair (rfKey, std::move (pnlVec) ));
287290 } else {
288- it->second .second += pnl;
291+ auto & aggVec = it->second .second ;
292+ if (aggVec.size () < pnlVec.size ())
293+ aggVec.resize (pnlVec.size (), 0.0 );
294+ for (Size i = 0 ; i < pnlVec.size (); ++i)
295+ aggVec[i] += pnlVec[i];
289296 }
290297 }
291- // Write one entry per risk factor name into the scenario map
292- for (const auto & e : byName) {
293- series[s].emplace (e.second .first , e.second .second );
294- }
298+ for (auto & e : byName) {
299+ series[s].emplace (e.second .first , std::move (e.second .second ));
300+ }
295301 }
296302
297303 return series;
0 commit comments