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))); }
public LsmcBenchmarks() { var valDate = new Day(2019, 8, 29); #region Set Up Simple Storage var storageStart = new Day(2019, 12, 1); var storageEnd = new Day(2020, 4, 1); const double maxWithdrawalRate = 850.0; const double maxInjectionRate = 625.0; const double maxInventory = 52_500.0; const double constantInjectionCost = 1.25; const double constantWithdrawalCost = 0.93; var simpleDailyStorage = CmdtyStorage <Day> .Builder .WithActiveTimePeriod(storageStart, storageEnd) .WithConstantInjectWithdrawRange(-maxWithdrawalRate, maxInjectionRate) .WithZeroMinInventory() .WithConstantMaxInventory(maxInventory) .WithPerUnitInjectionCost(constantInjectionCost, injectionDate => injectionDate) .WithNoCmdtyConsumedOnInject() .WithPerUnitWithdrawalCost(constantWithdrawalCost, withdrawalDate => withdrawalDate) .WithNoCmdtyConsumedOnWithdraw() .WithNoCmdtyInventoryLoss() .WithNoInventoryCost() .MustBeEmptyAtEnd() .Build(); #endregion Set Up Simple Storage const double oneFactorMeanReversion = 12.5; const double oneFactorSpotVol = 0.95; var oneFDailyMultiFactorParams = MultiFactorParameters.For1Factor(oneFactorMeanReversion, TimeSeriesFactory.ForConstantData(valDate, storageEnd, oneFactorSpotVol)); const double flatInterestRate = 0.055; const int numInventorySpacePoints = 100; const double baseForwardPrice = 53.5; const double forwardSeasonalFactor = 24.6; var forwardCurve = TimeSeriesFactory.FromMap(valDate, storageEnd, day => { int daysForward = day.OffsetFrom(valDate); return(baseForwardPrice + Math.Sin(2.0 * Math.PI / 365.0 * daysForward) * forwardSeasonalFactor); }); _valuationParameters = new LsmcValuationParameters <Day> .Builder { BasisFunctions = BasisFunctionsBuilder.Ones + BasisFunctionsBuilder.AllMarkovFactorAllPositiveIntegerPowersUpTo(RegressMaxDegree, 1), CurrentPeriod = new Day(2019, 8, 29), DiscountFactors = StorageHelper.CreateAct65ContCompDiscounter(flatInterestRate), ForwardCurve = forwardCurve, GridCalc = FixedSpacingStateSpaceGridCalc.CreateForFixedNumberOfPointsOnGlobalInventoryRange(simpleDailyStorage, numInventorySpacePoints), Inventory = 5_685, Storage = simpleDailyStorage, SettleDateRule = deliveryDate => Month.FromDateTime(deliveryDate.Start).Offset(1).First <Day>() + 19, // Settlement on 20th of following month }
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; })); }