SABR Calibration

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

SABR Calibration

Mario Marra
Hi all!

I am trying to do a SABR calibration for Equity Futures the same was as it is explained here: https://letianquant.files.wordpress.com/2016/01/12-sabr-model.pdf

I would like to keep Beta = 1 fixed and find Alpha, Rho and Nu such that equation (6) from the paper would return me the correct ATM Vol (so I can use the ATM Vols later on to shift Alpha without needing to recalibrate Beta, Rho and Nu).

I see that there are a lot of post on SABR and I apologize if the solution is already out there but I am relatively new to C++ (~2 months) and I come from a very good knowledge of VBA but I still struggle to properly understand everything happening in the background of QuantLib.

Attached you can see what I have done so far, I hope it helps.

Thank you,

Mario

SABR_so_Far.txt
Reply | Threaded
Open this post in threaded view
|

Re: SABR Calibration

Mario Marra
Ok guys, there are some progress and I want to share them with you. Thanks to Luigi's help, I managed to solve the following issues:

- As it is available elsewhere, in order to get the calibration, you need a call to update. In my code I did:
SABRLinInterpolation.update();

- To calibrate 3 parameters it is needed at least 4 (should be) observations, however, I found a way around it by incrementing the the strikes and the vol by an amount close to zero and the calibration seems to work well (I compared to the one in RStudio and the results seem to be correct);

What we are still trying to solve is the issue related to the constraint. From the equation (6) of the file I attached you can see that the constraint of alpha is a specific figure which is a function of ATM_Vol, Forward, Time_to_Maturity, Beta, Rho and Nu.
I suggested to use a Composite constraint but it seems that it might not be that easy as suggested by Luigi through emails.

So from now the real question is, do you know how can I force the calibration to have AlphaIsFixed = False while at the same time returning a parameter which returns the correct value if the equation (6) from the paper is used?

Thank you in advance,

Mario


Following there is what I have down so far

######

int main(int argc, const char * argv[])
{
//~~~~~~~~~~~~~~~~~~~~~~~~~SABR Interpolation Curve
        std::cout << "SABR Interpolation" << std::endl;
        std::vector <Real> xVec(4), yVec(xVec.size());

        xVec[0] = 100; yVec[0] = 0.120232487; //Create vectors
        xVec[1] = 120; yVec[1] = 0.088666203;
        xVec[2] = 120.00000000001; yVec[2] = 0.0886662030001; //Trick to have the calibration working as you need n+1 observations to calibrate n parameters
        xVec[3] = 120.00000000002; yVec[3] = 0.0886662030002;//Trick to have the calibration working as you need n+1 observations to calibrate n parameters

                                                                                                                 //SABR::SABR(4.649315068, 110.5, 0.5, 1, 0.5, 0.5, false, false, false, false); //It just assigns value within the private components of the class
        SABRInterpolation SABRLinInterpolation(xVec.begin(), xVec.end(), yVec.begin(), 3.649315068, 114.3, 0.087443, 1, 0.657465, -0.41797, false, true, false, false);
        SABRLinInterpolation.enableExtrapolation(); //This step is necessary to get the possibility of interpolate the curve outside the strikes provided
        {//Without Calibration
                for (double x = 90; x <= 150; x++)
                        std::cout << "Sabr Vol at Strike " << x << ":" << SABRLinInterpolation(x) << std::endl;
        }
        std::cout << "The error is :" << SABRLinInterpolation.rmsError() << std::endl << std::endl << std::endl;

        //~~~~~~~~~~~~~~~~~~~~~~~~~SABR Calibration
        {
                SABRLinInterpolation.update(); //Return Parameters
                Real Return_Parms[4] = { SABRLinInterpolation.alpha(), SABRLinInterpolation.beta(),SABRLinInterpolation.rho(),SABRLinInterpolation.nu() };
                std::cout << "The parameters calibrated are are (alpha, beta, rho and nu): " << std::endl;
                {
                        for (int y = 0; y <= 3; y++)
                                std::cout << Return_Parms[y] << std::endl;
                }
                std::cout << "\n\n";
                {
                        for (double x = 90; x <= 150; x++)
                                std::cout << "Sabr Vol at Strike (Calibrated) " << x << ":" << SABRLinInterpolation(x) << std::endl;
                }
                std::cout << "\nThe error is :" << SABRLinInterpolation.rmsError() << std::endl;

                system("pause");
        }
Reply | Threaded
Open this post in threaded view
|

Re: SABR Calibration

Peter Caspers-4
Hi Mario,

the SABR interpolation set up is quite generic, so I think it’s easy to add your new calibration strategy: Add a

struct SABRSmartAlphaSpecs

similar to SABRSpecs in sabrinterpolation.hpp and modify the inverse() and direct() methods that are the transformations between the (unconstrained) optimisation space and the SABR parameter space. You can probably inherit from SABRSpecs and just overwrite the two methods.

You can check if alpha is fixed in these methods (they have the isFixed bool-vector as an input) and if yes set it to the value from the paper. Then add the spec struct as a template parameter to SABRInterpolation (it’s hardcoded to SABRSpecs at the moment) and typedef SABRInterpolation_t<SABRSpec> to SABRInterpolation to maintain backwards compatibility. You can add a second typedef SABRInterpolation_t<SABRSmartAlphaSpecs> to SABRSmartAlphaInterpolation, which is then your new interpolation class.

There is a small problem though, since neither the option maturity nor the atm vol is provided to the inverse / direct methods. This would require an extension of the signature of these methods in SABRSpecs, ZabrSpecs, SviSpecs, and their common backbone XABRInterpolationImpl. Which is straightforward though.

If the new interpolation is actually working more stable and / or is faster to compute, then the whole thing might be worth a pull request.

About the number of parameters: When you use Levenberg Marquardt I’d expect that you need 3 points (not 4) to calibrate 3 parameters? Do you get an exception if you provide 3 points?
If on the other hand you use e.g. the Simplex Optimiser there is no such restriction, the optimisation should run with any number of points.

Best Regards
Peter

> On 10 May 2017, at 17:41, Mario Marra <[hidden email]> wrote:
>
> Ok guys, there are some progress and I  to share them with you. Thanks to
> Luigi's help, I managed to solve the following issues:
>
> - As it is available elsewhere, in order to get the calibration, you need a
> call to update. In my code I did:
> SABRLinInterpolation.update();
>
> - To calibrate 3 parameters it is needed at least 4 (should be)
> observations, however, I found a way around it by incrementing the the
> strikes and the vol by an amount close to zero and the calibration seems to
> work well (I compared to the one in RStudio and the results seem to be
> correct);
>
> What we are still trying to solve is the issue related to the constraint.
>> From the equation (6) of the file I attached you can see that the constraint
> of alpha is a specific figure which is a function of ATM_Vol, Forward,
> Time_to_Maturity, Beta, Rho and Nu.
> I suggested to use a Composite constraint but it seems that it might not be
> that easy as suggested by Luigi through emails.
>
> So from now the real question is, do you know how can I force the
> calibration to have AlphaIsFixed = False while at the same time returning a
> parameter which returns the correct value if the equation (6) from the paper
> is used?
>
> Thank you in advance,
>
> Mario
>
>
> Following there is what I have down so far
>
> ######
>
> int main(int argc, const char * argv[])
> {
> //~~~~~~~~~~~~~~~~~~~~~~~~~SABR Interpolation Curve
> std::cout << "SABR Interpolation" << std::endl;
> std::vector <Real> xVec(4), yVec(xVec.size());
>
> xVec[0] = 100; yVec[0] = 0.120232487; //Create vectors
> xVec[1] = 120; yVec[1] = 0.088666203;
> xVec[2] = 120.00000000001; yVec[2] = 0.0886662030001; //Trick to have the
> calibration working as you need n+1 observations to calibrate n parameters
> xVec[3] = 120.00000000002; yVec[3] = 0.0886662030002;//Trick to have the
> calibration working as you need n+1 observations to calibrate n parameters
>
> //SABR::SABR(4.649315068, 110.5, 0.5, 1, 0.5, 0.5, false,
> false, false, false); //It just assigns value within the private components
> of the class
> SABRInterpolation SABRLinInterpolation(xVec.begin(), xVec.end(),
> yVec.begin(), 3.649315068, 114.3, 0.087443, 1, 0.657465, -0.41797, false,
> true, false, false);
> SABRLinInterpolation.enableExtrapolation(); //This step is necessary to get
> the possibility of interpolate the curve outside the strikes provided
> {//Without Calibration
> for (double x = 90; x <= 150; x++)
> std::cout << "Sabr Vol at Strike " << x << ":" << SABRLinInterpolation(x)
> << std::endl;
> }
> std::cout << "The error is :" << SABRLinInterpolation.rmsError() <<
> std::endl << std::endl << std::endl;
>
> //~~~~~~~~~~~~~~~~~~~~~~~~~SABR Calibration
> {
> SABRLinInterpolation.update(); //Return Parameters
> Real Return_Parms[4] = { SABRLinInterpolation.alpha(),
> SABRLinInterpolation.beta(),SABRLinInterpolation.rho(),SABRLinInterpolation.nu()
> };
> std::cout << "The parameters calibrated are are (alpha, beta, rho and nu):
> " << std::endl;
> {
> for (int y = 0; y <= 3; y++)
> std::cout << Return_Parms[y] << std::endl;
> }
> std::cout << "\n\n";
> {
> for (double x = 90; x <= 150; x++)
> std::cout << "Sabr Vol at Strike (Calibrated) " << x << ":" <<
> SABRLinInterpolation(x) << std::endl;
> }
> std::cout << "\nThe error is :" << SABRLinInterpolation.rmsError() <<
> std::endl;
>
> system("pause");
> }
>
>
>
> --
> View this message in context: http://quantlib.10058.n7.nabble.com/SABR-Calibration-tp18226p18265.html
> Sent from the quantlib-users mailing list archive at Nabble.com.
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> QuantLib-users mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/quantlib-users


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
QuantLib-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/quantlib-users
Reply | Threaded
Open this post in threaded view
|

Re: SABR Calibration

Mario Marra
Hi Peter,

Thank you very much for taking the time to give me such a comprehensive response!

Regarding the last point, I can confirm you that I just tested it and I just needed 3 parameters to get the calibration and not 4 as I previously said. Thank you for that.

Regarding the SABRSmartAlphaSpecs, it seems that your response gets straight to the issue and you identified the changes to be made. I will try to solve this asap and post the code here as soon as I have a solution so you can decide whether a pull request would be beneficial.

I hope to be able to post it by tomorrow but if not, I will probably post at some point in June as I have an exam coming up and won't be working for the next 3 weeks.

Thank you again for your help.

Best regards,
Mario