public static double pricingVol(IVolSurface volSurf, Date exerciseDate, IOption option, double spot) { return(option.IsMoneynessOption ? //moneyness option , strike i.e. 120% of initialSpot volSurf.GetValue(exerciseDate, option.Strike * option.InitialSpotPrice, spot): volSurf.GetValue(exerciseDate, option.Strike, spot)); }
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)); }
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)); }
public LVSingleAsset(IVolSurface volSurface, DateTime startDate, DateTime expiryDate, int nTimeSteps, Func <double, double> forwardCurve, string name) { _surface = volSurface; _startDate = startDate; _expiryDate = expiryDate; _numberOfSteps = nTimeSteps; _name = name; _forwardCurve = forwardCurve; }
public void AddVolSurface(string name, IVolSurface surface) { if (IsFx(name)) { FundingModel.VolSurfaces[name] = surface; } else { _assetVols[new VolSurfaceKey(surface.AssetId, surface.Currency)] = surface; } }
public BlackScholesProcessWithQuantoForwardAdjustment(IYieldCurve spotRateCurve, IYieldCurve divCurve, IVolSurface volSurf, double rho, IVolSurface fxVolSurf) : base() { _spotRateCurve = spotRateCurve; _dividendCurve = divCurve; _volSurf = volSurf; _correlation = rho; _fxVolSurf = fxVolSurf; _isConstantRate = false; _isConstantVol = false; }
public CompositeVolSurface(string name, string assetId, Currency ccy, IVolSurface assetSurface, IFundingModel fundingModel, double correlation, CompositeVolType calculationType) { AssetSurface = assetSurface; FundingModel = fundingModel; Correlation = correlation; CalculationType = calculationType; Name = name; AssetId = assetId; Currency = ccy; _Pair = FundingModel.FxMatrix.GetFxPair(AssetSurface.Currency, Currency); }
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); }
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)); }
public LVSingleAsset(IVolSurface volSurface, DateTime startDate, DateTime expiryDate, int nTimeSteps, Func <double, double> forwardCurve, string name, Dictionary <DateTime, double> pastFixings = null, IATMVolSurface fxAdjustSurface = null, double fxAssetCorrelation = 0.0) { _surface = volSurface; _startDate = startDate; _expiryDate = expiryDate; _numberOfSteps = nTimeSteps; _name = name; _pastFixings = pastFixings ?? (new Dictionary <DateTime, double>()); _forwardCurve = forwardCurve; _adjSurface = fxAdjustSurface; _correlation = fxAssetCorrelation; }
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)); }
public static double[][] ComputeLocalVarianceOnGridFromCalls(this IVolSurface VanillaSurface, double[][] strikes, double[] timeSteps, Func <double, double> forwardFunc) { var numberOfTimesteps = timeSteps.Length; var deltaK = 0.001 * forwardFunc(timeSteps[0]); var lvGrid = new double[numberOfTimesteps - 1][]; var fwds = timeSteps.Select(t => forwardFunc(t)).ToArray(); //ParallelUtils.Instance.For(1, numberOfTimesteps, 1, it => for (var it = 1; it < numberOfTimesteps; it++) { var T = timeSteps[it]; var T1 = timeSteps[it - 1]; var fwd = fwds[it]; var fwdtm1 = fwds[it - 1]; var rmq = Log(fwd / fwdtm1) / (T - T1); var numberOfStrikes = strikes[it - 1].Length; var cInterp = VanillaSurface.GeneratePremiumInterpolator(numberOfStrikes * 2, T, fwd, OptionType.C); lvGrid[it - 1] = new double[numberOfStrikes]; if (numberOfStrikes > 1) { for (var ik = 0; ik < numberOfStrikes; ik++) { var K = strikes[it][ik]; var V = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd); var C = BlackFunctions.BlackPV(fwd, K, 0.0, T, V, OptionType.C); var Vtm1 = VanillaSurface.GetVolForAbsoluteStrike(K, T1, fwdtm1); //var dcdt = -BlackFunctions.BlackTheta(fwd, K, 0.0, T, V, OptionType.C); var dcdt = -(BlackFunctions.BlackPV(fwdtm1, K, 0.0, T1, Vtm1, OptionType.C) - C) / (T - T1); var dcdk = cInterp.FirstDerivative(K); var d2cdk2 = cInterp.SecondDerivative(K); var localVariance = d2cdk2 == 0 ? V * V : (dcdt - rmq * (C - K * dcdk)) / (0.5 * K * K * d2cdk2); lvGrid[it - 1][ik] = localVariance; } } else { var K = strikes[it][0]; var V = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd); lvGrid[it - 1][0] = V * V; } }//, false).Wait(); return(lvGrid); }
public bool TryGetVolSurface(string name, out IVolSurface volSurface) { if (VolSurfaces.TryGetValue(name, out volSurface)) { return(true); } if (TryGetInverseSurface(name, out volSurface)) { return(true); } volSurface = null; return(false); }
public bool TryGetVolSurface(string name, out IVolSurface surface, Currency currency = null) { surface = null; if (IsFx(name)) { return(FundingModel.TryGetVolSurface(name, out surface)); } if (currency != null) { return(_assetVols.TryGetValue(new VolSurfaceKey(name, currency), out surface)); } surface = _assetVols.Where(x => name.Contains("~") ? x.Key.ToString() == name : x.Key.AssetId == name).FirstOrDefault().Value; return(surface != default(IVolSurface)); }
public static TO_VolSurface GetTransportObject(this IVolSurface volSurface) { switch (volSurface) { case RiskyFlySurface rf: return(new TO_VolSurface { RiskyFlySurface = rf.GetTransportObject() }); case GridVolSurface gs: return(new TO_VolSurface { GridVolSurface = gs.GetTransportObject() }); case ConstantVolSurface cs: return(new TO_VolSurface { ConstantVolSurface = cs.GetTransportObject() }); default: throw new Exception("Unable to serialize volsurface"); } }
public LVSingleAsset(IVolSurface volSurface, DateTime startDate, DateTime expiryDate, int nTimeSteps, Func <double, double> forwardCurve, string name, Dictionary <DateTime, double> pastFixings = null, IATMVolSurface fxAdjustSurface = null, double fxAssetCorrelation = 0.0) { _surface = volSurface; _startDate = startDate; _expiryDate = expiryDate; _numberOfSteps = nTimeSteps; _name = name; _pastFixings = pastFixings ?? (new Dictionary <DateTime, double>()); _forwardCurve = forwardCurve; _adjSurface = fxAdjustSurface; _correlation = fxAssetCorrelation; if (volSurface is InverseFxSurface || (_adjSurface != null && _adjSurface?.AssetId == volSurface.AssetId)) { _siegelInvert = true; } if (_adjSurface != null && _adjSurface?.AssetId == volSurface.AssetId) { _adjSurface = null; } }
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)); }
public BlackScholesProcess(IYieldCurve spotRateCurve, IYieldCurve divCurve, IVolSurface volSurf, double[] times = null) { _spotRateCurve = spotRateCurve; _dividendCurve = divCurve; _volSurf = volSurf; _isConst = false; if (times == null) { return; } //cache forward rate _spotRateCurveForwardrateDict = new Dictionary <double, double>(); _dividendCurveForwardrateDict = new Dictionary <double, double>(); for (var i = 0; i < times.Length - 1; ++i) { var t0 = times[i]; var dt = times[i + 1] - times[i]; _spotRateCurveForwardrateDict[Math.Round(t0, Precision)] = _spotRateCurve.GetForwardRate(t0, dt, _spotRateCurve.Compound); _dividendCurveForwardrateDict[Math.Round(t0, Precision)] = _dividendCurve.GetForwardRate(t0, dt, _dividendCurve.Compound); } _isCached = true; }
public void AddVolSurface(VolSurfaceKey key, IVolSurface surface) => _assetVols[key] = surface;
public static IInterpolator1D GeneratePremiumInterpolator(this IVolSurface surface, int numSamples, DateTime expiry, double fwd, OptionType cp) => GeneratePremiumInterpolator(surface, numSamples, surface.OriginDate.CalculateYearFraction(expiry, DayCountBasis.Act365F), fwd, cp);
public void AddVolSurface(string name, IVolSurface surface) => _assetVols[new VolSurfaceKey(surface.AssetId, surface.Currency)] = surface;
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)); }
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)); }
public static double[][] ComputeLocalVarianceOnGrid(this IVolSurface VanillaSurface, double[][] strikes, double[] timeSteps, Func <double, double> forwardFunc) { var numberOfTimesteps = timeSteps.Length; var deltaK = 0.001 * forwardFunc(timeSteps[0]); var lvGrid = new double[numberOfTimesteps - 1][]; var Ss = new double[numberOfTimesteps]; for (var i = 0; i < Ss.Length; i++) { Ss[i] = forwardFunc(timeSteps[i]); } for (var it = 1; it < numberOfTimesteps; it++) { var numberOfStrikes = strikes[it - 1].Length; lvGrid[it - 1] = new double[numberOfStrikes]; double K, V, S, Td, dwdT, localVariance, TdSq, T, T1; double V_t1, V_Kp2, V_Km2, K_tm1, St; double y, yPlus, yPlus2, yMinus, yMinus2, dwdY, dwdY_p, dwdY_m, d2wd2Y, w, w_t1, w_kPlus2, w_kMinus2; //, Y1, Y2; T = timeSteps[it]; T1 = timeSteps[it - 1]; Td = T - T1; TdSq = Sqrt(Td); S = Ss[it]; St = Ss[it - 1]; var fwd = forwardFunc(T); for (var ik = 0; ik < numberOfStrikes; ik++) { K = strikes[it][ik]; K_tm1 = K * St / S; y = Log(K / S); yPlus = Log((K + deltaK) / S); yPlus2 = Log((K + deltaK * 2) / S); yMinus = Log((K - deltaK) / S); yMinus2 = Log((K - deltaK * 2) / S); //Y1 = Log(Sqrt(K * K + 2 * deltaK * K) / S); //Y2 = Log(Sqrt(K * K - 2 * deltaK * K) / S); V = VanillaSurface.GetVolForAbsoluteStrike(K, T, fwd); w = V * V * T; V_t1 = VanillaSurface.GetVolForAbsoluteStrike(K_tm1, T1, fwd); w_t1 = V_t1 * V_t1 * T1; V_Kp2 = VanillaSurface.GetVolForAbsoluteStrike(K + deltaK * 2, T, fwd); w_kPlus2 = V_Kp2 * V_Kp2 * T; V_Km2 = VanillaSurface.GetVolForAbsoluteStrike(K - deltaK * 2, T, fwd); w_kMinus2 = V_Km2 * V_Km2 * T; dwdT = (w - w_t1) / Td; dwdY_m = (w - w_kMinus2) / (y - yMinus2); dwdY_p = (w_kPlus2 - w) / (yPlus2 - y); dwdY = (dwdY_m + dwdY_p) / 2; //d2wd2Y = (dwdY_p - dwdY_m) / (Y1 - Y2); d2wd2Y = (dwdY_p - dwdY_m) / (yPlus - yMinus); localVariance = dwdT / (1 - y / w * dwdY + 0.25 * (-0.25 - 1 / w + (y * y / (w))) * dwdY * dwdY + 0.5 * d2wd2Y); lvGrid[it - 1][ik] = localVariance; } } return(lvGrid); }
public void RemoveVolSurface(IVolSurface surface) { var key = new VolSurfaceKey(surface.AssetId, surface.Currency); _assetVols.Remove(key); }
public static double StrikeForPV(double targetPV, double forward, double knownAverage, IVolSurface volSurface, DateTime evalDate, DateTime avgStartDate, DateTime avgEndDate, double riskFree, OptionType callPut) { var minStrike = forward / 100.0; var maxStrike = forward * 100.0; var volDate = avgStartDate.Average(avgEndDate); Func <double, double> testFunc = (absK => { var vol = volSurface.GetVolForAbsoluteStrike(absK, volDate, forward); var pv = PV(forward, knownAverage, vol, absK, evalDate, avgStartDate, avgEndDate, riskFree, callPut); return(targetPV - pv); }); var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, minStrike, maxStrike, 1e-8); return(solvedStrike); }
private bool TryGetInverseSurface(string name, out IVolSurface volSurface) { var inverseName = name.Substring(name.Length - 3, 3) + "/" + name.Substring(0, 3); return(VolSurfaces.TryGetValue(inverseName, out volSurface)); }
public static double StrikeForPV(double targetPV, double[] forwards, DateTime[] fixingDates, IVolSurface volSurface, DateTime evalDate, DateTime payDate, double riskFree, OptionType callPut) { var minStrike = forwards.Min() / 100.0; var maxStrike = forwards.Max() * 100.0; var ixMin = Array.BinarySearch(fixingDates, evalDate); if (ixMin < 0) { ixMin = ~ixMin; } Func <double, double> testFunc = (absK => { var vols = fixingDates.Select((d, ix) => ix >= ixMin ? volSurface.GetVolForAbsoluteStrike(absK, d, forwards[ix]) : 0.0).ToArray(); var pv = PV(forwards, fixingDates, evalDate, payDate, vols, absK, riskFree, callPut); return(targetPV - pv); }); var solvedStrike = Math.Solvers.Brent.BrentsMethodSolve(testFunc, minStrike, maxStrike, 1e-8); return(solvedStrike); }