Пример #1
0
        public void SABRSurfaceRRBF()
        {
            //flat surface
            var origin = new DateTime(2017, 02, 07);
            var expiry = origin.AddYears(1);
            var t      = (expiry - origin).TotalDays / 365.0;
            var fwd    = 1.5;
            var vol    = 0.32;
            var rr     = new[] { new[] { 0.02, 0.03 } };
            var bf     = new[] { new[] { 0.005, 0.007 } };

            Func <double, double> fwdCurve = (tt => { return(fwd); });

            var surface  = new SabrVolSurface(origin, new[] { vol }, new[] { expiry }, new[] { 0.25, 0.1 }, rr, bf, new[] { 100.0 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Math.Interpolation.Interpolator1DType.Linear);
            var gSurface = new RiskyFlySurface(origin, new[] { vol }, new[] { expiry }, new[] { 0.25, 0.1 }, rr, bf, new[] { 100.0 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Math.Interpolation.Interpolator1DType.Linear, Math.Interpolation.Interpolator1DType.Linear);

            var atmK = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, 0.5, 0.0, t, vol);

            Assert.Equal(vol, surface.GetVolForAbsoluteStrike(atmK, expiry, fwd), 2);

            var v25c = gSurface.GetVolForDeltaStrike(0.75, expiry, fwd);
            var v25p = gSurface.GetVolForDeltaStrike(0.25, expiry, fwd);
            var k25c = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, 0.25, 0.0, t, v25c);
            var k25p = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.25, 0.0, t, v25p);

            var t25c = surface.GetVolForAbsoluteStrike(k25c, expiry, fwd);
            var t25p = surface.GetVolForAbsoluteStrike(k25p, expiry, fwd);

            Assert.Equal(rr[0][0], t25c - t25p, 2);
        }
Пример #2
0
        public double GetVolForAbsoluteStrike(double strike, double maturity, double forward)
        {
            if (StrikeType == StrikeType.Absolute)
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                          _interpolators.Select(x => x.Interpolate(strike)).ToArray(),
                                                                          TimeInterpolatorType);
                return(interpForStrike.Interpolate(maturity));
            }
            else
            {
                var fwd = forward;
                var cp  = strike < 0 ? OptionType.Put : OptionType.Call;
                Func <double, double> testFunc = (deltaK =>
                {
                    var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                              _interpolators.Select(x => x.Interpolate(deltaK)).ToArray(),
                                                                              TimeInterpolatorType);
                    var vol = interpForStrike.Interpolate(maturity);
                    var absK = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, maturity, vol);
                    return(absK - strike);
                });

                var solvedStrike          = Qwack.Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 0.999999999, 1e-8);
                var interpForSolvedStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                                _interpolators.Select(x => x.Interpolate(solvedStrike)).ToArray(),
                                                                                TimeInterpolatorType);
                return(interpForSolvedStrike.Interpolate(maturity));
            }
        }
Пример #3
0
        private double GetDeltaStrikeForAbs(double fwd, double strike, double maturity)
        {
            var cp = strike < 0 ? OptionType.Put : OptionType.Call;
            Func <double, double> testFunc = (deltaK =>
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble, ExpiriesDouble.Select(e => GetVolForDeltaStrike(deltaK, e, fwd)).ToArray(), TimeInterpolatorType);
                var vol2 = interpForStrike.Interpolate(maturity);
                var absK = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, maturity, vol2);
                return(absK - strike);
            });

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

            if (solvedStrike == 0.00000000001 || solvedStrike == 0.99999999999) //out of bounds
            {
                var upperK = testFunc(-0.00000000001);
                var lowerK = testFunc(-0.99999999999);
                if (Abs(upperK - fwd) < Abs(lowerK - fwd))
                {
                    solvedStrike = 0.00000000001;
                }
                else
                {
                    solvedStrike = 0.99999999999;
                }
            }

            return(solvedStrike);
        }
Пример #4
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));
        }
Пример #5
0
        public double GetVolForAbsoluteStrike(double strike, double maturity, double forward)
        {
            var key = $"{strike:f6}~{maturity:f3}~{forward:f6}";

            if (_allowCaching && _absVolCache.TryGetValue(key, out var vol))
            {
                return(vol);
            }

            if (StrikeType == StrikeType.Absolute)
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                          _interpolators.Select(x => x.Interpolate(strike)).ToArray(),
                                                                          TimeInterpolatorType);
                vol = interpForStrike.Interpolate(maturity);
            }
            else
            {
                var fwd = forward;
                var cp  = strike < 0 ? OptionType.Put : OptionType.Call;
                Func <double, double> testFunc = (deltaK =>
                {
                    var dkModified = FlatDeltaSmileInExtreme ? Min(1.0 - FlatDeltaPoint, Max(deltaK, FlatDeltaPoint)) : deltaK;
                    var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                              _interpolators.Select(x => x.Interpolate(-dkModified)).ToArray(),
                                                                              TimeInterpolatorType);
                    var vol2 = interpForStrike.Interpolate(maturity);
                    var absK = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, deltaK, 0, maturity, vol2);
                    return(absK - strike);
                });

                var hiK          = FlatDeltaSmileInExtreme ? 1.0 - FlatDeltaPoint : 0.999999999;
                var loK          = FlatDeltaSmileInExtreme ? FlatDeltaPoint : 0.000000001;
                var solvedStrike = -Math.Solvers.Brent.BrentsMethodSolve(testFunc, -hiK, -loK, 1e-12);
                if (solvedStrike == loK || solvedStrike == hiK) //out of bounds
                {
                    var upperK = testFunc(-loK);
                    var lowerK = testFunc(-hiK);
                    if (Abs(upperK - fwd) < Abs(lowerK - fwd))
                    {
                        solvedStrike = loK;
                    }
                    else
                    {
                        solvedStrike = hiK;
                    }
                }
                var interpForSolvedStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                                _interpolators.Select(x => x.Interpolate(solvedStrike)).ToArray(),
                                                                                TimeInterpolatorType);
                vol = interpForSolvedStrike.Interpolate(maturity);
            }

            if (_allowCaching)
            {
                _absVolCache[key] = vol;
            }
            return(vol);
        }
Пример #6
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));
        }
Пример #7
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));
        }
Пример #8
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));
        }
Пример #9
0
        public void DeltaStrikeMappingFacts()
        {
            var t   = 1.0;
            var k   = 100;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.0;
            var cp  = OptionType.P;

            //black forward delta matches
            var delta    = BlackFunctions.BlackDelta(f, k, rf, t, vol, cp);
            var absolute = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(f, delta, rf, t, vol);

            Assert.Equal(k, absolute, 10);
        }
Пример #10
0
        public static IInterpolator1D GenerateCDF(this IInterpolator1D smile, int numSamples, double t, double fwd)
        {
            var deltaK = fwd * 0.0001;

            var atmVol    = smile.Interpolate(fwd);
            var lowStrike = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.0001, 0, t, atmVol);
            var hiStrike  = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.9999, 0, t, atmVol);

            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] = k / 2.0;
                    y[0] = 0;
                    continue;
                }
                if (i == x.Length - 1)
                {
                    x[i] = k * 2;
                    y[i] = 1;
                    continue;
                }
                var volLow  = smile.Interpolate(k - deltaK / 2.0);
                var putLow  = BlackFunctions.BlackPV(fwd, k - deltaK / 2.0, 0, t, volLow, OptionType.P);
                var volHi   = smile.Interpolate(k + deltaK / 2.0);
                var putHi   = BlackFunctions.BlackPV(fwd, k + deltaK / 2.0, 0, t, volHi, OptionType.P);
                var digital = (putHi - putLow) / deltaK;
                y[i] = digital;
                x[i] = k;
                k   += kStep;
            }

            return(InterpolatorFactory.GetInterpolator(x, y, Interpolator1DType.Linear));
        }
Пример #11
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));
        }
Пример #12
0
        public void SolveSmileMarket()
        {
            var valDate = new DateTime(2018, 07, 28);
            var expDate = valDate.AddDays(365);
            var tExp    = (expDate - valDate).TotalDays / 365.0;
            var fwd     = 1000;

            double[] strikes = { 0.25, 0.5, 0.75 };

            var atmConstraint = new ATMStraddleConstraint
            {
                ATMVolType = AtmVolType.ZeroDeltaStraddle,
                MarketVol  = 0.32
            };

            var smile25d = new RRBFConstraint
            {
                Delta         = 0.25,
                FlyVol        = 0.01,
                RisykVol      = 0.02,
                WingQuoteType = WingQuoteType.Market
            };

            var s = new AssetSmileSolver();

            if (IsCoverageOnly)
            {
                s.Tollerance = 1;
            }

            var smile = s.Solve(atmConstraint, new[] { smile25d }, valDate, expDate, fwd, strikes, Interpolator1DType.Linear);

            if (!IsCoverageOnly)
            {
                Assert.Equal(atmConstraint.MarketVol, smile[1], 8);
            }

            var surface = new GridVolSurface(valDate, strikes, new[] { expDate }, new[] { smile }, StrikeType.ForwardDelta, Interpolator1DType.Linear, Interpolator1DType.Linear, DayCountBasis.Act365F);

            //reprice market RR structrure off smile, premium must match
            var marketVolC  = atmConstraint.MarketVol + smile25d.FlyVol + 0.5 * smile25d.RisykVol;
            var marketVolP  = atmConstraint.MarketVol + smile25d.FlyVol - 0.5 * smile25d.RisykVol;
            var marketKC25  = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, 0.25, 0, tExp, marketVolC);
            var marketKP25  = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.25, 0, tExp, marketVolP);
            var marketC25FV = BlackFunctions.BlackPV(fwd, marketKC25, 0, tExp, marketVolC, OptionType.C);
            var marketP25FV = BlackFunctions.BlackPV(fwd, marketKP25, 0, tExp, marketVolP, OptionType.P);
            var marketRR    = marketC25FV - marketP25FV;

            var volC25d  = surface.GetVolForAbsoluteStrike(marketKC25, expDate, fwd);
            var volP25d  = surface.GetVolForAbsoluteStrike(marketKP25, expDate, fwd);
            var call25FV = BlackFunctions.BlackPV(fwd, marketKC25, 0, tExp, volC25d, OptionType.C);
            var put25FV  = BlackFunctions.BlackPV(fwd, marketKP25, 0, tExp, volP25d, OptionType.P);
            var smileRR  = call25FV - put25FV;

            if (!IsCoverageOnly)
            {
                Assert.Equal(marketRR, smileRR, 8);
            }

            //reprice market BF structrure off smile, premium must match
            var marketVolBF   = atmConstraint.MarketVol + smile25d.FlyVol;
            var marketKBFC25  = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, 0.25, 0, tExp, marketVolBF);
            var marketKBFP25  = BlackFunctions.AbsoluteStrikefromDeltaKAnalytic(fwd, -0.25, 0, tExp, marketVolBF);
            var marketBFC25FV = BlackFunctions.BlackPV(fwd, marketKBFC25, 0, tExp, marketVolBF, OptionType.C);
            var marketBFP25FV = BlackFunctions.BlackPV(fwd, marketKBFP25, 0, tExp, marketVolBF, OptionType.P);
            var marketBF      = marketBFC25FV + marketBFP25FV;

            var volCBF25d  = surface.GetVolForAbsoluteStrike(marketKBFC25, expDate, fwd);
            var volPBF25d  = surface.GetVolForAbsoluteStrike(marketKBFP25, expDate, fwd);
            var callBF25FV = BlackFunctions.BlackPV(fwd, marketKBFC25, 0, tExp, volCBF25d, OptionType.C);
            var putBF25FV  = BlackFunctions.BlackPV(fwd, marketKBFP25, 0, tExp, volPBF25d, OptionType.P);
            var smileBF    = callBF25FV + putBF25FV;

            if (!IsCoverageOnly)
            {
                Assert.Equal(marketBF, smileBF, 8);
            }
        }
Пример #13
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));
        }
Пример #14
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));
        }