88 ORE is free software: you can redistribute it and/or modify it
99 under the terms of the Modified BSD License. You should have received a
1010 copy of the license along with this program.
11- The license is also available online at <http://opensourcerisk.org>
11+ pr The license is also available online at <http://opensourcerisk.org>
1212
1313 This program is distributed on the basis that it will form a useful
1414 contribution to risk analytics and model standardisation, but WITHOUT
@@ -31,107 +31,100 @@ namespace analytics {
3131using crossPair = SensitivityCube::crossPair;
3232
3333SensitivityCubeStream::SensitivityCubeStream (const boost::shared_ptr<SensitivityCube>& cube, const string& currency)
34- : cube_(cube), currency_(currency), upRiskFactor_(cube_->upFactors ().begin()),
35- downRiskFactor_(cube_->downFactors ().begin()), itCrossPair_(cube_->crossFactors ().begin()),
36- tradeIdx_(cube_->tradeIdx ().begin()), canComputeGamma_(false ) {
34+ : cube_(cube), currency_(currency), canComputeGamma_(false ) {
3735
3836 // Set the value of canComputeGamma_ based on up and down risk factors.
3937 const auto & upFactors = cube_->upFactors ();
4038 const auto & downFactors = cube_->downFactors ();
4139 if (upFactors.size () == downFactors.size ()) {
42- auto pred = [](decltype (*upFactors.left .begin ()) a, pair<RiskFactorKey, SensitivityCube::FactorData> b) {
43- return a.first == b.first ;
44- };
45- canComputeGamma_ = equal (upFactors.left .begin (), upFactors.left .end (), downFactors.begin (), pred);
40+ canComputeGamma_ = equal (upFactors.begin (), upFactors.end (), downFactors.begin (),
41+ [](const auto & a, const auto & b) { return a.first == b.first ; });
4642 }
43+
44+ reset ();
4745}
4846
4947SensitivityRecord SensitivityCubeStream::next () {
5048
51- SensitivityRecord sr;
49+ while (tradeIdx_ != cube_->tradeIdx ().end () && currentDeltaKey_ == currentDeltaKeys_.end () &&
50+ currentCrossGammaKey_ == currentCrossGammaKeys_.end ()) {
51+ ++tradeIdx_;
52+ updateForNewTrade ();
53+ }
5254
53- const auto & upFactors = cube_->upFactors ();
54- const auto & downFactors = cube_-> downFactors ();
55+ if (tradeIdx_ == cube_->tradeIdx (). end ())
56+ return SensitivityRecord ();
5557
56- // If exhausted deltas, gammas AND cross gammas, update to next trade and reset iterators
57- if (upRiskFactor_ == upFactors.end () && itCrossPair_ == cube_->crossFactors ().end ()) {
58- tradeIdx_++;
59- upRiskFactor_ = upFactors.begin ();
60- downRiskFactor_ = downFactors.begin ();
61- itCrossPair_ = cube_->crossFactors ().begin ();
58+ SensitivityRecord sr;
59+ Size tradeIdx = tradeIdx_->second ;
60+ sr.tradeId = tradeIdx_->first ;
61+ sr.isPar = false ;
62+ sr.currency = currency_;
63+ sr.baseNpv = cube_->npv (tradeIdx);
64+
65+ if (currentDeltaKey_ != currentDeltaKeys_.end ()) {
66+ auto fd = cube_->upFactors ().at (*currentDeltaKey_);
67+ sr.key_1 = *currentDeltaKey_;
68+ sr.desc_1 = fd.factorDesc ;
69+ sr.shift_1 = fd.shiftSize ;
70+ sr.delta = cube_->delta (tradeIdx_->first , *currentDeltaKey_);
71+ if (canComputeGamma_)
72+ sr.gamma = cube_->gamma (tradeIdx_->first , *currentDeltaKey_);
73+ else
74+ sr.gamma = Null<Real>();
75+ ++currentDeltaKey_;
76+ } else if (currentCrossGammaKey_ != currentCrossGammaKeys_.end ()) {
77+ auto fd = cube_->crossFactors ().at (*currentCrossGammaKey_);
78+ sr.key_1 = currentCrossGammaKey_->first ;
79+ sr.desc_1 = std::get<0 >(fd).factorDesc ;
80+ sr.shift_1 = std::get<0 >(fd).shiftSize ;
81+ sr.key_2 = currentCrossGammaKey_->second ;
82+ sr.desc_2 = std::get<1 >(fd).factorDesc ;
83+ sr.shift_2 = std::get<1 >(fd).shiftSize ;
84+ sr.gamma = cube_->crossGamma (tradeIdx_->first , *currentCrossGammaKey_);
85+ ++currentCrossGammaKey_;
6286 }
6387
64- // Give back next record if we have a valid trade index
65- if (tradeIdx_ != cube_->tradeIdx ().end ()) {
66- Size tradeIdx = tradeIdx_->second ;
67- sr.tradeId = tradeIdx_->first ;
68- sr.isPar = false ;
69- sr.currency = currency_;
70- sr.baseNpv = cube_->npv (tradeIdx);
71-
72- // Are there more deltas and gammas for current trade ID
73- if (upRiskFactor_ != upFactors.end ()) {
74- Size usrx = upRiskFactor_->right .index ;
75- sr.key_1 = upRiskFactor_->left ;
76- sr.desc_1 = upRiskFactor_->right .factorDesc ;
77- sr.shift_1 = upRiskFactor_->right .shiftSize ;
78-
79- if (!cube_->twoSidedDelta (sr.key_1 .keytype )) {
80- sr.delta = cube_->delta (tradeIdx, usrx);
81- } else {
82- Size downIdx = downFactors.at (sr.key_1 ).index ;
83- sr.delta = cube_->delta (tradeIdx, usrx, downIdx);
84- }
85-
86- if (canComputeGamma_ && downRiskFactor_ != downFactors.end ()) {
87- Size dsrx = downRiskFactor_->second .index ;
88- sr.gamma = cube_->gamma (tradeIdx, usrx, dsrx);
89- downRiskFactor_++;
90- } else {
91- sr.gamma = Null<Real>(); // marks na result
92- }
88+ TLOG (" Next record is: " << sr);
89+ return sr;
90+ }
9391
94- upRiskFactor_++;
92+ void SensitivityCubeStream::updateForNewTrade () {
93+ currentDeltaKeys_.clear ();
94+ currentCrossGammaKeys_.clear ();
9595
96- TLOG (" Next record is: " << sr);
97- return sr;
98- }
96+ if (tradeIdx_ != cube_->tradeIdx ().end ()) {
9997
100- // Are there more cross pairs for current trade ID
101- if (itCrossPair_ != cube_->crossFactors ().end ()) {
102- sr.key_1 = itCrossPair_->first .first ;
103- sr.desc_1 = std::get<0 >(itCrossPair_->second ).factorDesc ;
104- sr.shift_1 = std::get<0 >(itCrossPair_->second ).shiftSize ;
98+ // add delta keys
10599
106- sr.key_2 = itCrossPair_->first .second ;
107- sr.desc_2 = std::get<1 >(itCrossPair_->second ).factorDesc ;
108- sr.shift_2 = std::get<1 >(itCrossPair_->second ).shiftSize ;
100+ for (auto const & [idx, _] : cube_->npvCube ()->getTradeNPVs (tradeIdx_->second )) {
101+ if (auto k = cube_->upDownFactor (idx); k.keytype != RiskFactorKey::KeyType::None)
102+ currentDeltaKeys_.insert (k);
103+ }
109104
110- Size id_1, id_2, id_x;
111- id_1 = std::get<0 >(itCrossPair_->second ).index ;
112- id_2 = std::get<1 >(itCrossPair_->second ).index ;
113- id_x = std::get<2 >(itCrossPair_->second );
105+ // add cross gamma keys
114106
115- sr.gamma = cube_->crossGamma (tradeIdx, id_1, id_2, id_x);
107+ for (auto const & [crossPair, data] : cube_->crossFactors ()) {
108+ if (!close_enough (cube_->crossGamma (tradeIdx_->second , std::get<0 >(data).index , std::get<1 >(data).index ,
109+ std::get<2 >(data)),
110+ 0.0 )) {
111+ currentCrossGammaKeys_.insert (crossPair);
116112
117- itCrossPair_++;
113+ // make sure, delta keys contain both cross keys, that's a guarantee of the SensitivityCubeStream
118114
119- TLOG (" Next record is: " << sr);
120- return sr;
115+ currentDeltaKeys_.insert (crossPair.first );
116+ currentDeltaKeys_.insert (crossPair.second );
117+ }
121118 }
122119 }
123120
124- // If we get to here, no more cube sensitivities to process so return empty record
125- TLOG (" Next record is: " << sr);
126- return sr;
121+ currentDeltaKey_ = currentDeltaKeys_.begin ();
122+ currentCrossGammaKey_ = currentCrossGammaKeys_.begin ();
127123}
128124
129125void SensitivityCubeStream::reset () {
130- // Reset indices and iterators
131126 tradeIdx_ = cube_->tradeIdx ().begin ();
132- upRiskFactor_ = cube_->upFactors ().begin ();
133- downRiskFactor_ = cube_->downFactors ().begin ();
134- itCrossPair_ = cube_->crossFactors ().begin ();
127+ updateForNewTrade ();
135128}
136129
137130} // namespace analytics
0 commit comments