public void SolveSmileSimple() { var valDate = new DateTime(2018, 07, 28); var expDate = valDate.AddDays(365); 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.Arithmatic }; 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); Assert.Equal(smile25d.RisykVol, smile[2] - smile[0], 8); Assert.Equal(smile25d.FlyVol, (smile[2] + smile[0]) / 2 - atmConstraint.MarketVol, 8); } }
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); } }
public RiskyFlySurface(DateTime originDate, double[] ATMVols, DateTime[] expiries, double[] wingDeltas, double[][] riskies, double[][] flies, double[] fwds, WingQuoteType wingQuoteType, AtmVolType atmVolType, Interpolator1DType strikeInterpType, Interpolator1DType timeInterpType, string[] pillarLabels = null) { if (pillarLabels == null) { PillarLabels = expiries.Select(x => x.ToString("yyyy-MM-dd")).ToArray(); } else { PillarLabels = pillarLabels; } if (ATMVols.Length != expiries.Length || expiries.Length != riskies.Length || riskies.Length != flies.Length) { throw new Exception("Inputs do not have consistent time dimensions"); } if (wingDeltas.Length != riskies[0].Length || riskies[0].Length != flies[0].Length) { throw new Exception("Inputs do not have consistent strike dimensions"); } var strikes = new double[2 * wingDeltas.Length + 1]; var vols = new double[expiries.Length][]; if (riskies.SelectMany(x => x).All(x => x == 0) && flies.SelectMany(x => x).All(x => x == 0)) { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[wingDeltas.Length - 1 - s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[wingDeltas.Length - 1 - s]; } for (var t = 0; t < expiries.Length; t++) { vols[t] = Enumerable.Repeat(ATMVols[t], strikes.Length).ToArray(); } } else { var atmConstraints = ATMVols.Select(a => new ATMStraddleConstraint { ATMVolType = atmVolType, MarketVol = a }).ToArray(); var needsFlip = wingDeltas.First() > wingDeltas.Last(); if (needsFlip) { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[wingDeltas.Length - 1 - s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[wingDeltas.Length - 1 - s]; } } else { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[s]; } } strikes[wingDeltas.Length] = 0.5; var wingConstraints = new RRBFConstraint[expiries.Length][]; var f = new AssetSmileSolver(); if (needsFlip) { for (var i = 0; i < wingConstraints.Length; i++) { var offset = wingDeltas.Length - 1; wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[offset - j], FlyVol = flies[i][offset - j], RisykVol = riskies[i][offset - j], WingQuoteType = wingQuoteType, }; } vols[i] = f.Solve(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], strikes, strikeInterpType); } } else { for (var i = 0; i < wingConstraints.Length; i++) { wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[j], FlyVol = flies[i][j], RisykVol = riskies[i][j], WingQuoteType = wingQuoteType, }; } vols[i] = f.Solve(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], strikes, strikeInterpType); } } } StrikeInterpolatorType = strikeInterpType; TimeInterpolatorType = timeInterpType; Expiries = expiries; ExpiriesDouble = expiries.Select(x => x.ToOADate()).ToArray(); Strikes = strikes; StrikeType = StrikeType.ForwardDelta; ATMs = ATMVols; Riskies = riskies; Flies = flies; WingDeltas = wingDeltas; Forwards = fwds; WingQuoteType = wingQuoteType; AtmVolType = atmVolType; base.Build(originDate, strikes, expiries, vols); }
public SVIVolSurface(DateTime originDate, double[] ATMVols, DateTime[] expiries, double[] wingDeltas, double[][] riskies, double[][] flies, double[] fwds, WingQuoteType wingQuoteType, AtmVolType atmVolType, Interpolator1DType timeInterpType, SviType sviType = SviType.Raw, string[] pillarLabels = null) : base() { if (pillarLabels == null) { PillarLabels = expiries.Select(x => x.ToString("yyyy-MM-dd")).ToArray(); } else { PillarLabels = pillarLabels; } if (ATMVols.Length != expiries.Length || expiries.Length != riskies.Length || riskies.Length != flies.Length) { throw new Exception("Inputs do not have consistent time dimensions"); } if (wingDeltas.Length != riskies[0].Length || riskies[0].Length != flies[0].Length) { throw new Exception("Inputs do not have consistent strike dimensions"); } var atmConstraints = ATMVols.Select(a => new ATMStraddleConstraint { ATMVolType = atmVolType, MarketVol = a }).ToArray(); var needsFlip = wingDeltas.First() > wingDeltas.Last(); var strikes = new double[2 * wingDeltas.Length + 1]; if (needsFlip) { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[wingDeltas.Length - 1 - s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[wingDeltas.Length - 1 - s]; } } else { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[s]; } } strikes[wingDeltas.Length] = 0.5; var wingConstraints = new RRBFConstraint[expiries.Length][]; RawParams = new SviRawParameters[expiries.Length]; var f = new AssetSmileSolver(); if (needsFlip) { for (var i = 0; i < wingConstraints.Length; i++) { var offset = wingDeltas.Length - 1; wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[offset - j], FlyVol = flies[i][offset - j], RisykVol = riskies[i][offset - j], WingQuoteType = wingQuoteType, }; } RawParams[i] = f.SolveSviRaw(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], true); } } else { for (var i = 0; i < wingConstraints.Length; i++) { wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[j], FlyVol = flies[i][j], RisykVol = riskies[i][j], WingQuoteType = wingQuoteType, }; } RawParams[i] = f.SolveSviRaw(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], true); } } OriginDate = originDate; TimeInterpolatorType = timeInterpType; Expiries = expiries; ExpiriesDouble = expiries.Select(x => originDate.CalculateYearFraction(x, TimeBasis)).ToArray(); _interps = new IInterpolator1D[5]; _interps[0] = InterpolatorFactory.GetInterpolator(ExpiriesDouble, RawParams.Select(x => x.A).ToArray(), TimeInterpolatorType); _interps[1] = InterpolatorFactory.GetInterpolator(ExpiriesDouble, RawParams.Select(x => x.B).ToArray(), TimeInterpolatorType); _interps[2] = InterpolatorFactory.GetInterpolator(ExpiriesDouble, RawParams.Select(x => x.M).ToArray(), TimeInterpolatorType); _interps[3] = InterpolatorFactory.GetInterpolator(ExpiriesDouble, RawParams.Select(x => x.Rho).ToArray(), TimeInterpolatorType); _interps[4] = InterpolatorFactory.GetInterpolator(ExpiriesDouble, RawParams.Select(x => x.Sigma).ToArray(), TimeInterpolatorType); _fwdsInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, fwds, Interpolator1DType.Linear); }
public SabrVolSurface(DateTime originDate, double[] ATMVols, DateTime[] expiries, double[] wingDeltas, double[][] riskies, double[][] flies, double[] fwds, WingQuoteType wingQuoteType, AtmVolType atmVolType, Interpolator1DType timeInterpType, string[] pillarLabels = null) { if (pillarLabels == null) { PillarLabels = expiries.Select(x => x.ToString("yyyy-MM-dd")).ToArray(); } else { PillarLabels = pillarLabels; } if (ATMVols.Length != expiries.Length || expiries.Length != riskies.Length || riskies.Length != flies.Length) { throw new Exception("Inputs do not have consistent time dimensions"); } if (wingDeltas.Length != riskies[0].Length || riskies[0].Length != flies[0].Length) { throw new Exception("Inputs do not have consistent strike dimensions"); } var atmConstraints = ATMVols.Select(a => new ATMStraddleConstraint { ATMVolType = atmVolType, MarketVol = a }).ToArray(); var needsFlip = wingDeltas.First() > wingDeltas.Last(); var strikes = new double[2 * wingDeltas.Length + 1]; if (needsFlip) { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[wingDeltas.Length - 1 - s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[wingDeltas.Length - 1 - s]; } } else { for (var s = 0; s < wingDeltas.Length; s++) { strikes[s] = wingDeltas[s]; strikes[strikes.Length - 1 - s] = 1.0 - wingDeltas[s]; } } strikes[wingDeltas.Length] = 0.5; var wingConstraints = new RRBFConstraint[expiries.Length][]; var parameters = new SABRParameters[expiries.Length]; var f = new AssetSmileSolver(); if (needsFlip) { for (var i = 0; i < wingConstraints.Length; i++) { var offset = wingDeltas.Length - 1; wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[offset - j], FlyVol = flies[i][offset - j], RisykVol = riskies[i][offset - j], WingQuoteType = wingQuoteType, }; } parameters[i] = f.SolveSABR(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], 1.0); } } else { for (var i = 0; i < wingConstraints.Length; i++) { wingConstraints[i] = new RRBFConstraint[wingDeltas.Length]; for (var j = 0; j < wingConstraints[i].Length; j++) { wingConstraints[i][j] = new RRBFConstraint { Delta = wingDeltas[j], FlyVol = flies[i][j], RisykVol = riskies[i][j], WingQuoteType = wingQuoteType, }; } parameters[i] = f.SolveSABR(atmConstraints[i], wingConstraints[i], originDate, expiries[i], fwds[i], 1.0); } } OriginDate = originDate; TimeInterpolatorType = timeInterpType; Expiries = expiries; ExpiriesDouble = expiries.Select(x => originDate.CalculateYearFraction(x, TimeBasis)).ToArray(); Alphas = parameters.Select(x => x.Alpha).ToArray(); Betas = parameters.Select(x => x.Beta).ToArray(); Nus = parameters.Select(x => x.Nu).ToArray(); Rhos = parameters.Select(x => x.Rho).ToArray(); _alphaInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Alphas, TimeInterpolatorType); _betaInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Betas, TimeInterpolatorType); _rhoInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Rhos, TimeInterpolatorType); _nuInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, Nus, TimeInterpolatorType); _fwdsInterp = InterpolatorFactory.GetInterpolator(ExpiriesDouble, fwds, TimeInterpolatorType); }