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); } }
public void TestInitialize() { _nodeA = new Node <string>("Chiang Mai"); _nodeB = new Node <string>("Lampang"); _nodeC = new Node <string>("Sukhothai"); _nodeD = new Node <string>("Ayuthaya"); _nodeE = new Node <string>("Bangkok"); var graph = new Graph <string>(); // Add node graph.AddNode(_nodeA); graph.AddNode(_nodeB); graph.AddNode(_nodeC); graph.AddNode(_nodeD); graph.AddNode(_nodeE); // Add edges graph.AddEdge(_nodeA, _nodeB, 3); graph.AddEdge(_nodeA, _nodeC, 5); graph.AddEdge(_nodeB, _nodeA, 3); graph.AddEdge(_nodeB, _nodeC, 1); graph.AddEdge(_nodeB, _nodeD, 2); graph.AddEdge(_nodeC, _nodeA, 5); graph.AddEdge(_nodeC, _nodeB, 1); graph.AddEdge(_nodeC, _nodeD, 3); graph.AddEdge(_nodeC, _nodeE, 6); graph.AddEdge(_nodeD, _nodeB, 2); graph.AddEdge(_nodeD, _nodeC, 3); graph.AddEdge(_nodeD, _nodeE, 4); graph.AddEdge(_nodeE, _nodeC, 6); graph.AddEdge(_nodeE, _nodeD, 4); _pathEngine = new PathEngine <string>(graph); }
public void TestBlockGeneration() { using var engine = new PathEngine(4 << 2); engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64()); engine.AddPathProcess(new FakeAssetProcess("TestUnderlying", numberOfDimensions: 2, timesteps: 10)); engine.SetupFeatures(); engine.RunProcess(); }
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 static void AddRate <T>(this PathEngine engine, T rateFeature) where T : IRateFeature { var rateCollection = engine.Features.GetFeature <IRatesFeature>(); rateCollection.AddRate(rateFeature); if (rateFeature is IPathProcess process) { engine.AddPathProcess(process); } }
public void TestBlockGenerationSobolFlipShifted() { var engine = new PathEngine(64); var directionNumbers = new Random.Sobol.SobolDirectionNumbers("SobolDirectionNumbers.txt"); engine.AddPathProcess(new Random.Sobol.SobolFlipShiftedPathGenerator(true, directionNumbers)); engine.AddPathProcess(new FakeAssetProcess("TestUnderlying", numberOfDimensions: 2, timesteps: 10)); engine.SetupFeatures(); engine.RunProcess(); }
public void RandsWithNoVectors() { var Paths = (int)System.Math.Pow(2, 14); using var engine = new PathEngine(Paths); engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64()); engine.AddPathProcess(new FakeAssetProcess("TestUnderlying", numberOfDimensions: 2, timesteps: 100)); engine.SetupFeatures(); engine.RunProcess(); }
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); }
static void FindShortestPath() { // Step 1: Create node var nodeA = new Node <string>("Chiang Mai"); var nodeB = new Node <string>("Lampang"); var nodeC = new Node <string>("Sukhothai"); var nodeD = new Node <string>("Ayuthaya"); var nodeE = new Node <string>("Bangkok"); // Step 2: Create graph data var graph = new Graph <string>(); // Step 3: Add node graph.AddNode(nodeA); graph.AddNode(nodeB); graph.AddNode(nodeC); graph.AddNode(nodeD); graph.AddNode(nodeE); // Step 4: Add edges graph.AddEdge(nodeA, nodeB, 3); graph.AddEdge(nodeA, nodeC, 5); graph.AddEdge(nodeB, nodeA, 3); graph.AddEdge(nodeB, nodeC, 1); graph.AddEdge(nodeB, nodeD, 2); graph.AddEdge(nodeC, nodeA, 5); graph.AddEdge(nodeC, nodeB, 1); graph.AddEdge(nodeC, nodeD, 3); graph.AddEdge(nodeC, nodeE, 6); graph.AddEdge(nodeD, nodeB, 2); graph.AddEdge(nodeD, nodeC, 3); graph.AddEdge(nodeD, nodeE, 4); graph.AddEdge(nodeE, nodeC, 6); graph.AddEdge(nodeE, nodeD, 4); // Step 5: Create path engine and call function var pathEngine = new PathEngine <string>(graph); var pathResult = pathEngine.FindShortestPath(nodeA, nodeE); // Display path result Console.WriteLine($"Total cost from {pathResult.From} to {pathResult.To} is {pathResult.TotalCost}"); Console.WriteLine("============================================"); foreach (var path in pathResult.Paths) { Console.WriteLine(path.ToString()); } Console.WriteLine("============================================"); Console.ReadKey(); }
public List <Model.PathAction> GetKeyboardPath(string searchTerm, string keyboardType) { List <Model.PathAction> pathActions = new List <Model.PathAction>(); KeyboardType type; if (Enum.TryParse(keyboardType, out type)) { Model.Keyboard keyboard = _keyboards.GetKeyboard(type); PathEngine engine = new PathEngine(searchTerm, keyboard); return(engine.GeneratePath()); } else { throw new InvalidKeyboardTypeException($"{keyboardType} is not a valid keyboard type."); } }
public void PathsGenerated() { var engine = new PathEngine(2 << 8); engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64() { UseNormalInverse = true }); var asset = new ConstantVolSingleAsset ( startDate: DateTime.Now.Date, expiry: DateTime.Now.Date.AddYears(1), vol: 0.30, spot: 1000, drift: 0.00, numberOfSteps: 100, name: "TestAsset" ); engine.AddPathProcess(asset); var asset2 = new ConstantVolSingleAsset ( startDate: DateTime.Now.Date, expiry: DateTime.Now.Date.AddYears(1), vol: 0.30, spot: 500, drift: 0.00, numberOfSteps: 25, name: "TestAsset2" ); engine.AddPathProcess(asset2); var payoff = new EuropeanPut("TestAsset2", 500, DateTime.Now.Date.AddYears(1)); engine.AddPathProcess(payoff); engine.SetupFeatures(); engine.RunProcess(); var output = new OutputPathsToImage(engine, 2000, 1000); }
public void BlackMC_PathsGenerated() { var origin = DateTime.Now.Date; using var engine = new PathEngine(2.IntPow(IsCoverageOnly ? 6 : 15)); engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64() { UseNormalInverse = true, UseAnthithetic = false }); var volSurface = new ConstantVolSurface(origin, 0.32); var fwdCurve = new Func <double, double>(t => { return(900 + 100 * t); }); var asset = new BlackSingleAsset ( startDate: origin, expiryDate: origin.AddYears(1), volSurface: volSurface, forwardCurve: fwdCurve, nTimeSteps: IsCoverageOnly ? 1 : 10, 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 blackPv = BlackFunctions.BlackPV(1000, 900, 0, 1, 0.32, OptionType.P); if (!IsCoverageOnly) { Assert.True(System.Math.Abs(blackPv - pv) < 1.0); var fwd = payoff2.AverageResult; Assert.True(System.Math.Abs(fwdCurve(1) / fwd - 1.0) < 0.001); } }
public OutputPathsToImage(PathEngine engine, int width, int height) { var image = new Image <Argb32>(width, height); var rnd = new Random(); var minMax = engine.BlockSet.Select(b => b.RawData.MinMax()).Aggregate((currentValues, next) => (System.Math.Min(currentValues.min, next.min), System.Math.Max(currentValues.max, next.max))); var range = minMax.max - minMax.min; var pixelsPerPointY = height / range; var pixelsPerPointX = width / engine.BlockSet.Steps; foreach (var block in engine.BlockSet) { for (var factor = 0; factor < block.Factors; factor++) { for (var path = 0; path < block.NumberOfPaths; path++) { var indexOfPath = block.GetIndexOfPathStart(path, factor); var bytes = new byte[3]; rnd.NextBytes(bytes); var pen = new ImageSharp.Drawing.Pens.Pen <Argb32>(new Argb32(bytes[0], bytes[1], bytes[2]), 2.0f); var points = new Vector2[block.NumberOfSteps]; for (var step = 0; step < block.NumberOfSteps; step++) { var nextX = (float)(step * pixelsPerPointX); var nextY = (float)((block[indexOfPath + step * Vector <double> .Count] - minMax.min) * pixelsPerPointY); points[step] = new Vector2(nextX, nextY); } image.DrawLines(pen, points); } } } using (var fs = System.IO.File.Create("C:\\code\\output.png")) { image.SaveAsPng(fs); } }
public void CompositeSmimleFacts_LocalVol() { var origin = new DateTime(2017, 02, 07); var expiry = origin.AddMonths(2); var tExp = origin.CalculateYearFraction(expiry, DayCountBasis.Act365F); var fwdCurveAsset = new Func <double, double>(t => { return(100); }); var fwdCurveFx = new Func <double, double>(t => { return(15); }); var volAsset = 0.32; var volFx = 0.16; var correl = 0.25; var surfaceAsset = new RiskyFlySurface(origin, new[] { volAsset }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.02, 0.03 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 100.0 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.GaussianKernel, Interpolator1DType.Linear) { FlatDeltaSmileInExtreme = true }; var surfaceFx = new RiskyFlySurface(origin, new[] { volFx }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.015, 0.025 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 0.1 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.GaussianKernel, Interpolator1DType.Linear) { FlatDeltaSmileInExtreme = true }; //var surfaceAsset = new SabrVolSurface(origin, new[] { volAsset }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.02, 0.03 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 100.0 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.Linear); //var surfaceFx = new SabrVolSurface(origin, new[] { volFx }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.015, 0.025 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 0.1 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.Linear); //var surfaceAsset = new SVIVolSurface(origin, new[] { volAsset }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.02, 0.03 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 100.0 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.Linear); //var surfaceFx = new SVIVolSurface(origin, new[] { volFx }, new[] { expiry }, new[] { 0.25, 0.1 }, new[] { new[] { 0.015, 0.025 } }, new[] { new[] { 0.005, 0.007 } }, new[] { 0.1 }, WingQuoteType.Arithmatic, AtmVolType.ZeroDeltaStraddle, Interpolator1DType.Linear); var invFx = new InverseFxSurface("inv", surfaceFx, TestProviderHelper.CurrencyProvider); var surfaceCompo = surfaceAsset.GenerateCompositeSmile(invFx, 200, expiry, 100, 1.0 / 15, correl); //setup MC using var engine = new PathEngine(2.IntPow(IsCoverageOnly?5:15)); engine.AddPathProcess( new Qwack.Random.MersenneTwister.MersenneTwister64 { UseNormalInverse = true }); var correlMatrix = new double[][] { new double[] { 1.0, correl }, new double[] { correl, 1.0 }, }; engine.AddPathProcess(new Cholesky(correlMatrix)); var asset1 = new TurboSkewSingleAsset ( startDate: origin, expiryDate: expiry, volSurface: surfaceAsset, forwardCurve: fwdCurveAsset, nTimeSteps: 1, name: "Asset" ); var asset2 = new TurboSkewSingleAsset ( startDate: origin, expiryDate: expiry, volSurface: surfaceFx, forwardCurve: fwdCurveFx, nTimeSteps: 1, name: "USD/ZAR" ); engine.AddPathProcess(asset1); engine.AddPathProcess(asset2); var strike = 1500; var product = new EuropeanOption { AssetId = "Asset", CallPut = OptionType.C, ExpiryDate = expiry, PaymentCurrency = TestProviderHelper.CurrencyProvider["ZAR"], PaymentDate = expiry, Notional = 1.0, SpotLag = new Frequency("0b"), Strike = strike, FxConversionType = FxConversionType.ConvertThenAverage }; var productAsset = new EuropeanOption { AssetId = "Asset", CallPut = OptionType.C, ExpiryDate = expiry, PaymentCurrency = TestProviderHelper.CurrencyProvider["USD"], PaymentDate = expiry, Notional = 1.0, SpotLag = new Frequency("0b"), Strike = 100, FxConversionType = FxConversionType.None }; var productFx = new EuropeanOption { AssetId = "USD/ZAR", CallPut = OptionType.C, ExpiryDate = expiry, PaymentCurrency = TestProviderHelper.CurrencyProvider["ZAR"], PaymentDate = expiry, Notional = 1.0, SpotLag = new Frequency("0b"), Strike = 0.1, FxConversionType = FxConversionType.None }; var pathProduct = new AssetPathPayoff(product, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider, TestProviderHelper.CurrencyProvider["ZAR"]); var pathProductAsset = new AssetPathPayoff(productAsset, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider, TestProviderHelper.CurrencyProvider["ZAR"]); var pathProductFx = new AssetPathPayoff(productFx, TestProviderHelper.CurrencyProvider, TestProviderHelper.CalendarProvider, TestProviderHelper.CurrencyProvider["ZAR"]); engine.AddPathProcess(pathProduct); engine.AddPathProcess(pathProductAsset); engine.AddPathProcess(pathProductFx); engine.SetupFeatures(); engine.RunProcess(); var q = pathProduct.ResultsByPath; var qq = q.Average(); var productIv = BlackFunctions.BlackImpliedVol(1500, strike, 0.0, tExp, pathProduct.AverageResult, OptionType.C); var productAssetIv = BlackFunctions.BlackImpliedVol(100, 100, 0.0, tExp, pathProductAsset.AverageResult, OptionType.C); var productFxIv = BlackFunctions.BlackImpliedVol(10, 10, 0.0, tExp, pathProductFx.AverageResult, OptionType.C); Assert.True(Abs(productIv - surfaceCompo.Interpolate(strike)) < 0.01); }
static void FindShortestPath() { // Step 1: Create node var nodeA = new Node <string>("Station A", 0); var nodeB = new Node <string>("Station B", 1); var nodeC = new Node <string>("SStation C", 2); var nodeD = new Node <string>("Station D", 3); var nodeE = new Node <string>("Station E", 4); var nodeF = new Node <string>("Station F", 5); // Step 2: Create graph data var graph = new Graph <string>(); // Step 3: Add node graph.AddNode(nodeA); graph.AddNode(nodeB); graph.AddNode(nodeC); graph.AddNode(nodeD); graph.AddNode(nodeE); graph.AddNode(nodeF); // Step 4: Add edges graph.AddEdge(nodeA, nodeB, 0, 3); graph.AddEdge(nodeA, nodeC, 1, 5); graph.AddEdge(nodeB, nodeA, 2, 3); graph.AddEdge(nodeB, nodeC, 3, 1); graph.AddEdge(nodeB, nodeD, 4, 2); graph.AddEdge(nodeC, nodeA, 5, 5); graph.AddEdge(nodeC, nodeB, 6, 1); graph.AddEdge(nodeC, nodeD, 7, 3); graph.AddEdge(nodeC, nodeE, 8, 6); graph.AddEdge(nodeD, nodeB, 9, 2); graph.AddEdge(nodeD, nodeC, 10, 3); graph.AddEdge(nodeD, nodeE, 11, 4); graph.AddEdge(nodeE, nodeC, 12, 6); graph.AddEdge(nodeE, nodeD, 13, 4); graph.AddEdge(nodeF, nodeC, 14, 6); graph.AddEdge(nodeF, nodeD, 15, 4); /////////add OD pairs///// graph.AddOD(nodeA, nodeF, 0, 100); graph.AddOD(nodeA, nodeD, 1, 100); //////////////// graph.CreateNodeEdgeRelation(); // Step 5: Create path engine and call function var pathEngine = new PathEngine <string>(graph); var pathResult = pathEngine.FindShortestPath(nodeA, nodeF); for (int w = 0; w < graph.ODs.Count; ++w) { var sp = pathEngine.FindShortestPath(graph.ODs[w].Origin, graph.ODs[w].Dest); Console.WriteLine(graph.ODs[w]); for (int i = 0; i < sp.PathEdgeList.Count; i++) { Console.WriteLine(sp.PathEdgeList[i].Id); graph.Edges[sp.PathEdgeList[i].Id].Flow = graph.ODs[w].Demand + graph.Edges[sp.PathEdgeList[i].Id].Flow; Console.WriteLine("flow ={0}", graph.Edges[sp.PathEdgeList[i].Id].Flow); graph.Edges[sp.PathEdgeList[i].Id].getCost(); } } for (int i = 0; i < graph.Nodes[0].OutGoingEdges.Count; i++) { int edgeid = graph.Nodes[0].OutGoingEdges[i].Id; Console.WriteLine("edge {0} leaving node 0/A", graph.Nodes[0].OutGoingEdges[i].Id); } // Display path result Console.WriteLine($"Total cost from {pathResult.From} to {pathResult.To} is {pathResult.TotalCost}"); Console.WriteLine("============================================"); foreach (var path in pathResult.PathEdgeList) { Console.WriteLine(path.ToString()); Console.WriteLine(path.Id); } Console.WriteLine("============================================"); Console.ReadKey(); }
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); } }
void Awake() { Instance = this; }
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); }
public AssetFxMCModel(DateTime originDate, Portfolio portfolio, IAssetFxModel model, McSettings settings, ICurrencyProvider currencyProvider, IFutureSettingsProvider futureSettingsProvider, ICalendarProvider calendarProvider) { if (settings.CompactMemoryMode && settings.AveragePathCorrection) { throw new Exception("Can't use both CompactMemoryMode and PathCorrection"); } _currencyProvider = currencyProvider; _futureSettingsProvider = futureSettingsProvider; _calendarProvider = calendarProvider; Engine = new PathEngine(settings.NumberOfPaths) { Parallelize = settings.Parallelize, CompactMemoryMode = settings.CompactMemoryMode }; OriginDate = originDate; Portfolio = portfolio; Model = model; Settings = settings; switch (settings.Generator) { case RandomGeneratorType.MersenneTwister: Engine.AddPathProcess(new Random.MersenneTwister.MersenneTwister64() { UseNormalInverse = true, UseAnthithetic = false }); break; case RandomGeneratorType.Sobol: var directionNumers = new Random.Sobol.SobolDirectionNumbers(GetSobolFilename()); Engine.AddPathProcess(new Random.Sobol.SobolPathGenerator(directionNumers, 1000) { UseNormalInverse = true }); break; case RandomGeneratorType.Constant: Engine.AddPathProcess(new Random.Constant.Constant() { UseNormalInverse = true, }); break; case RandomGeneratorType.FlipFlop: Engine.AddPathProcess(new Random.Constant.FlipFlop(settings.CreditSettings.ConfidenceInterval, true)); break; } Engine.IncrementDepth(); if (model.CorrelationMatrix != null) { if (settings.LocalCorrelation) { Engine.AddPathProcess(new CholeskyWithTime(model.CorrelationMatrix, model)); } else { Engine.AddPathProcess(new Cholesky(model.CorrelationMatrix)); } Engine.IncrementDepth(); } var lastDate = portfolio.LastSensitivityDate; var assetIds = portfolio.AssetIds(); var assetInstruments = portfolio.Instruments .Where(x => x is IAssetInstrument) .Select(x => x as IAssetInstrument); var fixingsNeeded = new Dictionary <string, List <DateTime> >(); foreach (var ins in assetInstruments) { var fixingsForIns = ins.PastFixingDates(originDate); if (fixingsForIns.Any()) { foreach (var kv in fixingsForIns) { if (!fixingsNeeded.ContainsKey(kv.Key)) { fixingsNeeded.Add(kv.Key, new List <DateTime>()); } fixingsNeeded[kv.Key] = fixingsNeeded[kv.Key].Concat(kv.Value).Distinct().ToList(); } } } //asset processes var fxAssetsToAdd = new List <string>(); var corrections = new Dictionary <string, SimpleAveragePathCorrector>(); foreach (var assetId in assetIds) { if (assetId.Length == 7 && assetId[3] == '/') { fxAssetsToAdd.Add(assetId); continue; } if (!(model.GetVolSurface(assetId) is IATMVolSurface surface)) { throw new Exception($"Vol surface for asset {assetId} could not be cast to IATMVolSurface"); } var fixingDict = fixingsNeeded.ContainsKey(assetId) ? model.GetFixingDictionary(assetId) : null; var fixings = fixingDict != null ? fixingsNeeded[assetId].ToDictionary(x => x, x => fixingDict.GetFixing(x)) : new Dictionary <DateTime, double>(); var futuresSim = settings.ExpensiveFuturesSimulation && (model.GetPriceCurve(assetId).CurveType == PriceCurveType.ICE || model.GetPriceCurve(assetId).CurveType == PriceCurveType.NYMEX); if (futuresSim) { var fwdCurve = new Func <DateTime, double>(t => { return(model.GetPriceCurve(assetId).GetPriceForDate(t)); }); var asset = new BlackFuturesCurve ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: Settings.FuturesMappingTable[assetId], pastFixings: fixings, futureSettingsProvider: _futureSettingsProvider ); Engine.AddPathProcess(asset); } else { var fwdCurve = new Func <double, double>(t => { var c = model.GetPriceCurve(assetId); var d = originDate.AddYearFraction(t, DayCountBasis.ACT365F); if (c is PriceCurve pc) { d = d.AddPeriod(RollType.F, pc.SpotCalendar, pc.SpotLag); } else if (c is ContangoPriceCurve cc) { d = d.AddPeriod(RollType.F, cc.SpotCalendar, cc.SpotLag); } return(c.GetPriceForDate(d)); }); IATMVolSurface adjSurface = null; var correlation = 0.0; if (settings.ReportingCurrency != model.GetPriceCurve(assetId).Currency) { var fxAdjPair = settings.ReportingCurrency + "/" + model.GetPriceCurve(assetId).Currency; var fxAdjPairInv = model.GetPriceCurve(assetId).Currency + "/" + settings.ReportingCurrency; if (!(model.FundingModel.GetVolSurface(fxAdjPair) is IATMVolSurface adjSurface2)) { throw new Exception($"Vol surface for fx pair {fxAdjPair} could not be cast to IATMVolSurface"); } adjSurface = adjSurface2; if (model.CorrelationMatrix != null) { if (model.CorrelationMatrix.TryGetCorrelation(fxAdjPair, assetId, out var correl)) { correlation = correl; } else if (model.CorrelationMatrix.TryGetCorrelation(fxAdjPairInv, assetId, out var correl2)) { correlation = -correl2; } } } if (settings.McModelType == McModelType.LocalVol) { var asset = new LVSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: assetId, pastFixings: fixings, fxAdjustSurface: adjSurface, fxAssetCorrelation: correlation ); Engine.AddPathProcess(asset); } else if (settings.McModelType == McModelType.TurboSkew) { var asset = new TurboSkewSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: assetId, pastFixings: fixings, fxAdjustSurface: adjSurface, fxAssetCorrelation: correlation ); Engine.AddPathProcess(asset); } else { var asset = new BlackSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: assetId, pastFixings: fixings, fxAdjustSurface: adjSurface, fxAssetCorrelation: correlation ); Engine.AddPathProcess(asset); } if (settings.AveragePathCorrection) { corrections.Add(assetId, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(assetId) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, assetId, fixings, adjSurface, correlation)); } } } //fx pairs var pairsAdded = new List <string>(); var fxPairs = portfolio.FxPairs(model).Concat(fxAssetsToAdd); var payoutCcys = portfolio.Instruments.Select(i => i.Currency); if (payoutCcys.Any(p => p != settings.ReportingCurrency)) { var ccysToAdd = payoutCcys.Where(p => p != settings.ReportingCurrency).Distinct(); var pairsToAdd = ccysToAdd.Select(c => $"{c.Ccy}/{settings.ReportingCurrency}"); fxPairs = fxPairs.Concat(pairsToAdd).Distinct(); } foreach (var fxPair in fxPairs) { var fxPairName = fxPair; var pair = fxPairName.FxPairFromString(_currencyProvider, _calendarProvider); if (pairsAdded.Contains(pair.ToString())) { continue; } if (!(model.FundingModel.VolSurfaces[fxPairName] is IATMVolSurface surface)) { throw new Exception($"Vol surface for fx pair {fxPairName} could not be cast to IATMVolSurface"); } var fwdCurve = new Func <double, double>(t => { var date = originDate.AddYearFraction(t, DayCountBasis.ACT365F); var spotDate = pair.SpotDate(date); return(model.FundingModel.GetFxRate(spotDate, fxPairName)); }); pairsAdded.Add(pair.ToString()); if (settings.McModelType == McModelType.LocalVol) { var asset = new LVSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: fxPairName ); Engine.AddPathProcess(asset); if (settings.AveragePathCorrection) { corrections.Add(fxPairName, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(fxPairName) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, fxPairName)); } } else if (settings.McModelType == McModelType.TurboSkew) { if (fxPairName.Substring(fxPairName.Length - 3, 3) != settings.ReportingCurrency) {//needs to be drift-adjusted var fxAdjPair = settings.ReportingCurrency + "/" + fxPairName.Substring(fxPairName.Length - 3, 3); if (!(model.FundingModel.VolSurfaces[fxAdjPair] is IATMVolSurface adjSurface)) { throw new Exception($"Vol surface for fx pair {fxAdjPair} could not be cast to IATMVolSurface"); } var correlation = fxPair == fxAdjPair ? -1.0 : 0.0; if (correlation != -1.0 && model.CorrelationMatrix != null) { if (model.CorrelationMatrix.TryGetCorrelation(fxAdjPair, fxPair, out var correl)) { correlation = correl; } } var asset = new TurboSkewSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: fxPairName, fxAdjustSurface: adjSurface, fxAssetCorrelation: correlation ); Engine.AddPathProcess(asset); if (settings.AveragePathCorrection) { corrections.Add(fxPairName, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(fxPairName) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, fxPairName, null, adjSurface, correlation)); } } else { var asset = new TurboSkewSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: fxPairName ); Engine.AddPathProcess(asset); if (settings.AveragePathCorrection) { corrections.Add(fxPairName, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(fxPairName) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, fxPairName)); } } } else { if (fxPairName.Substring(fxPairName.Length - 3, 3) != settings.ReportingCurrency) {//needs to be drift-adjusted var fxAdjPair = settings.ReportingCurrency + "/" + fxPairName.Substring(fxPairName.Length - 3, 3); if (!(model.FundingModel.VolSurfaces[fxAdjPair] is IATMVolSurface adjSurface)) { throw new Exception($"Vol surface for fx pair {fxAdjPair} could not be cast to IATMVolSurface"); } var correlation = fxPair == fxAdjPair ? -1.0 : 0.0; if (correlation != -1.0 && model.CorrelationMatrix != null) { if (model.CorrelationMatrix.TryGetCorrelation(fxAdjPair, fxPair, out var correl)) { correlation = correl; } } var asset = new BlackSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: fxPairName, fxAdjustSurface: adjSurface, fxAssetCorrelation: correlation ); Engine.AddPathProcess(asset); if (settings.AveragePathCorrection) { corrections.Add(fxPairName, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(fxPairName) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, fxPairName, null, adjSurface, correlation)); } } else { var asset = new BlackSingleAsset ( startDate: originDate, expiryDate: lastDate, volSurface: surface, forwardCurve: fwdCurve, nTimeSteps: settings.NumberOfTimesteps, name: fxPairName ); Engine.AddPathProcess(asset); if (settings.AveragePathCorrection) { corrections.Add(fxPairName, new SimpleAveragePathCorrector(new SimpleAveragePathCalculator(fxPairName) { CompactMode = settings.CompactMemoryMode }, surface, fwdCurve, fxPairName)); } } } } //apply path correctin if (settings.AveragePathCorrection && corrections.Any()) { Engine.IncrementDepth(); foreach (var pc in corrections) { Engine.AddPathProcess(pc.Value.PathCalc); } Engine.IncrementDepth(); foreach (var pc in corrections) { Engine.AddPathProcess(pc.Value); } } //payoffs Engine.IncrementDepth(); _payoffs = assetInstruments.ToDictionary(x => x.TradeId, y => new AssetPathPayoff(y, _currencyProvider, _calendarProvider, settings.ReportingCurrency)); if (!settings.AvoidRegressionForBackPricing && _payoffs.Any(x => x.Value.Regressors != null)) { var regressorsToAdd = _payoffs.Where(x => x.Value.Regressors != null) .SelectMany(x => x.Value.Regressors) .Distinct(); foreach (var regressor in regressorsToAdd) { Engine.AddPathProcess(regressor); foreach (var payoff in _payoffs.Where(x => x.Value.Regressors != null)) { if (payoff.Value.Regressors.Any(x => x == regressor)) { payoff.Value.SetRegressor(regressor); } } } Engine.IncrementDepth(); } foreach (var product in _payoffs) { if (settings.AvoidRegressionForBackPricing && (product.Value.AssetInstrument is BackPricingOption || product.Value.AssetInstrument is MultiPeriodBackpricingOption)) { product.Value.VanillaModel = VanillaModel; } Engine.AddPathProcess(product.Value); } var metricsNeedRegression = new[] { BaseMetric.PFE, BaseMetric.KVA, BaseMetric.CVA, BaseMetric.FVA, BaseMetric.EPE }; //Need to calculate PFE if (settings.CreditSettings != null && settings.CreditSettings.ExposureDates != null && settings.ReportingCurrency != null && metricsNeedRegression.Contains(settings.CreditSettings.Metric))//setup for PFE, etc { Engine.IncrementDepth(); switch (settings.CreditSettings.PfeRegressorType) { case PFERegressorType.MultiLinear: _regressor = new LinearPortfolioValueRegressor(settings.CreditSettings.ExposureDates, _payoffs.Values.ToArray(), settings); break; case PFERegressorType.MonoLinear: _regressor = new MonoIndexRegressor(settings.CreditSettings.ExposureDates, _payoffs.Values.ToArray(), settings, true); break; } Engine.AddPathProcess(_regressor); } //Need to calculate expected capital if (settings.CreditSettings != null && settings.CreditSettings.ExposureDates != null && settings.ReportingCurrency != null && settings.CreditSettings.Metric == BaseMetric.ExpectedCapital) { Engine.IncrementDepth(); _capitalCalc = new ExpectedCapitalCalculator(Portfolio, settings.CreditSettings.CounterpartyRiskWeighting, settings.CreditSettings.AssetIdToHedgeGroupMap, settings.ReportingCurrency, VanillaModel, settings.CreditSettings.ExposureDates); Engine.AddPathProcess(_capitalCalc); } Engine.SetupFeatures(); }