Discussion:
[Quantlib-users] Bicubic vs. Bilinear interpolation for volatility surface
Max
2007-10-03 15:33:45 UTC
Permalink
Hi,

I am using QuantLib-0.8.1 on cygwin platform.
I have written a simple C++ program to construct volatility surface using
Bilinear (default method) and Bicubic interpolation.
However, the result from Bicubic method is unsatisfactory, while Bilinear
method works fine.

Here is the way how I set up BlackVarianceSurface class:

boost::shared_ptr<BlackVarianceSurface> bVarSurface(
new BlackVarianceSurface(settlementDate, dates,
strikes, vols, dayCounter));

// change interpolation method to Bicubic
bVarSurface->setInterpolation<Bicubic>();

Handle<BlackVolTermStructure> blackSurface(bVarSurface);

Say, for the following simple data set:

strike 1M 3M
90 0.29 0.27
95 0.26 0.25

For Bilinear, blackSurface->blackVol(1/12, 90, true) returns 0.29, which is
correct.
However, for Bicubic, blackSurface->blackVol(1/12, 90, true) returns 0,
which is definitely wrong.

Does this suggest that Bicubic interpolation is broken for volatility
surface? Or any mistake in my coding?

Thanks in advance!

Best regards,
Max
Luigi Ballabio
2007-10-03 16:02:34 UTC
Permalink
Post by Max
I have written a simple C++ program to construct volatility surface
using Bilinear (default method) and Bicubic interpolation.
However, the result from Bicubic method is unsatisfactory, while
Bilinear method works fine.
strike 1M 3M
90 0.29 0.27
95 0.26 0.25
For Bilinear, blackSurface->blackVol(1/12, 90, true) returns 0.29,
which is correct.
However, for Bicubic, blackSurface->blackVol(1/12, 90, true) returns
0, which is definitely wrong.
Max,
I can't reproduce the problem---meaning that for your data, I get an
error when I try to switch to bicubic (it requires at least a 3x3
matrix.) Maybe you're catching the error and returning 0? May you try
extending the matrix with an additional row and column?

Also, careful with the argument you're passing. 1/12 is an integer
division whose result is 0. You want to write 1.0/12 instead.

Later,
Luigi
--
Vin: It's like this fellow I knew in El Paso. One day, he just took
all his clothes off and jumped in a mess of cactus. I asked him that
same question, "Why?"
Calvera: And?
Vin: He said, "It seemed like a good idea at the time."
-- The Magnificent Seven
Max
2007-10-03 16:35:52 UTC
Permalink
Hi Luigi,

By following your hints, I still face the same issue with BiCubic
interpolation.

Here is how I build and run the test program (appended bellow) when BiCubic
is set by the line "bVarSurface->setInterpolation<Bicubic>();" :

$ g++ -g -O2 -Wall -I/usr/local/include/ql -I/usr/include/boost-1_33_1/
-L/usr/local/lib TestVolSurface.cpp -lQuantlib -o TestVolSurface
$ ./TestVolSurfacel.exe
Minimum strike = 90
Maximum strike = 100
Implied Vol (1M, 90) = 0

---------------------------------------------------------------------------------------------------------------------------------------------
#include <iostream>
#include <ql/quantlib.hpp>

using namespace QuantLib;

int main(int argc, char **argv) {

Date todaysDate(3, Oct, 2007);
Date settlementDate(3, Oct, 2007);
Settings::instance().evaluationDate() = todaysDate;

DayCounter dayCounter = Actual365Fixed();

std::vector<Date> dates(3);
dates[0] = settlementDate + 1*Months;
dates[1] = settlementDate + 3*Months;
dates[2] = settlementDate + 6*Months;

std::vector<Real> strikes(3);
strikes[0] = 90;
strikes[1] = 95;
strikes[2] = 100;

Matrix vols(3, 3);

vols[0][0] = 0.293; vols[0][1] = 0.277; vols[0][2] = 0.263;
vols[1][0] = 0.256; vols[1][1] = 0.257; vols[1][2] = 0.249;
vols[2][0] = 0.220; vols[2][1] = 0.240; vols[2][2] = 0.237;

boost::shared_ptr<BlackVarianceSurface> bVarSurface(
new BlackVarianceSurface(settlementDate, dates,
strikes, vols, dayCounter));

// change interpolation method to Bicubic
bVarSurface->setInterpolation<Bicubic>();

Handle<BlackVolTermStructure> blackSurface(bVarSurface);

std::cout << "Minimum strike = " << blackSurface->minStrike() <<
std::endl;
std::cout << "Maximum strike = " << blackSurface->maxStrike() <<
std::endl;
std::cout << "Implied Vol = " << blackSurface->blackVol(1.0/12, 90,
true) << std::endl;
}
---------------------------------------------------------------------------------------------------------------------------------------------

Do you get the same result as I do?

Thanks

Best regards,
Max
Post by Luigi Ballabio
Post by Max
I have written a simple C++ program to construct volatility surface
using Bilinear (default method) and Bicubic interpolation.
However, the result from Bicubic method is unsatisfactory, while
Bilinear method works fine.
strike 1M 3M
90 0.29 0.27
95 0.26 0.25
For Bilinear, blackSurface->blackVol(1/12, 90, true) returns 0.29,
which is correct.
However, for Bicubic, blackSurface->blackVol(1/12, 90, true) returns
0, which is definitely wrong.
Max,
I can't reproduce the problem---meaning that for your data, I get an
error when I try to switch to bicubic (it requires at least a 3x3
matrix.) Maybe you're catching the error and returning 0? May you try
extending the matrix with an additional row and column?
Also, careful with the argument you're passing. 1/12 is an integer
division whose result is 0. You want to write 1.0/12 instead.
Later,
Luigi
--
Vin: It's like this fellow I knew in El Paso. One day, he just took
all his clothes off and jumped in a mess of cactus. I asked him that
same question, "Why?"
Calvera: And?
Vin: He said, "It seemed like a good idea at the time."
-- The Magnificent Seven
Luigi Ballabio
2007-10-04 14:21:03 UTC
Permalink
Post by Max
By following your hints, I still face the same issue with BiCubic
interpolation.
Hi Max,
I've reproduced your problem. The good news is that the code currently
in Subversion works---I haven't checked in depth, but I suspect that the
reason is the change logged at
<http://quantlib.svn.sourceforge.net/viewvc/quantlib/trunk/QuantLib/ql/math/interpolations/cubicspline.hpp?r1=11481&r2=12381>.
May you try applying it and see if it fixes the problem?

Luigi
--
Newton's Law of Gravitation:
What goes up must come down. But don't expect it to come down
where you can find it. Murphy's Law applies to Newton's.
Max
2007-10-04 15:56:07 UTC
Permalink
Post by Luigi Ballabio
Post by Max
By following your hints, I still face the same issue with BiCubic
interpolation.
Hi Max,
I've reproduced your problem. The good news is that the code currently
in Subversion works---I haven't checked in depth, but I suspect that the
reason is the change logged at
<
http://quantlib.svn.sourceforge.net/viewvc/quantlib/trunk/QuantLib/ql/math/interpolations/cubicspline.hpp?r1=11481&r2=12381
Post by Max
.
May you try applying it and see if it fixes the problem?
Hi Luigi,

Now the interpolated numbers are looking good after applying the fix.
And I will try to further verify it with matlab.

A side question, I didn't see "configure" script in the Subversion code, so
how can I build the code?

Thanks a lot!

Best regards,
Max
Luigi Ballabio
2007-10-04 16:05:39 UTC
Permalink
Post by Max
Now the interpolated numbers are looking good after applying the fix.
And I will try to further verify it with matlab.
A side question, I didn't see "configure" script in the Subversion
code, so how can I build the code?
Run autogen.sh first. To do that, you'll need recent (ideally, the
latest) versions of autoconf, automake, and libtool.

Luigi
--
The young man knows the rules, but the old man knows the exceptions.
-- O. W. Holmes
Loading...