예제 #1
0
        public static double Delta(double forward, double knownAverage, double sigma, double K, double tAvgStart, double tExpiry, double riskFree, OptionType callPut)
        {
            var tau = Max(0, tAvgStart);
            var M   = 2 * (Exp(sigma * sigma * tExpiry) - Exp(sigma * sigma * tau) * (1 + sigma * sigma * (tExpiry - tau)));

            M /= Pow(sigma, 4.0) * (tExpiry - tau) * (tExpiry - tau);

            var sigma_a = Sqrt(Log(M) / tExpiry);

            K = AsianUtils.AdjustedStrike(K, knownAverage, tExpiry, tAvgStart);

            if (K <= 0)
            {
                if (callPut == OptionType.P)
                {
                    return(0);
                }
                var t2     = tExpiry - tAvgStart;
                var expAvg = knownAverage * (t2 - tExpiry) / t2 + forward * tExpiry / t2;
                var df     = Exp(-riskFree * tExpiry);
                return(df * (expAvg - K));
            }

            var delta = BlackFunctions.BlackDelta(forward, K, riskFree, tExpiry, sigma_a, callPut);

            if (tAvgStart < 0)
            {
                delta *= tExpiry / (tExpiry - tAvgStart);
            }
            return(delta);
        }
예제 #2
0
        public void PathsGenerated()
        {
            var vol = 0.32;

            using var engine = new PathEngine(IsCoverageOnly ? 2.IntPow(6) : 2 << 10);
            engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64()
            {
                UseNormalInverse = true
            });
            var asset2 = new ConstantVolSingleAsset
                         (
                startDate: DateTime.Now.Date,
                expiry: DateTime.Now.Date.AddYears(1),
                vol: vol,
                spot: 500,
                drift: 0.00,
                numberOfSteps: IsCoverageOnly ? 1 : 365,
                name: "TestAsset2"
                         );

            engine.AddPathProcess(asset2);
            var payoff = new EuropeanPut("TestAsset2", 500, DateTime.Now.Date.AddYears(1));

            engine.AddPathProcess(payoff);
            engine.SetupFeatures();
            engine.RunProcess();

            var pv      = payoff.AverageResult;
            var blackPv = BlackFunctions.BlackPV(500, 500, 0, 1, vol, OptionType.P);

            if (!IsCoverageOnly)
            {
                Assert.Equal(blackPv, pv, 0);
            }
        }
예제 #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 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);
        }
예제 #5
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));
        }
예제 #6
0
        public void BarrierFacts()
        {
            var t   = 1.0;
            var k   = 100;
            var b   = 0.0;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.C;

            //zero barrier knock-in down is worthless
            var PV = BlackFunctions.BarrierOptionPV(f, k, rf, t, vol, cp, b, BarrierType.KI, BarrierSide.Down);

            Assert.Equal(0.0, PV, 10);

            //zero barrier knock-in up is worth vanilla
            var vanillaPV = BlackFunctions.BlackPV(f, k, rf, t, vol, cp);

            PV = BlackFunctions.BarrierOptionPV(f, k, rf, t, vol, cp, b, BarrierType.KI, BarrierSide.Up);
            Assert.Equal(vanillaPV, PV, 10);

            //ki forward is worth same as fwd
            b = 100;
            k = 110;
            var PVc   = BlackFunctions.BarrierOptionPV(f, k, rf, t, vol, OptionType.C, b, BarrierType.KI, BarrierSide.Down);
            var PVp   = BlackFunctions.BarrierOptionPV(f, k, rf, t, vol, OptionType.P, b, BarrierType.KI, BarrierSide.Down);
            var df    = Exp(-rf * t);
            var fwdPV = (f - k) * df;

            Assert.Equal(fwdPV, PVc - PVp, 10);
        }
예제 #7
0
        public void VegaFacts()
        {
            var t   = 1.0;
            var k   = 100;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;

            //vega closely matches numerical estimate
            var PV1     = BlackFunctions.BlackPV(f, k, rf, t, vol - 0.00005, cp);
            var PV2     = BlackFunctions.BlackPV(f, k, rf, t, vol + 0.00005, cp);
            var vegaEst = (PV2 - PV1) / 0.0001 * 0.01;
            var vega    = BlackFunctions.BlackVega(f, k, rf, t, vol);

            Assert.Equal(vegaEst, vega, 6);

            //all else the same, more time==more vega
            var vegaNear = BlackFunctions.BlackVega(f, k, rf, t, vol);
            var vegaFar  = BlackFunctions.BlackVega(f, k, rf, t * 2, vol);

            Assert.True(vegaFar > vegaNear);

            //cases for zero vega
            vega = BlackFunctions.BlackVega(f, 0, rf, t, vol);
            Assert.Equal(0, vega, 8);

            vega = BlackFunctions.BlackVega(f, 1e6, rf, t, vol);
            Assert.Equal(0, vega, 8);
        }
예제 #8
0
        public void ThetaFacts()
        {
            var t   = 1.0;
            var k   = 100;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;


            //theta closely matches numerical estimate
            var bumpT    = 1e-10;
            var PV1      = BlackFunctions.BlackPV(f, k, rf, t, vol, cp);
            var PV2      = BlackFunctions.BlackPV(f, k, rf, t - bumpT, vol, cp);
            var thetaEst = (PV2 - PV1) / bumpT;
            var theta    = BlackFunctions.BlackTheta(f, k, rf, t, vol, cp);

            Assert.Equal(thetaEst, theta, 3);


            //theta closely matches numerical estimate
            cp       = OptionType.C;
            PV1      = BlackFunctions.BlackPV(f, k, rf, t, vol, cp);
            PV2      = BlackFunctions.BlackPV(f, k, rf, t - bumpT, vol, cp);
            thetaEst = (PV2 - PV1) / bumpT;
            theta    = BlackFunctions.BlackTheta(f, k, rf, t, vol, cp);
            Assert.Equal(thetaEst, theta, 3);
        }
예제 #9
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));
            }
        }
예제 #10
0
        public double GetVolForDeltaStrike(double deltaStrike, double maturity, double forward)
        {
            if (StrikeType == StrikeType.ForwardDelta)
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                          _interpolators.Select(x => x.Interpolate(deltaStrike)).ToArray(),
                                                                          TimeInterpolatorType);
                return(interpForStrike.Interpolate(maturity));
            }
            else
            {
                var fwd = forward;
                var cp  = deltaStrike < 0 ? OptionType.Put : OptionType.Call;
                Func <double, double> testFunc = (absK =>
                {
                    var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                              _interpolators.Select(x => x.Interpolate(absK)).ToArray(),
                                                                              TimeInterpolatorType);
                    var vol = interpForStrike.Interpolate(maturity);
                    var deltaK = BlackFunctions.BlackDelta(fwd, absK, 0, maturity, vol, cp);
                    return(deltaK - System.Math.Abs(deltaStrike));
                });

                var solvedStrike          = Qwack.Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 10 * fwd, 1e-8);
                var interpForSolvedStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                                _interpolators.Select(x => x.Interpolate(solvedStrike)).ToArray(),
                                                                                TimeInterpolatorType);
                return(interpForSolvedStrike.Interpolate(maturity));
            }
        }
예제 #11
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);
        }
예제 #12
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));
        }
예제 #13
0
        public void LVMC_PathsGenerated()
        {
            var origin = DateTime.Now.Date;

            using var engine = new PathEngine(2.IntPow(IsCoverageOnly ? 6 : 12))
                  {
                      Parallelize = false
                  };

            engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64()
            {
                UseNormalInverse = true,
                UseAnthithetic   = true
            });

            var tenorsStr  = new[] { "1m", "2m", "3m", "6m" };
            var tenors     = tenorsStr.Select(x => new Frequency(x));
            var expiries   = tenors.Select(t => origin.AddPeriod(RollType.F, new Calendar(), t)).ToArray();
            var deltaKs    = new[] { 0.1, 0.25, 0.5, 0.75, 0.9 };
            var smileVols  = new[] { 0.32, 0.3, 0.29, 0.3, 0.32 };
            var vols       = Enumerable.Repeat(smileVols, expiries.Length).ToArray();
            var tExp       = (origin.AddMonths(6) - origin).TotalDays / 365.0;
            var volSurface = new GridVolSurface(origin, deltaKs, expiries, vols,
                                                StrikeType.ForwardDelta, Interpolator1DType.GaussianKernel,
                                                Interpolator1DType.LinearInVariance, DayCountBasis.Act365F);

            var fwdCurve = new Func <double, double>(t => { return(900 + 100 * t / tExp); });
            var asset    = new LVSingleAsset
                           (
                startDate: origin,
                expiryDate: origin.AddMonths(6),
                volSurface: volSurface,
                forwardCurve: fwdCurve,
                nTimeSteps: IsCoverageOnly ? 3 : 100,
                name: "TestAsset"
                           );

            engine.AddPathProcess(asset);
            var payoff  = new EuropeanPut("TestAsset", 900, origin.AddMonths(6));
            var payoff2 = new EuropeanCall("TestAsset", 0, origin.AddMonths(6));

            engine.AddPathProcess(payoff);
            engine.AddPathProcess(payoff2);
            engine.SetupFeatures();
            engine.RunProcess();

            var pv       = payoff.AverageResult;
            var blackVol = volSurface.GetVolForAbsoluteStrike(900, origin.AddMonths(6), fwdCurve(tExp));
            var blackPv  = BlackFunctions.BlackPV(fwdCurve(tExp), 900, 0, tExp, blackVol, OptionType.P);

            if (!IsCoverageOnly)
            {
                Assert.True(System.Math.Abs(blackPv / pv - 1.0) < 0.02);
                var fwd = payoff2.AverageResult;
                Assert.True(System.Math.Abs(fwdCurve(tExp) / fwd - 1.0) < 0.005);
            }
        }
예제 #14
0
        public void AbsKFromDelta_Facts()
        {
            var vol    = 0.32;
            var fwd    = 100.0;
            var k      = 115.0;
            var t      = 1.5;
            var deltaK = Qwack.Options.BlackFunctions.BlackDelta(fwd, k, 0, t, vol, OptionType.C);

            Assert.Equal(k, (double)BlackFunctions.AbsoluteStrikeFromDelta(t, deltaK, fwd, vol, 0), 12);
        }
예제 #15
0
        public void PVFacts()
        {
            var t   = 1.0;
            var t2  = 2.0;
            var k   = 0;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;

            //expired is worthless
            var PV = TurnbullWakeman.PV(f, 0, vol, 0, t, 0, rf, OptionType.P);

            Assert.Equal(0, PV, 10);
            PV = TurnbullWakeman.PV(f, 0, vol, 0, t, 0, rf, OptionType.C);
            Assert.Equal(0, PV, 10);

            //zero strike put is worthless
            PV = TurnbullWakeman.PV(f, 0, vol, 0, t, t2, rf, cp);
            Assert.Equal(0, PV, 10);
            PV = TurnbullWakeman.PV(f, 50, vol, 0, -0.1, t2, rf, cp);
            Assert.Equal(0, PV, 10);

            //zero strike call is worth discounted fwd
            cp = OptionType.C;
            PV = TurnbullWakeman.PV(f, 0, vol, 0, t, t2, rf, cp);
            Assert.Equal(System.Math.Exp(-rf * t2) * f, PV, 2);

            //OTM option with zero vol is worthless
            vol = 0.0;
            k   = f + 1;
            PV  = TurnbullWakeman.PV(f, k, vol, 0, t, t2, rf, cp);
            Assert.Equal(0, PV, 10);

            //put-call parity at f==k
            k   = f;
            vol = 0.32;
            var PVcall = TurnbullWakeman.PV(f, 0, vol, k, t, t2, rf, OptionType.C);
            var PVput  = TurnbullWakeman.PV(f, 0, vol, k, t, t2, rf, OptionType.P);

            Assert.Equal(PVcall, PVput, 2);

            //independent fwds version
            var valDate         = new DateTime(2019, 10, 24);
            var fixingStartDate = new DateTime(2019, 10, 01);
            var fixingEndDate   = new DateTime(2019, 10, 25);
            var fixingDates     = DateExtensions.BusinessDaysInPeriod(fixingStartDate, fixingEndDate, TestProviderHelper.CalendarProvider.Collection["NYC"]).ToArray();
            var fwds            = fixingDates.Select(x => 100.0).ToArray();
            var sigmas          = fixingDates.Select(x => 0.32).ToArray();

            PV = TurnbullWakeman.PV(fwds, fixingDates, valDate, fixingEndDate, sigmas, 1, 0.0, OptionType.C, true);
            var blackPV = BlackFunctions.BlackPV(100.0, 1, 0.0, 1 / 365.0, 0.32, OptionType.C);

            Assert.Equal(blackPV, PV, 4);
        }
예제 #16
0
        public void LVMC_PathsGenerated()
        {
            var origin = DateTime.Now.Date;
            var engine = new PathEngine(2.IntPow(17));

            //engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64()
            //{
            //    UseNormalInverse = true,
            //    UseAnthithetic = false
            //});
            engine.AddPathProcess(new Random.Sobol.SobolShiftedPathGenerator(new Random.Sobol.SobolDirectionNumbers(s_directionNumbers), 0)
            {
                UseNormalInverse = true
            });
            var tenorsStr = new[] { "1m", "2m", "3m", "6m", "9m", "1y" };
            var tenors    = tenorsStr.Select(x => new Frequency(x));
            var expiries  = tenors.Select(t => origin.AddPeriod(RollType.F, new Calendar(), t)).ToArray();
            var deltaKs   = new[] { -0.1, -0.25, -0.5, -0.75, -0.9 };
            var smileVols = new[] { 0.32, 0.3, 0.29, 0.3, 0.32 };
            var vols      = Enumerable.Repeat(smileVols, expiries.Length).ToArray();

            var volSurface = new GridVolSurface(origin, deltaKs, expiries, vols,
                                                Core.Basic.StrikeType.ForwardDelta, Interpolator1DType.LinearFlatExtrap,
                                                Interpolator1DType.LinearInVariance, DayCountBasis.Act365F);

            var fwdCurve = new Func <double, double>(t => { return(900 + 100 * t); });
            var asset    = new LVSingleAsset
                           (
                startDate: origin,
                expiryDate: origin.AddYears(1),
                volSurface: volSurface,
                forwardCurve: fwdCurve,
                nTimeSteps: 365,
                name: "TestAsset"
                           );

            engine.AddPathProcess(asset);
            var payoff  = new EuropeanPut("TestAsset", 900, origin.AddYears(1));
            var payoff2 = new EuropeanCall("TestAsset", 0, origin.AddYears(1));

            engine.AddPathProcess(payoff);
            engine.AddPathProcess(payoff2);
            engine.SetupFeatures();
            engine.RunProcess();
            var pv       = payoff.AverageResult;
            var blackVol = volSurface.GetVolForAbsoluteStrike(900, origin.AddYears(1), fwdCurve(1.0));
            var blackPv  = BlackFunctions.BlackPV(1000, 900, 0, 1, blackVol, OptionType.P);

            Assert.Equal(blackPv, pv, 0);
            var fwd = payoff2.AverageResult;

            Assert.True(System.Math.Abs(fwdCurve(1) / fwd - 1.0) < 0.001);
            //var output = new OutputPathsToImage(engine,2000,1000);
        }
예제 #17
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);
        }
예제 #18
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));
        }
예제 #19
0
        public void GridVolSurfaceAbsolute()
        {
            //flat surface
            var origin     = new DateTime(2017, 02, 07);
            var strikes    = new double[] { 1, 2 };
            var maturities = new DateTime[] { new DateTime(2017, 04, 06), new DateTime(2017, 06, 07) };
            var vols       = new double[][]
            {
                new double[] { 0.32, 0.32 },
                new double[] { 0.32, 0.32 }
            };
            var surface = new Qwack.Options.VolSurfaces.GridVolSurface(
                origin, strikes, maturities, vols,
                Core.Basic.StrikeType.Absolute,
                Math.Interpolation.Interpolator1DType.Linear,
                Math.Interpolation.Interpolator1DType.Linear,
                Dates.DayCountBasis.Act_365F);

            var fwd = 1.5;
            Func <double, double> fwdCurve = (t => { return(fwd); });

            Assert.Equal(vols[0][0], surface.GetVolForAbsoluteStrike(999, origin.AddDays(33), fwd), 12);
            Assert.Equal(vols[0][0], surface.GetVolForDeltaStrike(-0.3, origin.AddDays(303), fwd), 12);
            Assert.Equal(vols[0][0], surface.GetVolForAbsoluteStrike(4, 0.777, fwd), 12);
            Assert.Equal(vols[0][0], surface.GetVolForDeltaStrike(0.9, 0.123, fwd), 12);

            //with some shape
            vols = new double[][]
            {
                new double[] { 0.16, 0.32 },
                new double[] { 0.32, 0.64 }
            };

            surface = new Qwack.Options.VolSurfaces.GridVolSurface(
                origin, strikes, maturities, vols,
                Core.Basic.StrikeType.Absolute,
                Math.Interpolation.Interpolator1DType.Linear,
                Math.Interpolation.Interpolator1DType.Linear,
                Dates.DayCountBasis.Act_365F);

            Assert.Equal(vols[0].Average(), surface.GetVolForAbsoluteStrike(1.5, maturities[0], fwd), 12);
            var midPoint = maturities[0].AddDays(((maturities[1] - maturities[0]).TotalDays / 2.0));

            Assert.Equal(vols.Select(x => x.Average()).Average(), surface.GetVolForAbsoluteStrike(1.5, midPoint, fwd), 12);

            //test delta-space function
            var vol          = surface.GetVolForAbsoluteStrike(1.75, maturities[0].AddDays(15), fwd);
            var deltaK       = BlackFunctions.BlackDelta(1.5, 1.75, 0, surface.ExpiriesDouble[0] + 15.0 / 365.0, vol, OptionType.C);
            var volForDeltaK = surface.GetVolForDeltaStrike(deltaK, maturities[0].AddDays(15), fwd);

            Assert.Equal(vol, volForDeltaK, 8);
        }
예제 #20
0
        public void PVFacts()
        {
            var evalDate = DateTime.Today;
            var avgStart = evalDate.AddDays(365);
            var avgEnd   = avgStart.AddDays(32);
            var t        = (avgEnd - evalDate).TotalDays / 365.0;

            var fixCal = new Calendar();

            var k   = 0;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;

            //zero strike put is worthless
            var PV = LME_Clewlow.PV(f, 0, vol, 0.0, evalDate, avgStart, avgEnd, rf, OptionType.P, fixCal);

            Assert.Equal(0, PV, 10);

            //zero strike call is worth discounted fwd
            PV = LME_Clewlow.PV(f, 0, vol, 0.0, evalDate, avgStart, avgEnd, rf, OptionType.C, fixCal);
            Assert.Equal(System.Math.Exp(-rf * t) * f, PV, 2);

            //OTM option with zero vol is worthless
            vol = 0.0;
            k   = f + 1;
            PV  = LME_Clewlow.PV(f, 0, vol, 0.0, evalDate, avgStart, avgEnd, rf, OptionType.C, fixCal);
            Assert.Equal(0, PV, 10);

            //put-call parity at f==k
            k   = f;
            vol = 0.32;
            var PVcall = LME_Clewlow.PV(f, 0, vol, k, evalDate, avgStart, avgEnd, rf, OptionType.C, fixCal);
            var PVput  = LME_Clewlow.PV(f, 0, vol, k, evalDate, avgStart, avgEnd, rf, OptionType.P, fixCal);

            Assert.Equal(PVcall, PVput, 2);

            //bullet defaults to european
            avgStart = avgEnd;
            PV       = LME_Clewlow.PV(f, 0.0, vol, k, evalDate, avgStart, avgEnd, rf, OptionType.P, fixCal);
            var blackPV = BlackFunctions.BlackPV(f, k, rf, t, vol, OptionType.P);

            Assert.Equal(blackPV, PV, 10);

            //on expiry its intrinsic
            evalDate = avgEnd;
            PV       = LME_Clewlow.PV(f, f, vol, f + 10, evalDate, avgStart, avgEnd, rf, OptionType.P, fixCal);
            Assert.Equal(10.0, PV, 10);
            PV = LME_Clewlow.PV(f, f, vol, f - 10, evalDate, avgStart, avgEnd, rf, OptionType.C, fixCal);
            Assert.Equal(10.0, PV, 10);
        }
예제 #21
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));
        }
예제 #22
0
        public void ImpliedVolFacts()
        {
            var t   = 1.0;
            var k   = 120;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;

            var PV         = BlackFunctions.BlackPV(f, k, rf, t, vol, cp);
            var impliedVol = BlackFunctions.BlackImpliedVol(f, k, rf, t, PV, cp);

            Assert.Equal(vol, impliedVol, 10);
        }
예제 #23
0
        public double GetVolForDeltaStrike(double deltaStrike, double maturity, double forward)
        {
            var cp = deltaStrike < 0 ? OptionType.Put : OptionType.Call;
            Func <double, double> testFunc = (absK =>
            {
                var volTest = GetVolForAbsoluteStrike(absK, maturity, forward);
                var deltaK = BlackFunctions.BlackDelta(forward, absK, 0, maturity, volTest, cp);
                return(deltaK - System.Math.Abs(deltaStrike));
            });

            var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 10 * forward, 1e-8);

            return(GetVolForAbsoluteStrike(solvedStrike, maturity, forward));
        }
예제 #24
0
        public void DeltaGammaFacts()
        {
            var t   = 1.0;
            var k   = 100;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;

            //delta closely matches numerical estimate
            var PV1      = BlackFunctions.BlackPV(f + 0.000005, k, rf, t, vol, cp);
            var PV2      = BlackFunctions.BlackPV(f - 0.000005, k, rf, t, vol, cp);
            var deltaEst = (PV1 - PV2) / 0.00001;
            var delta    = BlackFunctions.BlackDelta(f, k, rf, t, vol, cp);

            Assert.Equal(deltaEst, delta, 6);

            //all else the same, more time for OTM option == more delta
            k = 150;
            var deltaNear = BlackFunctions.BlackDelta(f, k, rf, t, vol, cp);
            var deltaFar  = BlackFunctions.BlackDelta(f, k, rf, t * 2, vol, cp);

            Assert.True(deltaFar > deltaNear);

            //put-call parity
            var deltaCall = BlackFunctions.BlackDelta(f, k, rf, t, vol, OptionType.C);
            var deltaPut  = BlackFunctions.BlackDelta(f, k, rf, t, vol, OptionType.P);

            var syntheticFwdDelta = deltaCall - deltaPut;

            Assert.Equal(System.Math.Exp(-rf * t), syntheticFwdDelta, 10);

            //gamma closely matches numerical estimate
            var delta1   = BlackFunctions.BlackDelta(f + 0.000005, k, rf, t, vol, cp);
            var delta2   = BlackFunctions.BlackDelta(f - 0.000005, k, rf, t, vol, cp);
            var gammaEst = (delta1 - delta2) / 0.00001;
            var gamma    = BlackFunctions.BlackGamma(f, k, rf, t, vol);

            Assert.Equal(gammaEst, gamma, 6);

            //cases for zero delta / gamma
            delta = BlackFunctions.BlackDelta(f, 0, rf, t, vol, OptionType.P);
            Assert.Equal(0, delta, 8);
            delta = BlackFunctions.BlackDelta(f, 1e6, rf, t, vol, OptionType.C);
            Assert.Equal(0, delta, 8);
            gamma = BlackFunctions.BlackGamma(f, 0, rf, t, vol);
            Assert.Equal(0, gamma, 8);
            gamma = BlackFunctions.BlackGamma(f, 1e6, rf, t, vol);
            Assert.Equal(0, gamma, 8);
        }
예제 #25
0
        public void PVFacts()
        {
            var t   = 1.0;
            var k   = 0;
            var f   = 100;
            var vol = 0.32;
            var rf  = 0.05;
            var cp  = OptionType.P;
            var df  = System.Math.Exp(-rf * t);

            //zero strike put is worthless
            var PV = BinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);

            Assert.Equal(0, PV, 10);
            PV = TrinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.Equal(0, PV, 10);

            //zero strike call is worth fwd with no discounting
            cp = OptionType.C;
            PV = BinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.Equal(f, PV, 10);
            PV = TrinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.Equal(f, PV, 10);

            //and has delta = 1.0
            var greeks = TrinomialTree.AmericanFutureOption(f, k, rf, t, vol, cp);

            Assert.Equal(1.0, (double)greeks[1, 0], 10);
            greeks = BinomialTree.AmericanFutureOption(f, k, rf, t, vol, cp);
            Assert.Equal(1.0, (double)greeks[1, 0], 10);

            //OTM option with zero vol is worthless
            vol = 0.0;
            k   = f + 1;
            PV  = BinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.Equal(0, PV, 10);
            PV = TrinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.Equal(0, PV, 10);

            //option worth >= black in all cases for same inputs
            vol = 0.32;
            k   = f + 20;
            var PVBlack = BlackFunctions.BlackPV(f, k, rf, t, vol, cp);

            PV = BinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.True(PV >= PVBlack);
            PV = TrinomialTree.AmericanFutureOptionPV(f, k, rf, t, vol, cp);
            Assert.True(PV >= PVBlack);
        }
예제 #26
0
        public void PremiumInterpolatorFacts()
        {
            var origin       = new DateTime(2017, 02, 07);
            var expiry       = origin.AddYears(1);
            var t            = (expiry - origin).TotalDays / 365.0;
            var volAsset     = 0.32;
            var fwd          = 100.0;
            var surfaceAsset = new ConstantVolSurface(origin, volAsset);

            var premInterp = surfaceAsset.GeneratePremiumInterpolator(100, expiry, fwd, OptionType.P);

            var strike = fwd * 0.8;

            Assert.Equal(BlackFunctions.BlackPV(fwd, strike, 0.0, t, volAsset, OptionType.P), premInterp.Interpolate(strike), 2);
        }
예제 #27
0
        private double GetAbsStrikeForDelta(double fwd, double deltaStrike, double maturity)
        {
            var cp = deltaStrike < 0 ? OptionType.Put : OptionType.Call;
            Func <double, double> testFunc = (absK =>
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble, ExpiriesDouble.Select(e => GetVolForAbsoluteStrike(absK, e, fwd)).ToArray(), TimeInterpolatorType);
                var vol2 = interpForStrike.Interpolate(maturity);
                var deltaK = BlackFunctions.BlackDelta(fwd, absK, 0, maturity, vol2, cp);
                return(deltaK - deltaStrike);
            });

            var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 50 * fwd, 1e-8);

            return(solvedStrike);
        }
예제 #28
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);
        }
예제 #29
0
        public double GetVolForDeltaStrike(double deltaStrike, double maturity, double forward)
        {
            if (deltaStrike > 1.0 || deltaStrike < -1.0)
            {
                throw new ArgumentOutOfRangeException($"Delta strike must be in range -1.0 < x < 1.0 - value was {deltaStrike}");
            }

            var key = $"{deltaStrike:f6}~{maturity:f3}~{forward:f6}";

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

            if (StrikeType == StrikeType.ForwardDelta)
            {
                var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                          _interpolators.Select(x => x.Interpolate(deltaStrike)).ToArray(),
                                                                          TimeInterpolatorType);
                vol = interpForStrike.Interpolate(maturity);
            }
            else
            {
                var fwd = forward;
                var cp  = deltaStrike < 0 ? OptionType.Put : OptionType.Call;
                Func <double, double> testFunc = (absK =>
                {
                    var interpForStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                              _interpolators.Select(x => x.Interpolate(absK)).ToArray(),
                                                                              TimeInterpolatorType);
                    var vol2 = interpForStrike.Interpolate(maturity);
                    var deltaK = BlackFunctions.BlackDelta(fwd, absK, 0, maturity, vol2, cp);
                    return(deltaK - Abs(deltaStrike));
                });

                var solvedStrike          = Math.Solvers.Brent.BrentsMethodSolve(testFunc, 0.000000001, 10 * fwd, 1e-8);
                var interpForSolvedStrike = InterpolatorFactory.GetInterpolator(ExpiriesDouble,
                                                                                _interpolators.Select(x => x.Interpolate(solvedStrike)).ToArray(),
                                                                                TimeInterpolatorType);
                vol = interpForSolvedStrike.Interpolate(maturity);
            }

            if (_allowCaching)
            {
                _deltaVolCache[key] = vol;
            }
            return(vol);
        }
예제 #30
0
        public static double GetVolForDeltaStrike(double deltaStrike, double maturity, double forward, Func <double, double> GetVolForAbsoluteStrike)
        {
            var fwd = forward;
            var cp  = OptionType.Put;

            Func <double, double> testFunc = (absK =>
            {
                var vol = GetVolForAbsoluteStrike(absK);
                var deltaK = System.Math.Abs(BlackFunctions.BlackDelta(fwd, absK, 0, maturity, vol, cp));
                return(deltaK - System.Math.Abs(deltaStrike));
            });

            var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, fwd / 10, 50 * fwd, 1e-8);

            return(GetVolForAbsoluteStrike(solvedStrike));
        }