예제 #1
0
        public static IInterpolator1D GenerateCompositeSmileBasic(this IVolSurface surface, IVolSurface fxSurface, int numSamples, DateTime expiry, double fwdAsset, double fwdFx, double correlation, bool deltaStrikeOutput = false)
        {
            var deltaKa  = fwdAsset * 0.00001;
            var deltaKfx = fwdFx * 0.00001;

            var t = surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F);

            var atmFx = fxSurface.GetVolForAbsoluteStrike(fwdFx, t, fwdFx);
            var atmA  = surface.GetVolForAbsoluteStrike(fwdAsset, t, fwdAsset);

            var compoFwd = fwdAsset * fwdFx;
            var atmCompo = Sqrt(atmFx * atmFx + atmA * atmA + 2.0 * correlation * atmA * atmFx);
            var lowK     = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(compoFwd, -0.0001, 0, t, atmCompo);
            var hiK      = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(compoFwd, -0.9999, 0, t, atmCompo);
            var lowKA    = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwdAsset, -0.0001, 0, t, atmA);
            var hiKA     = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwdAsset, -0.9999, 0, t, atmA);

            var x = new double[numSamples];
            var y = new double[numSamples];

            var k = lowK;

            var kStep   = (hiK - lowK) / numSamples;
            var kStepA  = (hiKA - lowKA) / numSamples;
            var kStepFx = (hiK / hiKA - lowK / lowKA) / numSamples;

            for (var i = 0; i < x.Length; i++)
            {
                x[i] = k;
                var kA     = lowKA;
                var totalP = 0.0;
                for (var j = 0; j < numSamples; j++)
                {
                    var kFx            = k / kA;
                    var volFx          = fxSurface.GetVolForAbsoluteStrike(kFx, t, fwdFx);
                    var volA           = surface.GetVolForAbsoluteStrike(kA, t, fwdAsset);
                    var volC           = Sqrt(volFx * volFx + volA * volA + 2.0 * correlation * volA * volFx);
                    var fxBucketLow    = kFx - deltaKfx / 2.0;
                    var fxBucketHi     = kFx + deltaKfx / 2.0;
                    var assetBucketLow = kA - deltaKa / 2.0;
                    var assetBucketHi  = kA + deltaKa / 2.0;
                    var weight         = 1.0;
                    y[i]   += weight * volC;
                    totalP += weight;
                    kA     += kStepA;
                }

                y[i] /= totalP;
                k    += kStep;
            }

            if (deltaStrikeOutput)
            {
                x = x.Select((q, ix) => - BlackFunctions.BlackDelta(compoFwd, q, 0.0, t, y[ix], OptionType.P)).ToArray();
            }

            return(InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.LinearFlatExtrap));
        }
예제 #2
0
        public static double InverseCDFex(this IVolSurface surface, double t, double fwd, double p)
        {
            var deltaK    = fwd * 1e-10;
            var lowGuess  = fwd / 2;
            var highGuess = fwd * 2;

            var targetFunc = new Func <double, double>(k =>
            {
                var volM = surface.GetVolForAbsoluteStrike(k - deltaK, t, fwd);
                var volP = surface.GetVolForAbsoluteStrike(k + deltaK, t, fwd);
                var pvM  = BlackFunctions.BlackPV(fwd, k - deltaK, 0.0, t, volM, OptionType.P);
                var pvP  = BlackFunctions.BlackPV(fwd, k + deltaK, 0.0, t, volP, OptionType.P);
                var digi = (pvP - pvM) / (2 * deltaK);
                //var digi = BlackFunctions.BlackDigitalPV(fwd, k, 0, t, surface.GetVolForAbsoluteStrike(k, t, fwd), OptionType.P);
                return(p - digi);
            });

            var breakCount = 0;

            while (targetFunc(lowGuess) < 0)
            {
                // highGuess = lowGuess*2.0;
                lowGuess /= 2.0;
                breakCount++;
                if (breakCount == 10)
                {
                    return(lowGuess);
                }
            }
            breakCount = 0;
            while (targetFunc(highGuess) > 0)
            {
                //lowGuess = highGuess/2.0;
                highGuess *= 2.0;
                breakCount++;
                if (breakCount == 10)
                {
                    return(highGuess);
                }
            }

            var b = Math.Solvers.Brent.BrentsMethodSolve(targetFunc, lowGuess, highGuess, 1e-8);

            //var b = Math.Solvers.Newton1D.MethodSolve2(targetFunc, fwd, 1e-6, 1000, fwd * 0.00001);
            if (double.IsInfinity(b) || double.IsNaN(b))
            {
                throw new Exception("Invalid strike found");
            }
            //if (b==lowGuess || b==highGuess)
            //    throw new Exception("Strike outside of bounds");

            return(b);
        }
예제 #3
0
        public static IInterpolator1D GeneratePDF(this IVolSurface surface, int numSamples, DateTime expiry, double fwd)
        {
            var deltaK = fwd * 0.0001;

            var t            = surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F);
            var lowStrikeVol = surface.GetVolForDeltaStrike(0.0001, t, fwd);
            var lowStrike    = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.0001, 0, t, lowStrikeVol);
            var hiStrikeVol  = surface.GetVolForDeltaStrike(0.9999, t, fwd);
            var hiStrike     = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.9999, 0, t, hiStrikeVol);

            var x = new double[numSamples + 2];
            var y = new double[numSamples + 2];

            var k = lowStrike;

            var kStep = (hiStrike - lowStrike) / numSamples;

            for (var i = 0; i < x.Length; i++)
            {
                if (i == 0)
                {
                    x[0] = lowStrike / 2.0;
                    y[0] = 0;
                    continue;
                }
                if (i == x.Length - 1)
                {
                    x[i] = k * 2;
                    y[i] = 0;
                    continue;
                }

                var volLow    = surface.GetVolForAbsoluteStrike(k - deltaK, t, fwd);
                var callLow   = BlackFunctions.BlackPV(fwd, k - deltaK, 0, t, volLow, OptionType.C);
                var volMid    = surface.GetVolForAbsoluteStrike(k, t, fwd);
                var callMid   = BlackFunctions.BlackPV(fwd, k, 0, t, volMid, OptionType.C);
                var volHi     = surface.GetVolForAbsoluteStrike(k + deltaK, t, fwd);
                var callHi    = BlackFunctions.BlackPV(fwd, k + deltaK, 0, t, volHi, OptionType.C);
                var digitalLo = (callLow - callMid) / deltaK;
                var digitalHi = (callMid - callHi) / deltaK;
                y[i] = (digitalLo - digitalHi) / deltaK;
                x[i] = k;
                k   += kStep;
            }

            var firstPass = InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.LinearFlatExtrap);
            var totalY    = ((IIntegrableInterpolator)firstPass).DefiniteIntegral(x.First(), x.Last());

            y = y.Select(v => v / totalY).ToArray();
            return(InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.LinearFlatExtrap));
        }
예제 #4
0
        public static double[][] ComputeLocalVarianceOnGridFromCalls(this IVolSurface VanillaSurface, double[][] strikes, double[] timeSteps, Func <double, double> forwardFunc)
        {
            var numberOfTimesteps = timeSteps.Length;
            var deltaK            = 0.001 * forwardFunc(timeSteps[0]);
            var lvGrid            = new double[numberOfTimesteps - 1][];

            var fwds = timeSteps.Select(t => forwardFunc(t)).ToArray();

            //ParallelUtils.Instance.For(1, numberOfTimesteps, 1, it =>
            for (var it = 1; it < numberOfTimesteps; it++)
            {
                var T               = timeSteps[it];
                var T1              = timeSteps[it - 1];
                var fwd             = fwds[it];
                var fwdtm1          = fwds[it - 1];
                var rmq             = Log(fwd / fwdtm1) / (T - T1);
                var numberOfStrikes = strikes[it - 1].Length;
                var cInterp         = VanillaSurface.GeneratePremiumInterpolator(numberOfStrikes * 2, T, fwd, OptionType.C);

                lvGrid[it - 1] = new double[numberOfStrikes];

                if (numberOfStrikes > 1)
                {
                    for (var ik = 0; ik < numberOfStrikes; ik++)
                    {
                        var K    = strikes[it][ik];
                        var V    = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd);
                        var C    = BlackFunctions.BlackPV(fwd, K, 0.0, T, V, OptionType.C);
                        var Vtm1 = VanillaSurface.GetVolForAbsoluteStrike(K, T1, fwdtm1);

                        //var dcdt = -BlackFunctions.BlackTheta(fwd, K, 0.0, T, V, OptionType.C);
                        var dcdt   = -(BlackFunctions.BlackPV(fwdtm1, K, 0.0, T1, Vtm1, OptionType.C) - C) / (T - T1);
                        var dcdk   = cInterp.FirstDerivative(K);
                        var d2cdk2 = cInterp.SecondDerivative(K);

                        var localVariance = d2cdk2 == 0 ? V * V : (dcdt - rmq * (C - K * dcdk)) / (0.5 * K * K * d2cdk2);
                        lvGrid[it - 1][ik] = localVariance;
                    }
                }
                else
                {
                    var K = strikes[it][0];
                    var V = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd);
                    lvGrid[it - 1][0] = V * V;
                }
            }//, false).Wait();

            return(lvGrid);
        }
예제 #5
0
        public static IInterpolator1D GeneratePremiumInterpolator(this IVolSurface surface, int numSamples, double t, double fwd, OptionType cp)
        {
            var lowStrikeVol = surface.GetVolForDeltaStrike(0.001, t, fwd);
            var lowStrike    = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.001, 0, t, lowStrikeVol);
            var hiStrikeVol  = surface.GetVolForDeltaStrike(0.999, t, fwd);
            var hiStrike     = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.999, 0, t, hiStrikeVol);

            var x = new double[numSamples + 2];
            var y = new double[numSamples + 2];

            var k = lowStrike;

            var kStep = (hiStrike - lowStrike) / (numSamples + 1.0);

            var vol  = surface.GetVolForAbsoluteStrike(k / 10, t, fwd);
            var call = BlackFunctions.BlackPV(fwd, k / 10, 0, t, vol, cp);

            y[0] = call;
            x[0] = k / 10;

            for (var i = 0; i < x.Length - 1; i++)
            {
                vol      = surface.GetVolForAbsoluteStrike(k, t, fwd);
                call     = BlackFunctions.BlackPV(fwd, k, 0, t, vol, cp);
                y[i + 1] = call;
                x[i + 1] = k;
                k       += kStep;
            }

            vol             = surface.GetVolForAbsoluteStrike(k * 10, t, fwd);
            call            = BlackFunctions.BlackPV(fwd, k * 10, 0, t, vol, cp);
            y[x.Length - 1] = call;
            x[x.Length - 1] = k * 10;

            return(InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.MonotoneCubicSpline));
        }
예제 #6
0
        public static double StrikeForPV(double targetPV, double forward, double knownAverage, IVolSurface volSurface, DateTime evalDate, DateTime avgStartDate, DateTime avgEndDate, double riskFree, OptionType callPut)
        {
            var minStrike = forward / 100.0;
            var maxStrike = forward * 100.0;

            var volDate = avgStartDate.Average(avgEndDate);

            Func <double, double> testFunc = (absK =>
            {
                var vol = volSurface.GetVolForAbsoluteStrike(absK, volDate, forward);
                var pv = PV(forward, knownAverage, vol, absK, evalDate, avgStartDate, avgEndDate, riskFree, callPut);
                return(targetPV - pv);
            });

            var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, minStrike, maxStrike, 1e-8);

            return(solvedStrike);
        }
예제 #7
0
        public static double StrikeForPV(double targetPV, double[] forwards, DateTime[] fixingDates, IVolSurface volSurface, DateTime evalDate, DateTime payDate, double riskFree, OptionType callPut)
        {
            var minStrike = forwards.Min() / 100.0;
            var maxStrike = forwards.Max() * 100.0;

            var ixMin = Array.BinarySearch(fixingDates, evalDate);

            if (ixMin < 0)
            {
                ixMin = ~ixMin;
            }

            Func <double, double> testFunc = (absK =>
            {
                var vols = fixingDates.Select((d, ix) => ix >= ixMin ? volSurface.GetVolForAbsoluteStrike(absK, d, forwards[ix]) : 0.0).ToArray();
                var pv = PV(forwards, fixingDates, evalDate, payDate, vols, absK, riskFree, callPut);
                return(targetPV - pv);
            });

            var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, minStrike, maxStrike, 1e-8);

            return(solvedStrike);
        }
예제 #8
0
        public static double[][] ComputeLocalVarianceOnGrid(this IVolSurface VanillaSurface, double[][] strikes, double[] timeSteps, Func <double, double> forwardFunc)
        {
            var numberOfTimesteps = timeSteps.Length;
            var deltaK            = 0.001 * forwardFunc(timeSteps[0]);
            var lvGrid            = new double[numberOfTimesteps - 1][];

            var Ss = new double[numberOfTimesteps];

            for (var i = 0; i < Ss.Length; i++)
            {
                Ss[i] = forwardFunc(timeSteps[i]);
            }


            for (var it = 1; it < numberOfTimesteps; it++)
            {
                var numberOfStrikes = strikes[it - 1].Length;
                lvGrid[it - 1] = new double[numberOfStrikes];

                double K, V, S, Td, dwdT, localVariance, TdSq, T, T1;
                double V_t1, V_Kp2, V_Km2, K_tm1, St;
                double y, yPlus, yPlus2, yMinus, yMinus2, dwdY, dwdY_p, dwdY_m, d2wd2Y, w, w_t1, w_kPlus2, w_kMinus2; //, Y1, Y2;

                T    = timeSteps[it];
                T1   = timeSteps[it - 1];
                Td   = T - T1;
                TdSq = Sqrt(Td);
                S    = Ss[it];
                St   = Ss[it - 1];
                var fwd = forwardFunc(T);

                for (var ik = 0; ik < numberOfStrikes; ik++)
                {
                    K       = strikes[it][ik];
                    K_tm1   = K * St / S;
                    y       = Log(K / S);
                    yPlus   = Log((K + deltaK) / S);
                    yPlus2  = Log((K + deltaK * 2) / S);
                    yMinus  = Log((K - deltaK) / S);
                    yMinus2 = Log((K - deltaK * 2) / S);
                    //Y1 = Log(Sqrt(K * K + 2 * deltaK * K) / S);
                    //Y2 = Log(Sqrt(K * K - 2 * deltaK * K) / S);
                    V         = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd);
                    w         = V * V * T;
                    V_t1      = VanillaSurface.GetVolForAbsoluteStrike(K_tm1, T1, fwd);
                    w_t1      = V_t1 * V_t1 * T1;
                    V_Kp2     = VanillaSurface.GetVolForAbsoluteStrike(K + deltaK * 2, T, fwd);
                    w_kPlus2  = V_Kp2 * V_Kp2 * T;
                    V_Km2     = VanillaSurface.GetVolForAbsoluteStrike(K - deltaK * 2, T, fwd);
                    w_kMinus2 = V_Km2 * V_Km2 * T;


                    dwdT   = (w - w_t1) / Td;
                    dwdY_m = (w - w_kMinus2) / (y - yMinus2);
                    dwdY_p = (w_kPlus2 - w) / (yPlus2 - y);
                    dwdY   = (dwdY_m + dwdY_p) / 2;

                    //d2wd2Y = (dwdY_p - dwdY_m) / (Y1 - Y2);
                    d2wd2Y = (dwdY_p - dwdY_m) / (yPlus - yMinus);

                    localVariance = dwdT / (1 - y / w * dwdY + 0.25 * (-0.25 - 1 / w + (y * y / (w))) * dwdY * dwdY + 0.5 * d2wd2Y);

                    lvGrid[it - 1][ik] = localVariance;
                }
            }

            return(lvGrid);
        }