public void Parse_ValidInput_AsExpected() { const string expression = "1 + s + s*s + s*s**3 + x0 + x1**3 + s*x2**4"; BasisFunction[] basisFunctions = BasisFunctionsBuilder.Parse(expression); Assert.Equal(7, basisFunctions.Length); var spotPriceSims = new[] { 25.69, 21.88, 16.78 }; var markovFactors = new ReadOnlyMemory <double>[] { new[] { 0.56, 0.12, 1.55 }, new[] { 1.08, 2.088, 0.988 }, new[] { 2.808, 0.998, 5.84 } }; // 1s AssertBasisFunction(basisFunctions[0], spotPriceSims, markovFactors, new[] { 1.0, 1.0, 1.0 }); // Spot price AssertBasisFunction(basisFunctions[1], spotPriceSims, markovFactors, spotPriceSims); // Spot price squared AssertBasisFunction(basisFunctions[2], spotPriceSims, markovFactors, spotPriceSims.Select(s => s * s)); // Spot price to power of 4 AssertBasisFunction(basisFunctions[3], spotPriceSims, markovFactors, spotPriceSims.Select(s => s * s * s * s)); // First factor AssertBasisFunction(basisFunctions[4], spotPriceSims, markovFactors, markovFactors[0].ToArray()); // Second factor cubed AssertBasisFunction(basisFunctions[5], spotPriceSims, markovFactors, markovFactors[1].ToArray().Select(x => x * x * x)); // Spot price times third factor to power of 4 double[] thirdFactor = markovFactors[2].ToArray(); AssertBasisFunction(basisFunctions[6], spotPriceSims, markovFactors, spotPriceSims.Select((s, i) => s * Math.Pow(thirdFactor[i], 4))); }
Category = AddIn.ExcelFunctionCategory, IsThreadSafe = false, IsVolatile = false, IsExceptionSafe = true)] // TODO turn IsThreadSafe to true and use ConcurrentDictionary? public static object StorageValueThreeFactor( [ExcelArgument(Name = "Name", Description = "Name of cached object to create.")] string name, [ExcelArgument(Name = ExcelArg.StorageHandle.Name, Description = ExcelArg.StorageHandle.Description)] string storageHandle, [ExcelArgument(Name = ExcelArg.ValDate.Name, Description = ExcelArg.ValDate.Description)] DateTime valuationDate, [ExcelArgument(Name = ExcelArg.Inventory.Name, Description = ExcelArg.Inventory.Description)] double currentInventory, [ExcelArgument(Name = ExcelArg.ForwardCurve.Name, Description = ExcelArg.ForwardCurve.Description)] object forwardCurve, [ExcelArgument(Name = ExcelArg.InterestRateCurve.Name, Description = ExcelArg.InterestRateCurve.Description)] object interestRateCurve, [ExcelArgument(Name = ExcelArg.SpotVol.Name, Description = ExcelArg.SpotVol.Description)] double spotVol, [ExcelArgument(Name = ExcelArg.SpotMeanReversion.Name, Description = ExcelArg.SpotMeanReversion.Description)] double spotMeanReversion, [ExcelArgument(Name = ExcelArg.LongTermVol.Name, Description = ExcelArg.LongTermVol.Description)] double longTermVol, [ExcelArgument(Name = ExcelArg.SeasonalVol.Name, Description = ExcelArg.SeasonalVol.Description)] double seasonalVol, [ExcelArgument(Name = ExcelArg.DiscountDeltas.Name, Description = ExcelArg.DiscountDeltas.Description)] bool discountDeltas, [ExcelArgument(Name = ExcelArg.SettleDates.Name, Description = ExcelArg.SettleDates.Description)] object settleDatesIn, [ExcelArgument(Name = ExcelArg.NumSims.Name, Description = ExcelArg.NumSims.Description)] int numSims, [ExcelArgument(Name = ExcelArg.BasisFunctions.Name, Description = ExcelArg.BasisFunctions.Description)] string basisFunctionsIn, [ExcelArgument(Name = ExcelArg.Seed.Name, Description = ExcelArg.Seed.Description)] object seedIn, [ExcelArgument(Name = ExcelArg.ForwardSimSeed.Name, Description = ExcelArg.ForwardSimSeed.Description)] object fwdSimSeedIn, [ExcelArgument(Name = ExcelArg.NumGridPoints.Name, Description = ExcelArg.NumGridPoints.Description)] object numGlobalGridPointsIn, [ExcelArgument(Name = ExcelArg.NumericalTolerance.Name, Description = ExcelArg.NumericalTolerance.Description)] object numericalTolerance, [ExcelArgument(Name = ExcelArg.ExtraDecisions.Name, Description = ExcelArg.ExtraDecisions.Description)] object extraDecisions) { return(StorageExcelHelper.ExecuteExcelFunction(() => { _calcWrappers[name] = ExcelCalcWrapper.CreateCancellable((cancellationToken, onProgress) => { // TODO provide alternative method for interpolating interest rates Func <Day, double> interpolatedInterestRates = StorageExcelHelper.CreateLinearInterpolatedInterestRateFunc(interestRateCurve, ExcelArg.InterestRateCurve.Name); Func <Day, Day, double> discountFunc = StorageHelper.CreateAct65ContCompDiscounter(interpolatedInterestRates); Day valDate = Day.FromDateTime(valuationDate); Func <Day, Day> settleDateRule = StorageExcelHelper.CreateSettlementRule(settleDatesIn, ExcelArg.SettleDates.Name); CmdtyStorage <Day> storage = _storageObjects[storageHandle]; int numGlobalGridPoints = StorageExcelHelper.DefaultIfExcelEmptyOrMissing(numGlobalGridPointsIn, ExcelArg.NumGridPoints.Default, ExcelArg.NumGridPoints.Name); string basisFunctionsText = basisFunctionsIn.Replace("x_st", "x0").Replace("x_lt", "x1").Replace("x_sw", "x2"); var lsmcParamsBuilder = new LsmcValuationParameters <Day> .Builder { Storage = storage, CurrentPeriod = valDate, Inventory = currentInventory, ForwardCurve = StorageExcelHelper.CreateDoubleTimeSeries <Day>(forwardCurve, ExcelArg.ForwardCurve.Name), DiscountFactors = discountFunc, DiscountDeltas = discountDeltas, BasisFunctions = BasisFunctionsBuilder.Parse(basisFunctionsText), ExtraDecisions = StorageExcelHelper.DefaultIfExcelEmptyOrMissing(extraDecisions, 0, ExcelArg.ExtraDecisions.Name), CancellationToken = cancellationToken, OnProgressUpdate = onProgress, GridCalc = FixedSpacingStateSpaceGridCalc.CreateForFixedNumberOfPointsOnGlobalInventoryRange(storage, numGlobalGridPoints), NumericalTolerance = StorageExcelHelper.DefaultIfExcelEmptyOrMissing(numericalTolerance, LsmcValuationParameters <Day> .Builder.DefaultNumericalTolerance, ExcelArg.NumericalTolerance.Description), SettleDateRule = settleDateRule }; // TODO test that this works with expired storage Day endDate = new[] { valDate, storage.EndPeriod }.Max(); var threeFactorParams = MultiFactorParameters.For3FactorSeasonal(spotMeanReversion, spotVol, longTermVol, seasonalVol, valDate, endDate); // TODO better error messages if seedIn and fwdSimSeedIn cannot be cast int?seed = StorageExcelHelper.IsExcelEmptyOrMissing(seedIn) ? (int?)null : (int)(double)seedIn; int?fwdSimSeed = StorageExcelHelper.IsExcelEmptyOrMissing(fwdSimSeedIn) ? (int?)null : (int)(double)fwdSimSeedIn; lsmcParamsBuilder.SimulateWithMultiFactorModelAndMersenneTwister(threeFactorParams, numSims, seed, fwdSimSeed); return LsmcStorageValuation.WithNoLogger.Calculate(lsmcParamsBuilder.Build()); }); return name; })); }