Hello everybody,
i recently did a lot of testing with the localvolSurface
class (which contains Gatherals Dupire Formula) and i am not very happy with
the results. Ok, the class is (regarding to the documentation) untested, so I guess
I cant expect it to work properly. But I figured that numerical problems cause
this class to return the error message “negative local vol … the
black vol surface is not smooth enough”. This also happens for very
smooth black vol surfaces. The Problem lies in this code:
Real forwardValue =
underlying *
(dividendTS->discount(t, true)/
riskFreeTS->discount(t, true));
// strike derivatives
Real strike, y, dy, strikep, strikem;
Real w, wp, wm, dwdy, d2wdy2;
strike = underlyingLevel;
y = std::log(strike/forwardValue);
dy = ((y!=
strikep=strike*std::exp(dy);
strikem=strike/std::exp(dy);
w = blackTS->blackVariance(t, strike, true);
wp = blackTS->blackVariance(t, strikep, true);
wm = blackTS->blackVariance(t, strikem, true);
dwdy = (wp-wm)/(
d2wdy2 = (wp-
// time derivative
Real dt, wpt, wmt, dwdt;
if (t==
dt =
wpt = blackTS->blackVariance(t+dt, strike, true);
QL_ENSURE(wpt>=w,
"decreasing variance at
strike " << strike
<< " between time
" << t << " and time " << t+dt);
dwdt = (wpt-w)/dt;
} else {
dt = std::min<Time>(
wpt = blackTS->blackVariance(t+dt, strike, true);
wmt = blackTS->blackVariance(t-dt, strike, true);
QL_ENSURE(wpt>=w,
"decreasing variance at strike
" << strike
<< " between time
" << t << " and time " << t+dt);
QL_ENSURE(w>=wmt,
"decreasing variance at
strike " << strike
<< " between time
" << t-dt << " and time " << t);
dwdt = (wpt-wmt)/(
}
if (dwdy==
return std::sqrt(dwdt);
} else {
Real den1 =
Real den2 =
Real den3 =
Real den = den1+den2+den3;
Real result = dwdt / den;
QL_ENSURE(result>=
"negative local vol^2 at
strike " << strike
<< " and time
" << t
<< "; the black
vol surface is not smooth enough");
return
std::sqrt(result);
// return std::sqrt(dwdt / (
//
}
To be a bit more precise the problem lies in the
second derivative of the black variance with respect to the strike. Even if I
take surfaces without Smile/Skew, i.e. flat ones, I still get the problem
there. This is because (wp-
Real forwardValue =
underlying *
(dividendTS->discount(t, true)/
riskFreeTS->discount(t, true));
// strike derivatives
Real strike, y, dy, strikep, strikem;
Real w, wp, wm, dwdy, d2wdy2;
Real z1,z2;
// strike ist gegeben
strike
= underlyingLevel;
// log(strike/forwardValue)
y
= std::log(strike/forwardValue);
std::cout
<< "y: "
<< y << std::endl;
// wir leiten blackScholesVariance nach
y ab, bilde daher diskrete kleine unterteilung
dy
= ((y!=
std::cout
<< "dy: "
<< dy << std::endl;
strikep=strike*std::exp(dy);
strikem=strike/std::exp(dy);
w = blackTS->blackVariance(t, strike, true);
wp = blackTS->blackVariance(t, strikep, true);
wm = blackTS->blackVariance(t, strikem, true);
z1=wp-wm;
if (std::abs(z1) <
z1=0;
dwdy = (z1)/(
z2=wp-
if
(std::abs(z2) <
z2=0;
d2wdy2 = (z2)/(dy*dy);
// time derivative
Real dt, wpt, wmt, dwdt;
dt
= (
wpt = blackTS->blackVariance(t+dt, strike, true);
QL_ENSURE(wpt>=w,
"decreasing variance at
strike " << strike
<<
" between time "
<< t << "
and time " << t+dt);
dwdt = (wpt-w)/dt;
if (dwdy==
return std::sqrt(dwdt);
} else {
Real den1 =
Real den2 =
Real den3 =
Real den = den1+den2+den3;
Real result = dwdt / den;
QL_ENSURE(result>=
"negative local vol^2 at
strike " << strike
<< " and time
" << t
<< "; the black
vol surface is not smooth enough");
return
std::sqrt(result);
// return std::sqrt(dwdt / (
//
}
So far all the testing I did I received much better and more
stable results. But since I am not an expert in computational and numerical
methods regarding precision, can anybody who is a bit more experienced with c++
numerical issues give me some advice and probably check this out?
Greetings
Michael
| Free forum by Nabble | Edit this page |