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); } }
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); }
public static object CreateGridVolSurface( [ExcelArgument(Description = "Object name")] string ObjectName, [ExcelArgument(Description = "Origin date")] DateTime OriginDate, [ExcelArgument(Description = "Strikes")] double[] Strikes, [ExcelArgument(Description = "Expiries")] double[] Expiries, [ExcelArgument(Description = "Volatilities")] double[,] Volatilities, [ExcelArgument(Description = "Stike Type - default Absolute")] object StrikeType, [ExcelArgument(Description = "Stike Interpolation - default Linear")] object StrikeInterpolation, [ExcelArgument(Description = "Time Interpolation - default Linear")] object TimeInterpolation ) { return(ExcelHelper.Execute(_logger, () => { var stikeType = StrikeType.OptionalExcel <string>("Absolute"); var expiries = ExcelHelper.ToDateTimeArray(Expiries); var surface = new GridVolSurface(OriginDate, Strikes, expiries, Volatilities.SquareToJagged()); var cache = ContainerStores.GetObjectCache <GridVolSurface>(); cache.PutObject(ObjectName, new SessionItem <GridVolSurface> { Name = ObjectName, Value = surface }); return ObjectName + '¬' + cache.GetObject(ObjectName).Version; })); }
public void LVMCDualPathsGenerated(double correlation) { var origin = DateTime.Now.Date; using var engine = new PathEngine(2.IntPow(IsCoverageOnly ? 6 : 8)) { Parallelize = false }; engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64() { UseNormalInverse = true, UseAnthithetic = false, }); engine.IncrementDepth(); var correlMatrix = new double[][] { new double[] { 1.0, correlation }, new double[] { correlation, 1.0 }, }; engine.AddPathProcess(new Cholesky(correlMatrix)); engine.IncrementDepth(); 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 volSurface = new GridVolSurface(origin, deltaKs, expiries, vols, StrikeType.ForwardDelta, Interpolator1DType.GaussianKernel, Interpolator1DType.LinearInVariance, DayCountBasis.Act365F); var fwdCurve1 = new Func <double, double>(t => { return(1000); }); var asset1 = new LVSingleAsset ( startDate: origin, expiryDate: origin.AddMonths(6), volSurface: volSurface, forwardCurve: fwdCurve1, nTimeSteps: IsCoverageOnly ? 3 : 100, name: "TestAsset1" ); var fwdCurve2 = new Func <double, double>(t => { return(1000); }); var asset2 = new LVSingleAsset ( startDate: origin, expiryDate: origin.AddMonths(6), volSurface: volSurface, forwardCurve: fwdCurve2, nTimeSteps: IsCoverageOnly ? 3 : 100, name: "TestAsset2" ); engine.AddPathProcess(asset1); engine.AddPathProcess(asset2); engine.IncrementDepth(); var correl = new Correlation("TestAsset1", "TestAsset2"); engine.AddPathProcess(correl); engine.SetupFeatures(); engine.RunProcess(); var corr = correl.AverageResult; var errCorr = correl.ResultStdError; if (!IsCoverageOnly) { Assert.Equal(correlation, corr, 1); } }
private AssetFxMCModel GetSut() { var buildDate = DateTime.Parse("2018-10-04"); var usd = TestProviderHelper.CurrencyProvider["USD"]; var zar = TestProviderHelper.CurrencyProvider["ZAR"]; TestProviderHelper.CalendarProvider.Collection.TryGetCalendar("NYC", out var usdCal); var pair = new FxPair() { Domestic = zar, Foreign = usd, PrimaryCalendar = usdCal, SpotLag = 2.Bd() }; var dfCurve = new IrCurve(new[] { buildDate, buildDate.AddDays(1000) }, new[] { 0.0, 0.0 }, buildDate, "disco", Interpolator1DType.Linear, usd, "DISCO"); var dates = new[] { buildDate, buildDate.AddDays(32), buildDate.AddDays(60), buildDate.AddDays(90) }; var times = dates.Select(d => buildDate.CalculateYearFraction(d, DayCountBasis.Act365F)).ToArray(); var vols = new[] { 0.32, 0.30, 0.29, 0.28 }; var comCurve = new PriceCurve(buildDate, dates, new[] { 100.0, 100.0, 100.0, 100.0 }, PriceCurveType.NYMEX, TestProviderHelper.CurrencyProvider) { Name = "CL", AssetId = "CL" }; var comSurface = new GridVolSurface(buildDate, new[] { 0.5 }, dates, vols.Select(x => new double[] { x }).ToArray(), StrikeType.ForwardDelta, Interpolator1DType.Linear, Interpolator1DType.LinearInVariance, DayCountBasis.Act365F) { AssetId = "CL" }; var fxSurface = new ConstantVolSurface(buildDate, 0.16) { AssetId = "USD/ZAR" }; var correlVector = new CorrelationTimeVector("CL", "USD/ZAR", _correls, times); var fModel = new FundingModel(buildDate, new Dictionary <string, IrCurve> { { "DISCO", dfCurve } }, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider); var fxM = new FxMatrix(TestProviderHelper.CurrencyProvider); fxM.Init(usd, buildDate, new Dictionary <Currency, double>() { { zar, 14.0 } }, new List <FxPair>() { pair }, new Dictionary <Currency, string> { { usd, "DISCO" }, { zar, "DISCO" } }); fModel.SetupFx(fxM); fModel.VolSurfaces.Add("ZAR/USD", fxSurface); fModel.VolSurfaces.Add("USD/ZAR", fxSurface); var aModel = new AssetFxModel(buildDate, fModel); aModel.AddVolSurface("CL", comSurface); aModel.AddPriceCurve("CL", comCurve); aModel.CorrelationMatrix = correlVector; var product1 = AssetProductFactory.CreateAsianOption(dates[1], dates[1], 1400, "CL", OptionType.Call, usdCal, dates[1], zar); product1.TradeId = "P1"; product1.DiscountCurve = "DISCO"; product1.FxConversionType = FxConversionType.AverageThenConvert; var product2 = AssetProductFactory.CreateAsianOption(dates[2], dates[2], 1400, "CL", OptionType.Call, usdCal, dates[2], zar); product2.TradeId = "P2"; product2.DiscountCurve = "DISCO"; product2.FxConversionType = FxConversionType.AverageThenConvert; var product3 = AssetProductFactory.CreateAsianOption(dates[3], dates[3], 1400, "CL", OptionType.Call, usdCal, dates[3], zar); product3.TradeId = "P3"; product3.DiscountCurve = "DISCO"; product3.FxConversionType = FxConversionType.AverageThenConvert; var pfolio = new Portfolio { Instruments = new List <IInstrument> { product1, product2, product3 } }; var settings = new McSettings { Generator = RandomGeneratorType.MersenneTwister, NumberOfPaths = (int)2.0.IntPow(15), NumberOfTimesteps = 1, ReportingCurrency = zar, Parallelize = false, LocalCorrelation = true, }; var sut = new AssetFxMCModel(buildDate, pfolio, aModel, settings, TestProviderHelper.CurrencyProvider, TestProviderHelper.FutureSettingsProvider, TestProviderHelper.CalendarProvider); return(sut); }
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 static object CreateGridVolSurface( [ExcelArgument(Description = "Object name")] string ObjectName, [ExcelArgument(Description = "Asset Id")] string AssetId, [ExcelArgument(Description = "Origin date")] DateTime OriginDate, [ExcelArgument(Description = "Strikes")] double[] Strikes, [ExcelArgument(Description = "Expiries")] double[] Expiries, [ExcelArgument(Description = "Volatilities")] double[,] Volatilities, [ExcelArgument(Description = "Stike Type - default Absolute")] object StrikeType, [ExcelArgument(Description = "Stike Interpolation - default Linear")] object StrikeInterpolation, [ExcelArgument(Description = "Time Interpolation - default Linear")] object TimeInterpolation, [ExcelArgument(Description = "Time basis - default ACT365F")] object TimeBasis, [ExcelArgument(Description = "Pillar labels (optional)")] object PillarLabels, [ExcelArgument(Description = "Currency - default USD")] object Currency, [ExcelArgument(Description = "Override spot lag - default none")] object SpotLag) { return(ExcelHelper.Execute(_logger, () => { var labels = (PillarLabels is ExcelMissing) ? null : ((object[, ])PillarLabels).ObjectRangeToVector <string>(); var ccyStr = Currency.OptionalExcel("USD"); ContainerStores.SessionContainer.GetService <ICalendarProvider>().Collection.TryGetCalendar(ccyStr, out var ccyCal); var stikeType = StrikeType.OptionalExcel <string>("Absolute"); var strikeInterpType = StrikeInterpolation.OptionalExcel <string>("Linear"); var timeInterpType = TimeInterpolation.OptionalExcel <string>("LinearInVariance"); var timeBasis = TimeBasis.OptionalExcel <string>("ACT365F"); var expiries = ExcelHelper.ToDateTimeArray(Expiries); if (!Enum.TryParse(stikeType, out StrikeType sType)) { return $"Could not parse strike type - {stikeType}"; } if (!Enum.TryParse(strikeInterpType, out Interpolator1DType siType)) { return $"Could not parse strike interpolator type - {strikeInterpType}"; } if (!Enum.TryParse(timeInterpType, out Interpolator1DType tiType)) { return $"Could not parse time interpolator type - {timeInterpType}"; } if (!Enum.TryParse(timeBasis, out DayCountBasis basis)) { return $"Could not parse time basis type - {timeBasis}"; } var surface = new GridVolSurface(OriginDate, Strikes, expiries, Volatilities.SquareToJagged(), sType, siType, tiType, basis, labels) { Currency = ContainerStores.CurrencyProvider[ccyStr], Name = AssetId ?? ObjectName, AssetId = AssetId ?? ObjectName, }; if (SpotLag != null && !(SpotLag is ExcelMissing)) { surface.OverrideSpotLag = new Frequency((string)SpotLag); } return ExcelHelper.PushToCache <IVolSurface>(surface, ObjectName); })); }
public void LVMC_TriplePathsGenerated(double correlationAB, double correlationAC, double correlationBC) { var origin = DateTime.Now.Date; var engine = new PathEngine(2.IntPow(15)); engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64() { UseNormalInverse = true, UseAnthithetic = false }); var correlMatrix = new double[][] { new double[] { 1.0, correlationAB, correlationAC }, new double[] { correlationAB, 1.0, correlationBC }, new double[] { correlationAC, correlationBC, 1.0 }, }; engine.AddPathProcess(new Cholesky(correlMatrix)); 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 fwdCurve1 = new Func <double, double>(t => { return(1000); }); var fwdCurve2 = new Func <double, double>(t => { return(1000); }); var fwdCurve3 = new Func <double, double>(t => { return(1000); }); var assetA = new LVSingleAsset ( startDate: origin, expiryDate: origin.AddYears(1), volSurface: volSurface, forwardCurve: fwdCurve1, nTimeSteps: 365, name: "TestAssetA" ); var assetB = new LVSingleAsset ( startDate: origin, expiryDate: origin.AddYears(1), volSurface: volSurface, forwardCurve: fwdCurve2, nTimeSteps: 365, name: "TestAssetB" ); var assetC = new LVSingleAsset ( startDate: origin, expiryDate: origin.AddYears(1), volSurface: volSurface, forwardCurve: fwdCurve3, nTimeSteps: 365, name: "TestAssetC" ); engine.AddPathProcess(assetA); engine.AddPathProcess(assetB); engine.AddPathProcess(assetC); var correlAB = new Correlation("TestAssetA", "TestAssetB"); var correlAC = new Correlation("TestAssetA", "TestAssetC"); var correlBC = new Correlation("TestAssetB", "TestAssetC"); engine.AddPathProcess(correlAB); engine.AddPathProcess(correlAC); engine.AddPathProcess(correlBC); engine.SetupFeatures(); engine.RunProcess(); Assert.Equal(correlationAB, correlAB.AverageResult, 2); Assert.Equal(correlationAC, correlAC.AverageResult, 2); Assert.Equal(correlationBC, correlBC.AverageResult, 2); }