@@ -57,17 +57,16 @@ std::ostream& operator<<(std::ostream& out, const SensitivityCube::crossPair& cp
5757SensitivityCube::SensitivityCube (const boost::shared_ptr<NPVSensiCube>& cube,
5858 const vector<ShiftScenarioDescription>& scenarioDescriptions,
5959 const map<RiskFactorKey, QuantLib::Real>& shiftsizes,
60- const set<RiskFactorKey::KeyType>& twoSidedDeltas)
61- : cube_(cube), scenarioDescriptions_(scenarioDescriptions), shiftSizes_(shiftsizes),
62- twoSidedDeltas_ (twoSidedDeltas) {
60+ const std::map<RiskFactorKey, ShiftScheme>& shiftSchemes)
61+ : cube_(cube), scenarioDescriptions_(scenarioDescriptions), shiftSizes_(shiftsizes), shiftSchemes_(shiftSchemes) {
6362 initialise ();
6463}
6564
6665SensitivityCube::SensitivityCube (const boost::shared_ptr<NPVSensiCube>& cube,
6766 const vector<string>& scenarioDescriptions,
6867 const map<RiskFactorKey, QuantLib::Real>& shiftsizes,
69- const set<RiskFactorKey::KeyType >& twoSidedDeltas )
70- : cube_(cube), shiftSizes_(shiftsizes), twoSidedDeltas_(twoSidedDeltas ) {
68+ const std::map<RiskFactorKey, ShiftScheme >& shiftSchemes )
69+ : cube_(cube), shiftSizes_(shiftsizes), shiftSchemes_(shiftSchemes ) {
7170
7271 // Populate scenarioDescriptions_ from string descriptions
7372 scenarioDescriptions_.reserve (scenarioDescriptions.size ());
@@ -79,6 +78,7 @@ SensitivityCube::SensitivityCube(const boost::shared_ptr<NPVSensiCube>& cube,
7978}
8079
8180void SensitivityCube::initialise () {
81+
8282 QL_REQUIRE (scenarioDescriptions_[0 ].type () == ShiftScenarioDescription::Type::Base,
8383 " Expected the first scenario in the sensitivity cube to be of type 'Base'" );
8484
@@ -110,6 +110,7 @@ void SensitivityCube::initialise() {
110110 QL_REQUIRE (downFactors_.count (des.key1 ()) == 0 , " Cannot have multiple down factors with "
111111 " the same risk factor key ["
112112 << des.key1 () << " ]" );
113+ factors_.insert (des.key1 ());
113114 downFactors_[des.key1 ()] = fd;
114115 downIndexToKey_[fd.index ] = des.key1 ();
115116 break ;
@@ -135,34 +136,26 @@ void SensitivityCube::initialise() {
135136 }
136137
137138 // Log warnings if each factor does not have a shift size entry and that it is not a Null<Real>()
138- if (upFactors_.size () != shiftSizes_.size ()) {
139- WLOG (" The number of 'Up' shifts (" << upFactors_.size () << " ) does not equal "
140- << " the number of shift sizes (" << shiftSizes_.size () << " ) supplied" );
139+ if (factors_.size () != shiftSizes_.size ()) {
140+ WLOG (" The number of factors from up / down shifts (" << factors_.size () << " ) does not equal "
141+ << " the number of shift sizes (" << shiftSizes_.size ()
142+ << " ) supplied" );
141143 }
142144
143- for (auto const & kv : upFactors_ ) {
144- auto it = shiftSizes_.find (kv. first );
145+ for (auto const & f : factors_ ) {
146+ auto it = shiftSizes_.find (f );
145147 if (it == shiftSizes_.end ()) {
146- WLOG (" No entry for risk factor " << kv.first << " in shift sizes." );
147- }
148- if (it->second == Null<Real>()) {
149- WLOG (" The shift size for risk factor " << kv.first << " is not valid." )
148+ WLOG (" No entry for risk factor " << f << " in shift sizes." );
150149 }
151150 }
152151}
153152
154153bool SensitivityCube::hasTrade (const string& tradeId) const { return tradeIdx_.count (tradeId) > 0 ; }
155154
156- RiskFactorKey SensitivityCube::upFactor (const Size upIndex ) const {
157- if (auto k = upIndexToKey_.find (upIndex ); k != upIndexToKey_.end ()) {
155+ RiskFactorKey SensitivityCube::upDownFactor (const Size index ) const {
156+ if (auto k = upIndexToKey_.find (index ); k != upIndexToKey_.end ()) {
158157 return k->second ;
159- } else {
160- return RiskFactorKey ();
161- }
162- }
163-
164- RiskFactorKey SensitivityCube::downFactor (const Size downIndex) const {
165- if (auto k = downIndexToKey_.find (downIndex); k != downIndexToKey_.end ()) {
158+ } else if (auto k = downIndexToKey_.find (index); k != downIndexToKey_.end ()) {
166159 return k->second ;
167160 } else {
168161 return RiskFactorKey ();
@@ -178,7 +171,7 @@ SensitivityCube::crossPair SensitivityCube::crossFactor(const Size crossIndex) c
178171}
179172
180173bool SensitivityCube::hasScenario (const ShiftScenarioDescription& scenarioDescription) const {
181- return scenarioIdx_.count (scenarioDescription) > 0 ;
174+ return scenarioIdx_.find (scenarioDescription) != scenarioIdx_. end () ;
182175}
183176
184177std::string SensitivityCube::factorDescription (const RiskFactorKey& riskFactorKey) const {
@@ -199,6 +192,12 @@ Real SensitivityCube::shiftSize(const RiskFactorKey& riskFactorKey) const {
199192 return it->second ;
200193}
201194
195+ ShiftScheme SensitivityCube::shiftScheme (const RiskFactorKey& riskFactorKey) const {
196+ auto it = shiftSchemes_.find (riskFactorKey);
197+ QL_REQUIRE (it != shiftSchemes_.end (), " Risk factor, " << riskFactorKey << " , was not found in the shift schemes." );
198+ return it->second ;
199+ }
200+
202201Real SensitivityCube::npv (const string& tradeId) const { return cube_->getT0 (tradeId, 0 ); }
203202
204203Real SensitivityCube::npv (Size id) const { return cube_->getT0 (id, 0 ); }
@@ -211,77 +210,76 @@ Real SensitivityCube::npv(const string& tradeId, const ShiftScenarioDescription&
211210 return npv (tradeIdx, scenarioIdx);
212211}
213212
214- Real SensitivityCube::delta (Size id, Size scenarioIdx) const {
215- return cube_->get (id, scenarioIdx) - cube_->getT0 (id, 0 );
216- }
217-
218- Real SensitivityCube::delta (Size id, Size upIdx, Size downIdx) const {
219- return (cube_->get (id, upIdx) - cube_->get (id, downIdx)) / 2.0 ;
220- }
221-
222- Real SensitivityCube::delta (const string& tradeId, const RiskFactorKey& riskFactorKey) const {
223- Size scenarioIdx = index (riskFactorKey, upFactors_).index ;
224- Size tradeIdx = cube_->getTradeIndex (tradeId);
225- if (!twoSidedDelta (riskFactorKey.keytype )) {
226- return delta (tradeIdx, scenarioIdx);
227- } else {
213+ Real SensitivityCube::delta (const Size tradeIdx, const RiskFactorKey& riskFactorKey) const {
214+ auto s = shiftSchemes_.find (riskFactorKey);
215+ QL_REQUIRE (s != shiftSchemes_.end (),
216+ " SensitivityCube::delta(" << tradeIdx << " , " << riskFactorKey << " ): no shift scheme stored." );
217+ if (s->second == ShiftScheme::Forward) {
218+ Size scenarioIdx = index (riskFactorKey, upFactors_).index ;
219+ return cube_->get (tradeIdx, scenarioIdx) - cube_->getT0 (tradeIdx, 0 );
220+ } else if (s->second == ShiftScheme::Backward) {
221+ Size scenarioIdx = index (riskFactorKey, downFactors_).index ;
222+ return cube_->getT0 (tradeIdx, 0 ) - cube_->get (tradeIdx, scenarioIdx);
223+ } else if (s->second == ShiftScheme::Central) {
224+ Size upIdx = index (riskFactorKey, upFactors_).index ;
228225 Size downIdx = index (riskFactorKey, downFactors_).index ;
229- return delta (tradeIdx, scenarioIdx, downIdx);
226+ return (cube_->get (tradeIdx, upIdx) - cube_->get (tradeIdx, downIdx)) / 2.0 ;
227+ } else {
228+ QL_FAIL (" SensitivityCube::delta(" << tradeIdx << " , " << riskFactorKey << " ): unknown shift scheme '"
229+ << s->second << " '" );
230230 }
231231}
232232
233- Real SensitivityCube::gamma (Size id, Size upScenarioIdx, Size downScenarioIdx) const {
234-
235- Real baseNpv = cube_->getT0 (id, 0 );
236- Real upNpv = cube_->get (id, upScenarioIdx);
237- Real downNpv = cube_->get (id, downScenarioIdx);
238-
239- return upNpv - 2.0 * baseNpv + downNpv;
233+ Real SensitivityCube::delta (const string& tradeId, const RiskFactorKey& riskFactorKey) const {
234+ return delta (cube_->getTradeIndex (tradeId), riskFactorKey);
240235}
241236
242- Real SensitivityCube::gamma (const std::string& tradeId , const RiskFactorKey& riskFactorKey) const {
237+ Real SensitivityCube::gamma (const Size tradeIdx , const RiskFactorKey& riskFactorKey) const {
243238 Size upIdx = index (riskFactorKey, upFactors_).index ;
244239 Size downIdx = index (riskFactorKey, downFactors_).index ;
245- Size tradeIdx = cube_->getTradeIndex (tradeId);
240+ Real baseNpv = cube_->getT0 (tradeIdx, 0 );
241+ Real upNpv = cube_->get (tradeIdx, upIdx);
242+ Real downNpv = cube_->get (tradeIdx, downIdx);
243+ return upNpv - 2.0 * baseNpv + downNpv;
244+ }
246245
247- return gamma (tradeIdx, upIdx, downIdx);
246+ Real SensitivityCube::gamma (const string& tradeId, const RiskFactorKey& riskFactorKey) const {
247+ return gamma (cube_->getTradeIndex (tradeId), riskFactorKey);
248248}
249249
250- Real SensitivityCube::crossGamma (Size id, Size upIdx_1, Size upIdx_2, Size crossIdx) const {
250+ QuantLib::Real SensitivityCube::crossGamma (QuantLib::Size id, QuantLib::Size upIdx_1, QuantLib::Size upIdx_2,
251+ QuantLib::Size crossIdx) const {
251252 // Approximate f_{xy}|(x,y) by
252253 // ([f_{x}|(x,y + dy)] - [f_{x}|(x,y)]) / dy
253254 // ([f(x + dx,y + dy) - f(x, y + dy)] - [f(x + dx,y) - f(x,y)]) / (dx dy)
254255 Real baseNpv = cube_->getT0 (id, 0 );
255256 Real upNpv_1 = cube_->get (id, upIdx_1);
256257 Real upNpv_2 = cube_->get (id, upIdx_2);
257258 Real crossNpv = cube_->get (id, crossIdx);
258-
259259 return crossNpv - upNpv_1 - upNpv_2 + baseNpv;
260260}
261261
262- std::set<RiskFactorKey> SensitivityCube::relevantRiskFactors () {
263- std::set<RiskFactorKey> result;
264- for (auto const i : cube_->relevantScenarios ()) {
265- result.insert (scenarioDescriptions_[i].key1 ());
266- if (scenarioDescriptions_[i].type () == ShiftScenarioDescription::Type::Cross)
267- result.insert (scenarioDescriptions_[i].key2 ());
268- }
269- return result;
270- }
271-
272- Real SensitivityCube::crossGamma (const string& tradeId, const crossPair& riskFactorKeyPair) const {
262+ Real SensitivityCube::crossGamma (const Size tradeIdx, const crossPair& riskFactorKeyPair) const {
273263 FactorData upFd_1, upFd_2;
274- Size upIdx_1, upIdx_2, crossIdx, tradeIdx ;
264+ Size upIdx_1, upIdx_2, crossIdx;
275265 std::tie (upFd_1, upFd_2, crossIdx) = index (riskFactorKeyPair, crossFactors_);
276266 upIdx_1 = upFd_1.index ;
277267 upIdx_2 = upFd_2.index ;
278- tradeIdx = cube_->getTradeIndex (tradeId);
279-
280268 return crossGamma (tradeIdx, upIdx_1, upIdx_2, crossIdx);
281269}
282270
283- bool SensitivityCube::twoSidedDelta (const RiskFactorKey::KeyType& keyType) const {
284- return twoSidedDeltas_.count (keyType) == 1 ;
271+ Real SensitivityCube::crossGamma (const std::string& tradeId, const crossPair& riskFactorKeyPair) const {
272+ return crossGamma (cube_->getTradeIndex (tradeId), riskFactorKeyPair);
273+ }
274+
275+ std::set<RiskFactorKey> SensitivityCube::relevantRiskFactors () const {
276+ std::set<RiskFactorKey> result;
277+ for (auto const i : cube_->relevantScenarios ()) {
278+ result.insert (scenarioDescriptions_[i].key1 ());
279+ if (scenarioDescriptions_[i].type () == ShiftScenarioDescription::Type::Cross)
280+ result.insert (scenarioDescriptions_[i].key2 ());
281+ }
282+ return result;
285283}
286284
287285} // namespace analytics
0 commit comments