Posted by
MH_quant on
URL: http://quantlib.414.s1.nabble.com/LocalvolSurface-cpp-tp12806p12808.html
Hallo Klaus,
I checked out your new version of the localvolsurface.cpp from the SVN and
run some extensive tests.
First of all I found some minor errors in your code which are:
1. (Line 116): Real strikept = strike*dr*dq/(drpt*dqpt);
This should be:
Real strikept = strike*dr*dqpt/(drpt*dq);
2. (same in line 130 and 131):
Real strikept = strike*dr*dq/(drpt*dqpt);
Real strikemt = strike*dr*dq/(drmt*dqmt);
This should be:
Real strikept = strike*dr*dqpt/(drpt*dq);
Real strikemt = strike*dr*dqmt/(drmt*dq);
Just minor things, but think it over. You divide through the risk free
discount and multiply with the dividend discount. And if you do this from t
to t+dt then this is what you get.
Now a few words what I figured out by extensive testing. I ran tests with MC
with 100 thousand of paths. And your Bug-Fix brought some slight
improvements but the problem with the second derivative still remains.
It happens very often that the program crashes and tells me "negative local
vol^2 at ..."
The black vol surface I am using is very smooth. So this is not the reason
for the problems. Much more is the problem again the numerical instability
when taking the second derivative of the implied variance surface with
respect to the log-moneyness.
Let me introduce 2 more variables:
Real z1,z2;
Where
z1=wp-wm;
z2=wp-2.0*w+wm;
Then the first derivative of w with respect to log-moneyness is:
dwdy = (z1)/(2.0*dy);
And the second is:
d2wdy2 = (z2)/(dy*dy);
It happens at different strikes and moneyness under some conditions that the
d2wdy2 blows up and becomes something like -4231,12
Like a really big negative number. This obviously makes the denominator
which consists of den1+den2+den3 negative and the whole program crashes.
The numerator is always positive since we make sure that the implied
variance is monotone increasing.
So the only thing we have to take care about is that our denominator is not
getting negative.
I figured out (by extensive testing and only empirically) that
0.4 < den1+den2<1.3
So at least for the surfaces I was testing, this was always given. So
basically we have to make sure that den3 is not getting smaller then -0.4 in
order for the program not to crash.
But my tests showed that den3 is either in the green zone or it blows up
dramatically which gives me the suppression that we encounter some numerical
problems under certain conditions.
The only way how I managed for the program to run stable is by controlling
z1,z2 by setting:
if ((std::abs(z1) < std::abs(dy)/1000 && z1!=0.0) || std::abs(z1) >
2*std::abs(dy))
z1=0;
and
if ((std::abs(z2) < dy*dy/1000 && z2!=0.0) || std::abs(z2) > dy*dy)
z2=0;
So what I basically do is setting the first derivative to zero when it is
getting so small that it doesn't really affect our result anymore anyways.
Same with the second derivative.
But the more critical part is setting the derivative to zero when it blows
up. I just cut off all critical values.
This makes (obviously) the program run stable.
On the off-side I cant really say for sure (at least till now) how big the
impacts of this manipulation are for the precision of our results. I figured
that we basically never get problems with z1 which means with the first
derivative. But we set the second derivative which means z2 quit often to
zero when it falls out of the good range.
For some reason I don't get rid of the feeling that we would be better of to
work completely without the second derivative since it seems to be
impossible to get this numerically under control. But would that probably
make the dupire formula useless to us?
Do you have any Ideas? Or can I help you with this issue any further?
Greetings,
Michael
PS: is it possible to write a paper which examines under which conditions
(what range for what variables and what interdependencies of the variables
and what restrictions to the shape of the black vol surface) the formula is
theoretically/mathematically possible (i.e. doesn't get negative) and then
use this new gained knowledge to make our code stable with the smallest
impact possible to the precision of the result?
-----Original Message-----
From: Klaus Spanderen [mailto:
[hidden email]]
Sent: Freitag, 24. April 2009 00:07
To:
[hidden email]
Cc: Michael Heckl; Ferdinando Ametrano
Subject: Re: [Quantlib-dev] LocalvolSurface.cpp
Hi Michael,
you wrote
> 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-2.0*w+wm) is not exactly zero but very very small. And this gets
> devided by 0. 000000000001.
To me the root of the problem was the line
dy = ((y!=0.0) ? y*0.000001 : 0.000001);
For ve y small y this code leads to unrealistic small dy and to numerical
problems during the calculation of the difference quotient. Therfore I've
changed it into
dy = ((std::fabs(y) > 0.001) ? y*0.0001 : 0.000001);
and at least for my tests the numerical problems with the difference
quotient
disappeared. (pls see the latest version of localvolsurface.cpp in the SVN
repository). Could you test this fix using your test cases?
regards
Klaus
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensign option that enables unlimited
royalty-free distribution of the report engine for externally facing
server and web deployment.
http://p.sf.net/sfu/businessobjects_______________________________________________
QuantLib-dev mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-dev