示例#1
0
        private AssetFxMCModel GetSut()
        {
            var buildDate = DateTime.Parse("2018-10-04");
            var usd       = TestProviderHelper.CurrencyProvider["USD"];

            TestProviderHelper.CalendarProvider.Collection.TryGetCalendar("NYC", out var usdCal);
            var dfCurve = new IrCurve(new[] { buildDate, buildDate.AddDays(1000) }, new[] { 0.0, 0.0 }, buildDate, "disco", Interpolator1DType.Linear, usd, "DISCO");

            var comCurve = new BasicPriceCurve(buildDate, new[] { buildDate, buildDate.AddDays(15), buildDate.AddDays(100) }, new[] { 100.0, 100.0, 100.0 }, PriceCurveType.NYMEX, TestProviderHelper.CurrencyProvider)
            {
                Name    = "CL",
                AssetId = "CL"
            };
            var comSurface = new ConstantVolSurface(buildDate, 0.32)
            {
                AssetId = "CL"
            };
            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>(), new List <FxPair>(), new Dictionary <Currency, string> {
                { usd, "DISCO" }
            });
            fModel.SetupFx(fxM);

            var aModel = new AssetFxModel(buildDate, fModel);

            aModel.AddVolSurface("CL", comSurface);
            aModel.AddPriceCurve("CL", comCurve);

            var product = AssetProductFactory.CreateAsianOption(buildDate.AddDays(10), buildDate.AddDays(20), 101, "CL", OptionType.Call, usdCal, buildDate.AddDays(21), usd);

            product.TradeId       = "waaah";
            product.DiscountCurve = "DISCO";


            var pfolio = new Portfolio {
                Instruments = new List <IInstrument> {
                    product
                }
            };
            var settings = new McSettings
            {
                Generator         = RandomGeneratorType.MersenneTwister,
                NumberOfPaths     = (int)System.Math.Pow(2, 13),
                NumberOfTimesteps = 1,
                ReportingCurrency = usd,
                Parallelize       = false,
                CreditSettings    = new CreditSettings
                {
                    ExposureDates = new DateTime[] { buildDate.AddDays(5), buildDate.AddDays(20), buildDate.AddDays(22) }
                },
            };
            var sut = new AssetFxMCModel(buildDate, pfolio, aModel, settings, TestProviderHelper.CurrencyProvider, TestProviderHelper.FutureSettingsProvider, TestProviderHelper.CalendarProvider);

            return(sut);
        }
示例#2
0
        public static object CreateMcSettings(
            [ExcelArgument(Description = "Settings object name")] string ObjectName,
            [ExcelArgument(Description = "Number of paths")] int NumberOfPaths,
            [ExcelArgument(Description = "Number of timesteps")] int NumberOfTimesteps,
            [ExcelArgument(Description = "Random number generator, e.g. Sobol or MersenneTwister")] object RandomGenerator,
            [ExcelArgument(Description = "Reporting currency")] object ReportingCurrency,
            [ExcelArgument(Description = "Model to use, e.g. Black,LocalVol or TurboSkew")] string McModel,
            [ExcelArgument(Description = "Full futures simulation? (True/False)")] bool FuturesSim,
            [ExcelArgument(Description = "Parallel execution? (True/False)")] bool Parallel,
            [ExcelArgument(Description = "Futures mapping dictionary, assetId to futures code")] object FutMappingDict,
            [ExcelArgument(Description = "Enable debug mode")] object DebugMode,
            [ExcelArgument(Description = "Enable average path correction")] object PathCorrection,
            [ExcelArgument(Description = "Enable reduced memory operation")] object CompactMemoryMode,
            [ExcelArgument(Description = "Avoid regresison if possible for BackPricing options")] object AvoidBPRegression,
            [ExcelArgument(Description = "Enable local correlation? (True/False)")] bool LocalCorrelation,
            [ExcelArgument(Description = "Credit settings object")] object CreditSettings)
        {
            return(ExcelHelper.Execute(_logger, () =>
            {
                if (!ContainerStores.GlobalContainer.GetRequiredService <ICurrencyProvider>().TryGetCurrency(ReportingCurrency.OptionalExcel("USD"), out var repCcy))
                {
                    return $"Could not find currency {ReportingCurrency} in cache";
                }

                if (!Enum.TryParse(RandomGenerator.OptionalExcel("MersenneTwister"), true, out RandomGeneratorType randomGenerator))
                {
                    return $"Could not parse random generator name - {RandomGenerator}";
                }

                if (!Enum.TryParse(McModel.OptionalExcel("Black"), true, out McModelType mcModel))
                {
                    return $"Could not parse model type - {McModel}";
                }

                var settings = new McSettings
                {
                    Generator = randomGenerator,
                    NumberOfPaths = NumberOfPaths,
                    NumberOfTimesteps = NumberOfTimesteps,
                    ReportingCurrency = repCcy,
                    McModelType = mcModel,
                    ExpensiveFuturesSimulation = FuturesSim,
                    Parallelize = Parallel,
                    FuturesMappingTable = (FutMappingDict is ExcelMissing) ?
                                          new Dictionary <string, string>() :
                                          ((object[, ])FutMappingDict).RangeToDictionary <string, string>(),
                    DebugMode = DebugMode.OptionalExcel(false),
                    AveragePathCorrection = PathCorrection.OptionalExcel(false),
                    CompactMemoryMode = CompactMemoryMode.OptionalExcel(false),
                    AvoidRegressionForBackPricing = AvoidBPRegression.OptionalExcel(false),
                    LocalCorrelation = LocalCorrelation,
                    CreditSettings = (CreditSettings is ExcelMissing) ? null : ContainerStores.GetObjectCache <CreditSettings>().GetObjectOrThrow(CreditSettings as string, $"Unable to find Credit Settings {CreditSettings}").Value
                };

                return ExcelHelper.PushToCache(settings, ObjectName);
            }));
        }
示例#3
0
        public MonoIndexRegressor(DateTime[] regressionDates, IAssetPathPayoff[] portfolio, McSettings settings, bool requireContinuity)
        {
            _regressionDates   = regressionDates;
            _portfolio         = portfolio;
            _requireContinuity = requireContinuity;
            _repCcy            = settings.ReportingCurrency;
            _pathwiseValues    = new double[_regressionDates.Length][];
            DebugMode          = settings.DebugMode;

            for (var i = 0; i < _pathwiseValues.Length; i++)
            {
                _pathwiseValues[i] = new double[settings.NumberOfPaths];
            }
        }
示例#4
0
        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 LinearPortfolioValueRegressor(DateTime[] regressionDates, IAssetPathPayoff[] portfolio, McSettings settings)
 {
     _regressionDates = regressionDates;
     _portfolio       = portfolio;
     _repCcy          = settings.ReportingCurrency;
     _pathwiseValues  = new double[_regressionDates.Length][][];
     for (var i = 0; i < _pathwiseValues.Length; i++)
     {
         _pathwiseValues[i] = new double[settings.NumberOfPaths][];
     }
 }
示例#6
0
        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();
        }