@@ -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, std::string>& 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, std::string >& shiftSchemes )
69+ : cube_(cube), shiftSizes_(shiftsizes), shiftSchemes_(shiftSchemes ) {
7170
7271 // Populate scenarioDescriptions_ from string descriptions
7372 scenarioDescriptions_.reserve (scenarioDescriptions.size ());
@@ -110,6 +109,7 @@ void SensitivityCube::initialise() {
110109 QL_REQUIRE (downFactors_.count (des.key1 ()) == 0 , " Cannot have multiple down factors with "
111110 " the same risk factor key ["
112111 << des.key1 () << " ]" );
112+ factors_.insert (des.key1 ());
113113 downFactors_[des.key1 ()] = fd;
114114 downIndexToKey_[fd.index ] = des.key1 ();
115115 break ;
@@ -135,34 +135,26 @@ void SensitivityCube::initialise() {
135135 }
136136
137137 // 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" );
138+ if (factors_.size () != shiftSizes_.size ()) {
139+ WLOG (" The number of factors from up / down shifts (" << factors_.size () << " ) does not equal "
140+ << " the number of shift sizes (" << shiftSizes_.size ()
141+ << " ) supplied" );
141142 }
142143
143- for (auto const & kv : upFactors_ ) {
144- auto it = shiftSizes_.find (kv. first );
144+ for (auto const & f : factors_ ) {
145+ auto it = shiftSizes_.find (f );
145146 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." )
147+ WLOG (" No entry for risk factor " << f << " in shift sizes." );
150148 }
151149 }
152150}
153151
154152bool SensitivityCube::hasTrade (const string& tradeId) const { return tradeIdx_.count (tradeId) > 0 ; }
155153
156- RiskFactorKey SensitivityCube::upFactor (const Size upIndex ) const {
157- if (auto k = upIndexToKey_.find (upIndex ); k != upIndexToKey_.end ()) {
154+ RiskFactorKey SensitivityCube::upDownFactor (const Size index ) const {
155+ if (auto k = upIndexToKey_.find (index ); k != upIndexToKey_.end ()) {
158156 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 ()) {
157+ } else if (auto k = downIndexToKey_.find (index); k != downIndexToKey_.end ()) {
166158 return k->second ;
167159 } else {
168160 return RiskFactorKey ();
@@ -178,7 +170,7 @@ SensitivityCube::crossPair SensitivityCube::crossFactor(const Size crossIndex) c
178170}
179171
180172bool SensitivityCube::hasScenario (const ShiftScenarioDescription& scenarioDescription) const {
181- return scenarioIdx_.count (scenarioDescription) > 0 ;
173+ return scenarioIdx_.find (scenarioDescription) != scenarioIdx_. end () ;
182174}
183175
184176std::string SensitivityCube::factorDescription (const RiskFactorKey& riskFactorKey) const {
@@ -199,6 +191,12 @@ Real SensitivityCube::shiftSize(const RiskFactorKey& riskFactorKey) const {
199191 return it->second ;
200192}
201193
194+ std::string SensitivityCube::shiftScheme (const RiskFactorKey& riskFactorKey) const {
195+ auto it = shiftSchemes_.find (riskFactorKey);
196+ QL_REQUIRE (it != shiftSchemes_.end (), " Risk factor, " << riskFactorKey << " , was not found in the shift schemes." );
197+ return it->second ;
198+ }
199+
202200Real SensitivityCube::npv (const string& tradeId) const { return cube_->getT0 (tradeId, 0 ); }
203201
204202Real SensitivityCube::npv (Size id) const { return cube_->getT0 (id, 0 ); }
@@ -211,77 +209,76 @@ Real SensitivityCube::npv(const string& tradeId, const ShiftScenarioDescription&
211209 return npv (tradeIdx, scenarioIdx);
212210}
213211
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 {
212+ Real SensitivityCube::delta (const Size tradeIdx, const RiskFactorKey& riskFactorKey) const {
213+ auto s = shiftSchemes_.find (riskFactorKey);
214+ QL_REQUIRE (s != shiftSchemes_.end (),
215+ " SensitivityCube::delta(" << tradeIdx << " , " << riskFactorKey << " ): no shift scheme stored." );
216+ if (s->second == " Forward" ) {
217+ Size scenarioIdx = index (riskFactorKey, upFactors_).index ;
218+ return cube_->get (tradeIdx, scenarioIdx) - cube_->getT0 (tradeIdx, 0 );
219+ } else if (s->second == " Backward" ) {
220+ Size scenarioIdx = index (riskFactorKey, downFactors_).index ;
221+ return cube_->getT0 (tradeIdx, 0 ) - cube_->get (tradeIdx, scenarioIdx);
222+ } else if (s->second == " Central" ) {
223+ Size upIdx = index (riskFactorKey, upFactors_).index ;
228224 Size downIdx = index (riskFactorKey, downFactors_).index ;
229- return delta (tradeIdx, scenarioIdx, downIdx);
230- }
225+ return (cube_->get (tradeIdx, upIdx) - cube_->get (tradeIdx, downIdx)) / 2.0 ;
226+ } else {
227+ QL_FAIL (" SensitivityCube::delta(" << tradeIdx << " , " << riskFactorKey << " ): unknown shift scheme '"
228+ << s->second << " '" );
229+ }
231230}
232231
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;
232+ Real SensitivityCube::delta (const string& tradeId, const RiskFactorKey& riskFactorKey) const {
233+ return delta (cube_->getTradeIndex (tradeId), riskFactorKey);
240234}
241235
242- Real SensitivityCube::gamma (const std::string& tradeId , const RiskFactorKey& riskFactorKey) const {
236+ Real SensitivityCube::gamma (const Size tradeIdx , const RiskFactorKey& riskFactorKey) const {
243237 Size upIdx = index (riskFactorKey, upFactors_).index ;
244238 Size downIdx = index (riskFactorKey, downFactors_).index ;
245- Size tradeIdx = cube_->getTradeIndex (tradeId);
239+ Real baseNpv = cube_->getT0 (tradeIdx, 0 );
240+ Real upNpv = cube_->get (tradeIdx, upIdx);
241+ Real downNpv = cube_->get (tradeIdx, downIdx);
242+ return upNpv - 2.0 * baseNpv + downNpv;
243+ }
246244
247- return gamma (tradeIdx, upIdx, downIdx);
245+ Real SensitivityCube::gamma (const string& tradeId, const RiskFactorKey& riskFactorKey) const {
246+ return gamma (cube_->getTradeIndex (tradeId), riskFactorKey);
248247}
249248
250- Real SensitivityCube::crossGamma (Size id, Size upIdx_1, Size upIdx_2, Size crossIdx) const {
249+ QuantLib::Real SensitivityCube::crossGamma (QuantLib::Size id, QuantLib::Size upIdx_1, QuantLib::Size upIdx_2,
250+ QuantLib::Size crossIdx) const {
251251 // Approximate f_{xy}|(x,y) by
252252 // ([f_{x}|(x,y + dy)] - [f_{x}|(x,y)]) / dy
253253 // ([f(x + dx,y + dy) - f(x, y + dy)] - [f(x + dx,y) - f(x,y)]) / (dx dy)
254254 Real baseNpv = cube_->getT0 (id, 0 );
255255 Real upNpv_1 = cube_->get (id, upIdx_1);
256256 Real upNpv_2 = cube_->get (id, upIdx_2);
257257 Real crossNpv = cube_->get (id, crossIdx);
258-
259258 return crossNpv - upNpv_1 - upNpv_2 + baseNpv;
260259}
261260
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 {
261+ Real SensitivityCube::crossGamma (const Size tradeIdx, const crossPair& riskFactorKeyPair) const {
273262 FactorData upFd_1, upFd_2;
274- Size upIdx_1, upIdx_2, crossIdx, tradeIdx ;
263+ Size upIdx_1, upIdx_2, crossIdx;
275264 std::tie (upFd_1, upFd_2, crossIdx) = index (riskFactorKeyPair, crossFactors_);
276265 upIdx_1 = upFd_1.index ;
277266 upIdx_2 = upFd_2.index ;
278- tradeIdx = cube_->getTradeIndex (tradeId);
279-
280267 return crossGamma (tradeIdx, upIdx_1, upIdx_2, crossIdx);
281268}
282269
283- bool SensitivityCube::twoSidedDelta (const RiskFactorKey::KeyType& keyType) const {
284- return twoSidedDeltas_.count (keyType) == 1 ;
270+ Real SensitivityCube::crossGamma (const std::string& tradeId, const crossPair& riskFactorKeyPair) const {
271+ return crossGamma (cube_->getTradeIndex (tradeId), riskFactorKeyPair);
272+ }
273+
274+ std::set<RiskFactorKey> SensitivityCube::relevantRiskFactors () const {
275+ std::set<RiskFactorKey> result;
276+ for (auto const i : cube_->relevantScenarios ()) {
277+ result.insert (scenarioDescriptions_[i].key1 ());
278+ if (scenarioDescriptions_[i].type () == ShiftScenarioDescription::Type::Cross)
279+ result.insert (scenarioDescriptions_[i].key2 ());
280+ }
281+ return result;
285282}
286283
287284} // namespace analytics
0 commit comments