Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Attributes | List of all members
CarrMadanMarginalProbability Class Reference

#include <qle/models/carrmadanarbitragecheck.hpp>

+ Collaboration diagram for CarrMadanMarginalProbability:

Public Member Functions

 CarrMadanMarginalProbability (const std::vector< Real > &strikes, const Real forward, const std::vector< Real > &callPrices, const VolatilityType volType=ShiftedLognormal, const Real shift=0.0)
 
const std::vector< Real > & strikes () const
 
Real forward () const
 
const std::vector< Real > & callPrices () const
 
VolatilityType volatilityType () const
 
Real shift () const
 
bool arbitrageFree () const
 
const std::vector< bool > & callSpreadArbitrage () const
 
const std::vector< bool > & butterflyArbitrage () const
 
const std::vector< Real > & density () const
 

Private Attributes

std::vector< Real > strikes_
 
Real forward_
 
std::vector< Real > callPrices_
 
VolatilityType volType_
 
Real shift_
 
std::vector< boolcallSpreadArbitrage_
 
std::vector< boolbutterflyArbitrage_
 
std::vector< Real > q_
 
bool smileIsArbitrageFree_
 

Detailed Description

Definition at line 36 of file carrmadanarbitragecheck.hpp.

Constructor & Destructor Documentation

◆ CarrMadanMarginalProbability()

CarrMadanMarginalProbability ( const std::vector< Real > &  strikes,
const Real  forward,
const std::vector< Real > &  callPrices,
const VolatilityType  volType = ShiftedLognormal,
const Real  shift = 0.0 
)

The callPrices should be non-discounted

Definition at line 29 of file carrmadanarbitragecheck.cpp.

33
34 // check input
35
36 QL_REQUIRE(close_enough(shift_, 0.0) || shift_ > 0.0,
37 "CarrMadanMarginalProbability: shift (" << shift_ << ") must be non-negative");
38
39 QL_REQUIRE(strikes_.size() == callPrices_.size(), "CarrMadanMarginalProbability: strikes ("
40 << strikes_.size() << ") inconsistent to callPrices ("
41 << callPrices_.size() << ")");
42
43 QL_REQUIRE(!strikes_.empty(), "CarrMadanMarginalProbability: input moneyness is empty");
44
45 // build sort permutation for strikes
46
47 std::vector<Size> perm(strikes.size());
48 std::iota(perm.begin(), perm.end(), 0);
49 std::sort(perm.begin(), perm.end(), [this](Size a, Size b) { return strikes_[a] < strikes_[b]; });
50
51 // check strikes are different (and increasing for the found permutation)
52
53 for (Size i = 1; i < strikes_.size(); ++i) {
54 QL_REQUIRE(strikes_[perm[i]] > strikes_[perm[i - 1]] && !close_enough(strikes_[perm[i]], strikes_[perm[i - 1]]),
55 "CarrMadanMarginalProbability: duplicate strikes at "
56 << perm[i - 1] << ", " << perm[i] << ": " << strikes[perm[i - 1]] << ", " << strikes[perm[i]]);
57 }
58
59 QL_REQUIRE(volType_ == Normal || strikes_[perm[0]] > -shift_ || close_enough(strikes_[perm[0]], -shift_),
60 "CarrMadanMarginalProbability: all input strikes (" << strikes_[perm[0]] << ") plus shift (" << shift
61 << ") must be positive or zero, got "
62 << strikes_[perm[0]] + shift);
63
64 /* add strike -shift and corresponding call price (= forward + shift), if not already present
65 this is only done for ShiftedLognormal vols, not for Normal */
66 bool minusShiftStrikeAdded = false;
67 if (volType_ == ShiftedLognormal) {
68 if (!close_enough(strikes_[perm[0]], 0.0)) {
69 strikes_.push_back(-shift);
70 callPrices_.push_back(forward_);
71 perm.insert(perm.begin(), strikes_.size() - 1);
72 minusShiftStrikeAdded = true;
73 } else {
74 QL_REQUIRE(close_enough(callPrices_[perm[0]], forward_ + shift_),
75 "CarrMadanMarginalProbability: call price ("
76 << callPrices_.front() << ") for strike -shift (" << -shift_ << ") should match forward ("
77 << forward_ << ") + shift (" << shift_ << ") = " << forward_ + shift_);
78 }
79 }
80
81 // check we have two strikes at least
82
83 QL_REQUIRE(strikes_.size() >= 2,
84 "CarrMadanMarginalProbability: at least two strikes levels required (after adding -shift)");
85
86 // compute Q
87
88 std::vector<Real> Q(strikes_.size() - 1);
89 for (Size i = 1; i < strikes_.size(); ++i) {
90 Q[i - 1] = (callPrices_[perm[i - 1]] - callPrices_[perm[i]]) / (strikes_[perm[i]] - strikes_[perm[i - 1]]);
91 }
92
93 // compute BS
94
95 std::vector<Real> BS(strikes_.size() - 2);
96 for (Size i = 1; i < strikes_.size() - 1; ++i) {
97 BS[i - 1] = callPrices_[perm[i - 1]] -
98 (strikes_[perm[i + 1]] - strikes_[perm[i - 1]]) / (strikes_[perm[i + 1]] - strikes_[perm[i]]) *
99 callPrices_[perm[i]] +
100 (strikes_[perm[i]] - strikes_[perm[i - 1]]) / (strikes_[perm[i + 1]] - strikes_[perm[i]]) *
101 callPrices_[perm[i + 1]];
102 }
103
104 // perform the checks 1, 2 from the paper, and populate the set of arbitrage
105
107 callSpreadArbitrage_.resize(strikes_.size());
108 butterflyArbitrage_.resize(strikes_.size());
109
110 // check 1: Q(i,j) in [0,1]
111
112 for (Size i = 0; i < Q.size(); ++i) {
113 if (Q[i] < -1.0E-10 || Q[i] > 1.0 + 1.0E-10) {
114 callSpreadArbitrage_[perm[i]] = true;
115 callSpreadArbitrage_[perm[i + 1]] = true;
116 smileIsArbitrageFree_ = false;
117 }
118 }
119
120 // check 2: BS(i,j) >= 0
121
122 for (Size i = 0; i < BS.size(); ++i) {
123 if (BS[i] < -1.0E-10) {
124 butterflyArbitrage_[perm[i]] = true;
125 butterflyArbitrage_[perm[i + 1]] = true;
126 butterflyArbitrage_[perm[i + 2]] = true;
127 smileIsArbitrageFree_ = false;
128 }
129 }
130
131 // compute the density q
132
133 q_.resize(strikes_.size());
134 q_[perm[0]] = 1.0 - Q.front();
135 for (Size i = 0; i < Q.size() - 1; ++i) {
136 q_[perm[i + 1]] = Q[i] - Q[i + 1];
137 }
138 q_[perm.back()] = Q.back();
139
140 // remove zero strike again, if not present from the start
141
142 if (minusShiftStrikeAdded) {
143 strikes_.erase(std::next(strikes_.end(), -1));
144 callPrices_.erase(std::next(callPrices_.end(), -1));
145 callSpreadArbitrage_.erase(std::next(callSpreadArbitrage_.begin(), perm.front()));
146 butterflyArbitrage_.erase(std::next(butterflyArbitrage_.begin(), perm.front()));
147 q_.erase(std::next(q_.begin(), perm.front()));
148 }
149}
const std::vector< Real > & strikes() const
const std::vector< Real > & callPrices() const
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:

Member Function Documentation

◆ strikes()

const std::vector< Real > & strikes ( ) const

Definition at line 151 of file carrmadanarbitragecheck.cpp.

151{ return strikes_; }
+ Here is the caller graph for this function:

◆ forward()

Real forward ( ) const

Definition at line 152 of file carrmadanarbitragecheck.cpp.

152{ return forward_; }

◆ callPrices()

const std::vector< Real > & callPrices ( ) const

Definition at line 153 of file carrmadanarbitragecheck.cpp.

153{ return callPrices_; }

◆ volatilityType()

VolatilityType volatilityType ( ) const

Definition at line 154 of file carrmadanarbitragecheck.cpp.

154{ return volType_; }

◆ shift()

Real shift ( ) const

Definition at line 155 of file carrmadanarbitragecheck.cpp.

155{ return shift_; }
+ Here is the caller graph for this function:

◆ arbitrageFree()

bool arbitrageFree ( ) const

Definition at line 157 of file carrmadanarbitragecheck.cpp.

157{ return smileIsArbitrageFree_; }
+ Here is the caller graph for this function:

◆ callSpreadArbitrage()

const std::vector< bool > & callSpreadArbitrage ( ) const

Definition at line 159 of file carrmadanarbitragecheck.cpp.

159{ return callSpreadArbitrage_; }
+ Here is the caller graph for this function:

◆ butterflyArbitrage()

const std::vector< bool > & butterflyArbitrage ( ) const

Definition at line 160 of file carrmadanarbitragecheck.cpp.

160{ return butterflyArbitrage_; }
+ Here is the caller graph for this function:

◆ density()

const std::vector< Real > & density ( ) const

Definition at line 161 of file carrmadanarbitragecheck.cpp.

161{ return q_; }
+ Here is the caller graph for this function:

Member Data Documentation

◆ strikes_

std::vector<Real> strikes_
private

Definition at line 56 of file carrmadanarbitragecheck.hpp.

◆ forward_

Real forward_
private

Definition at line 57 of file carrmadanarbitragecheck.hpp.

◆ callPrices_

std::vector<Real> callPrices_
private

Definition at line 58 of file carrmadanarbitragecheck.hpp.

◆ volType_

VolatilityType volType_
private

Definition at line 59 of file carrmadanarbitragecheck.hpp.

◆ shift_

Real shift_
private

Definition at line 60 of file carrmadanarbitragecheck.hpp.

◆ callSpreadArbitrage_

std::vector<bool> callSpreadArbitrage_
private

Definition at line 62 of file carrmadanarbitragecheck.hpp.

◆ butterflyArbitrage_

std::vector<bool> butterflyArbitrage_
private

Definition at line 62 of file carrmadanarbitragecheck.hpp.

◆ q_

std::vector<Real> q_
private

Definition at line 63 of file carrmadanarbitragecheck.hpp.

◆ smileIsArbitrageFree_

bool smileIsArbitrageFree_
private

Definition at line 64 of file carrmadanarbitragecheck.hpp.