Example #1
0
        public static IInterpolator1D GenerateCDF(this IVolSurface surface, int numSamples, DateTime expiry, double fwd, bool returnInverse = false)
        {
            var deltaKLow  = 0.0000001;
            var deltaKHi   = 0.9999999;
            var kStepD     = (deltaKHi - deltaKLow) / (numSamples + 3);
            var deltaKBump = deltaKLow / 10;

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

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


            for (var i = 0; i < x.Length; i++)
            {
                var deltaKNew = deltaKLow + i * kStepD;
                var mStrike   = deltaKNew - deltaKBump / 2;
                var pStrike   = deltaKNew + deltaKBump / 2;

                var mStrikeVol = surface.GetVolForDeltaStrike(mStrike, t, fwd);
                var mk         = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -mStrike, 0, t, mStrikeVol);
                var pStrikeVol = surface.GetVolForDeltaStrike(pStrike, t, fwd);
                var pk         = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -pStrike, 0, t, pStrikeVol);

                if (i == 0)
                {
                    x[0] = mk / 2.0;
                    y[0] = 0;
                    continue;
                }
                if (i == x.Length - 1)
                {
                    x[i] = pk * 2;
                    y[i] = 1;
                    continue;
                }

                var dkAbs = (pk - mk);

                var pPut = BlackFunctions.BlackPV(fwd, pk, 0, t, pStrikeVol, OptionType.P);
                var mPut = BlackFunctions.BlackPV(fwd, mk, 0, t, mStrikeVol, OptionType.P);


                var digital = (pPut - mPut) / dkAbs;
                y[i] = digital;
                x[i] = (mk + pk) / 2.0;
            }

            return(returnInverse ?
                   InterpolatorFactory.GetInterpolator(y, x, Interpolator1DType.LinearFlatExtrap) :
                   InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.LinearFlatExtrap));
        }
Example #2
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));
        }
Example #3
0
        public static IInterpolator1D GenerateCDF2(this IVolSurface surface, int numSamples, DateTime expiry, double fwd, bool returnInverse = false, double strikeScale = 1.0, bool logStrikes = false)
        {
            var premInterp = GeneratePremiumInterpolator(surface, numSamples, expiry, fwd, OptionType.P);
            var t          = surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F);

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

            var deltaKLow = 0.0000000001;
            var deltaKHi  = 0.9999999999;
            var kStepD    = (deltaKHi - deltaKLow) / numSamples;

            for (var i = 0; i < x.Length; i++)
            {
                var deltaKNew    = -deltaKLow - i * kStepD;
                var newStrikeVol = surface.GetVolForDeltaStrike(-deltaKNew, t, fwd);
                var k            = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaKNew, 0, t, newStrikeVol);
                var digital      = premInterp.FirstDerivative(k);
                y[i] = digital;
                x[i] = k * strikeScale;
                if (logStrikes)
                {
                    x[i] = Log(x[i]);
                }
            }

            return(returnInverse ?
                   InterpolatorFactory.GetInterpolator(y, x, Interpolator1DType.MonotoneCubicSpline) :
                   InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.MonotoneCubicSpline));
        }
Example #4
0
        public void Finish(IFeatureCollection collection)
        {
            if (!_timesteps.IsComplete)
            {
                return;
            }

            //drifts and vols...
            _drifts    = new Vector <double> [_timesteps.TimeStepCount];
            _lvInterps = new IInterpolator1D[_timesteps.TimeStepCount - 1];

            var strikes = new double[_timesteps.TimeStepCount][];
            var atmVols = new double[_timesteps.TimeStepCount];

            for (var t = 0; t < strikes.Length; t++)
            {
                var fwd = _forwardCurve(_timesteps.Times[t]);
                atmVols[t] = _surface.GetVolForDeltaStrike(0.5, _timesteps.Times[t], fwd);

                if (_timesteps.Times[t] == 0)
                {
                    strikes[t] = new double[] { fwd };
                    continue;
                }
                else
                {
                    var nStrikes   = 200;
                    var strikeStep = 1.0 / nStrikes;
                    strikes[t] = new double[nStrikes];
                    for (var k = 0; k < strikes[t].Length; k++)
                    {
                        var deltaK = -(strikeStep + strikeStep * k);
                        strikes[t][k] = Options.BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, _timesteps.Times[t], atmVols[t]);
                    }
                }
            }

            var lvSurface = Options.LocalVol.ComputeLocalVarianceOnGridFromCalls(_surface, strikes, _timesteps.Times, _forwardCurve);

            for (var t = 0; t < _lvInterps.Length; t++)
            {
                _lvInterps[t] = InterpolatorFactory.GetInterpolator(strikes[t], lvSurface[t], t == 0 ? Interpolator1DType.DummyPoint : Interpolator1DType.LinearFlatExtrap);
            }

            var prevSpot = _forwardCurve(0);

            for (var t = 1; t < _drifts.Length; t++)
            {
                var fxAtmVol = _adjSurface == null ? 0.0 : _adjSurface.GetForwardATMVol(0, _timesteps.Times[t]);
                var driftAdj = _adjSurface == null ? 1.0 : Exp(atmVols[t] * fxAtmVol * _timesteps.Times[t] * _correlation);
                var spot     = _forwardCurve(_timesteps.Times[t]) * driftAdj;

                _drifts[t] = new Vector <double>(Log(spot / prevSpot) / _timesteps.TimeSteps[t]);

                prevSpot = spot;
            }
            _isComplete = true;
        }
Example #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));
        }
Example #6
0
        public void Finish(FeatureCollection collection)
        {
            if (!_timesteps.IsComplete)
            {
                return;
            }

            //drifts and vols...
            _drifts    = new double[_timesteps.TimeStepCount];
            _lvInterps = new IInterpolator1D[_timesteps.TimeStepCount - 1];

            var strikes = new double[_timesteps.TimeStepCount][];

            for (var t = 0; t < strikes.Length; t++)
            {
                strikes[t] = new double[98];
                var fwd    = _forwardCurve(_timesteps.Times[t]);
                var atmVol = _surface.GetVolForDeltaStrike(fwd, _timesteps.Times[t], fwd);
                for (var k = 0; k < strikes[t].Length; k++)
                {
                    var deltaK = -(0.01 + 0.01 * k);
                    strikes[t][k] = Options.BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, _timesteps.Times[t], atmVol);
                }
            }

            var lvSurface = Options.LocalVol.ComputeLocalVarianceOnGrid(_surface, strikes, _timesteps.Times, _forwardCurve);

            for (var t = 0; t < _lvInterps.Length; t++)
            {
                _lvInterps[t] = InterpolatorFactory.GetInterpolator(strikes[t], lvSurface[t], t == 0 ? Interpolator1DType.DummyPoint : Interpolator1DType.LinearFlatExtrap);
            }

            var prevSpot = _forwardCurve(0);

            for (var t = 1; t < _drifts.Length; t++)
            {
                var spot = _forwardCurve(_timesteps.Times[t]);
                _drifts[t] = System.Math.Log(spot / prevSpot) / _timesteps.TimeSteps[t];

                prevSpot = spot;
            }
            _isComplete = true;
        }
Example #7
0
        public static IInterpolator1D GenerateCompositeSmileB(this IVolSurface surface, IVolSurface fxSurface, int numSamples, DateTime expiry, double fwdAsset, double fwdFx, double correlation, bool strikesInDeltaSpace = false)
        {
            var t     = surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F);
            var fxInv = new InverseFxSurface("fxInv", fxSurface as IATMVolSurface, null);

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

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

            //var cdfInvFx = fxSurface.GenerateCDF2(numSamples * 10, expiry, fwdFx, true);
            //var cdfInvAsset = surface.GenerateCDF2(numSamples * 10, expiry, fwdAsset, true);
            //var yFx = new Func<double, double>(z => cdfInvFx.Interpolate(Statistics.NormSDist(z)));
            //var yAsset = new Func<double, double>(z => cdfInvAsset.Interpolate(Statistics.NormSDist(z)));

            var fxCDFCache    = new Dictionary <double, double>();
            var assetCDFCache = new Dictionary <double, double>();
            var yFx           = new Func <double, double>(z =>
            {
                if (fxCDFCache.TryGetValue(z, out var K))
                {
                    return(K);
                }
                K = fxInv.InverseCDF(expiry, 1.0 / fwdFx, Statistics.NormSDist(z));
                fxCDFCache.Add(z, K);
                return(K);
            });
            var yAsset = new Func <double, double>(z =>
            {
                if (assetCDFCache.TryGetValue(z, out var K))
                {
                    return(K);
                }
                K = surface.InverseCDF(expiry, fwdAsset, Statistics.NormSDist(z));
                assetCDFCache.Add(z, K);
                return(K);
            });

            //var fxCDFCache = new Dictionary<double, double>();
            //var assetCDFCache = new Dictionary<double, double>();
            //var putFx = fxInv.GeneratePremiumInterpolator(numSamples * 10, expiry, 1.0/fwdFx, OptionType.P);
            //var putAsset = surface.GeneratePremiumInterpolator(numSamples * 10, expiry, fwdAsset, OptionType.P);
            //var yFx = new Func<double, double>(z =>
            //{
            //    if (fxCDFCache.TryGetValue(z, out var K)) return K;
            //    K = InverseCDF(putFx, t, 1.0/fwdFx, Statistics.NormSDist(z));
            //    fxCDFCache.Add(z, K);
            //    return K;
            //});
            //var yAsset = new Func<double, double>(z =>
            //{
            //    if (assetCDFCache.TryGetValue(z, out var K)) return K;
            //    K = InverseCDF(putAsset, t, fwdAsset, Statistics.NormSDist(z));
            //    var kl = assetCDFCache.Keys.ToList();
            //    var closerIx = kl.BinarySearch(z);
            //    var keyIx = ~closerIx;
            //    if (closerIx < 0 && z < 0 && kl.Count > keyIx)
            //    {
            //        if (assetCDFCache[kl[keyIx]] < K)
            //            K = assetCDFCache[kl[keyIx]];
            //    }
            //    assetCDFCache.Add(z, K);
            //    return K;
            //});

            var payoff    = new Func <double, double, double, double>((z1, z2, kQ) => Max(kQ * yFx(z2) - yAsset(z1), 0));
            var integrand = new Func <double, double, double, double>((z1, z2, kQ) => payoff(z1, z2, kQ) * BivariateNormal.PDF(z1, z2, -correlation));

            var kStep    = (hiK - lowK) / numSamples;
            var ks       = Enumerable.Range(0, numSamples).Select(kk => lowK + kk * kStep).ToArray();
            var premiums = new double[ks.Length];
            var vols     = new double[ks.Length];

            for (var i = 0; i < ks.Length; i++)
            {
                var ik = new Func <double, double, double>((z1, z2) => integrand(z1, z2, ks[i]));
                var pk = Integration.TwoDimensionalGaussLegendre(ik, -5, 5, -5, 5, 16);
                //var pk = Integration.TwoDimensionalSimpsons(ik, -5, 5, -5, 5, 100);
                pk *= fwdFx;
                var volK = BlackFunctions.BlackImpliedVol(compoFwd, ks[i], 0.0, t, pk, OptionType.P);
                vols[i]     = volK;
                premiums[i] = pk;
            }


            if (strikesInDeltaSpace)
            {
                ks = ks.Select((ak, ix) => - BlackFunctions.BlackDelta(compoFwd, ak, 0.0, t, vols[ix], OptionType.P)).ToArray();
            }

            return(InterpolatorFactory.GetInterpolator(ks, vols, Interpolator1DType.CubicSpline));
        }
Example #8
0
        public static IInterpolator1D GenerateCompositeSmile(this IVolSurface surface, IVolSurface fxSurface, int numSamples, DateTime expiry, double fwdAsset, double fwdFx, double rho, bool strikesInDeltaSpace = false)
        {
            var t = surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F);

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

            var compoFwd = fwdAsset / fwdFx;
            var atmCompo = Sqrt(atmFx * atmFx + atmA * atmA + 2.0 * rho * atmA * atmFx);
            var lowK     = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(compoFwd, -0.01, 0, t, atmCompo);
            var hiK      = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(compoFwd, -0.99, 0, t, atmCompo);

            var nuA  = Sqrt(t) * atmA;
            var nuFx = Sqrt(t) * atmFx;

            var cdfFx = new Func <double, double>(k => fxSurface.CDF(expiry, fwdFx, Exp(k)));
            var cdfA  = new Func <double, double>(k => surface.CDF(expiry, fwdAsset, Exp(k)));

            var fxCDFCache    = new Dictionary <double, double>();
            var assetCDFCache = new Dictionary <double, double>();
            var yFx           = new Func <double, double>(z =>
            {
                if (fxCDFCache.TryGetValue(z, out var K))
                {
                    return(K);
                }
                K = Log(fxSurface.InverseCDF(expiry, fwdFx, Statistics.NormSDist(z)));
                fxCDFCache.Add(z, K);
                return(K);
            });
            var yA = new Func <double, double>(z =>
            {
                if (assetCDFCache.TryGetValue(z, out var K))
                {
                    return(K);
                }
                K = Log(surface.InverseCDF(expiry, fwdAsset, Statistics.NormSDist(z)));
                assetCDFCache.Add(z, K);
                return(K);
            });

            //var zfxS = new Func<double, double, double>((zA, K) => Statistics.NormInv(Max(1e-18, Min(1.0 - 1e-18, cdfFx(yA(zA) - Log(K))))));
            //var zAs = new Func<double, double, double>((zFx, K) => Statistics.NormInv(Max(1e-18, Min(1.0 - 1e-18, cdfA(yFx(zFx) + Log(K))))));
            var zfxS = new Func <double, double, double>((zA, K) => Statistics.NormInv(cdfFx(yA(zA) - Log(K))));
            var zAs  = new Func <double, double, double>((zFx, K) => Statistics.NormInv(cdfA(yFx(zFx) + Log(K))));

            var d  = -1.0;
            var p2 = 1.0 / Sqrt(2.0 * PI);
            //var I1 = new Func<double, double, double>((zA, K) =>
            //p2*Exp(yA(zA) - (nuA * zA - nuA * nuA / 2)) * Statistics.NormSDist(d * (zfxS(zA, K) - rho * zA) / Sqrt(1 - rho * rho)) * Exp(-(zA - nuA) * (zA - nuA) / 2.0)
            //    );
            //var I2 = new Func<double, double, double>((zFx, K) =>
            //p2*Exp(yFx(zFx) - (nuFx * zFx - nuFx * nuFx / 2)) * Statistics.NormSDist(-d * (zAs(zFx, K) - rho * zFx) / Sqrt(1 - rho * rho)) * Exp(-(zFx - nuFx) * (zFx - nuFx) / 2.0)
            //    );
            var I1 = new Func <double, double, double>((zA, K) =>
                                                       p2 * Exp(yA(zA)) * Statistics.NormSDist(d * (zfxS(zA, K) - rho * zA) / Sqrt(1 - rho * rho)) * Exp(-(zA * zA) / 2.0)
                                                       );
            var I2 = new Func <double, double, double>((zFx, K) =>
                                                       p2 * Exp(yFx(zFx)) * Statistics.NormSDist(-d * (zAs(zFx, K) - rho * zFx) / Sqrt(1 - rho * rho)) * Exp(-(zFx * zFx) / 2.0)
                                                       );


            var kStep    = (hiK - lowK) / numSamples;
            var ks       = Enumerable.Range(0, numSamples).Select(kk => lowK + kk * kStep).ToArray();
            var premiums = new double[ks.Length];
            var vols     = new double[ks.Length];

            for (var i = 0; i < ks.Length; i++)
            {
                var I1k = new Func <double, double>(z => I1(z, ks[i]));
                var I2k = new Func <double, double>(z => I2(z, ks[i]));

                //var i1 = Integration.GaussLegendre(I1k, -5, 5, 16);
                //var i2 = Integration.GaussLegendre(I2k, -5, 5, 16);
                var i1 = Integration.SimpsonsRule(I1k, -5, 5, numSamples);
                var i2 = Integration.SimpsonsRule(I2k, -5, 5, numSamples);
                var pk = d * (i1 - ks[i] * i2);
                pk /= fwdFx;
                var volK = BlackFunctions.BlackImpliedVol(compoFwd, ks[i], 0.0, t, pk, OptionType.P);
                vols[i]     = volK;
                premiums[i] = pk;
            }


            if (strikesInDeltaSpace)
            {
                ks = ks.Select((ak, ix) => - BlackFunctions.BlackDelta(compoFwd, ak, 0.0, t, vols[ix], OptionType.P)).ToArray();
            }

            return(InterpolatorFactory.GetInterpolator(ks, vols, Interpolator1DType.CubicSpline));
        }