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 }
public void GetGridPoints_StateSpaceLowerBoundHigherThanUpperBound_ThrowsArgumentException() { const double spacing = 15.0; const double stateSpaceLowerBound = 121.2; const double stateSpaceUpperBound = 121.19; var gridCalc = new FixedSpacingStateSpaceGridCalc(spacing); Assert.Throws <ArgumentException>(() => gridCalc.GetGridPoints(stateSpaceLowerBound, stateSpaceUpperBound).ToArray()); }
public void GetGridPoints_StateSpaceLessThanSpacing_ReturnsStateSpaceLowerAndUpperBounds() { const double spacing = 50.0; const double stateSpaceLowerBound = 120.55; const double stateSpaceUpperBound = 161.89; var gridCalc = new FixedSpacingStateSpaceGridCalc(spacing); var gridPoints = gridCalc.GetGridPoints(stateSpaceLowerBound, stateSpaceUpperBound); var expectedGridPoints = new[] { stateSpaceLowerBound, stateSpaceUpperBound }; Assert.Equal(expectedGridPoints, gridPoints); }
public void GetGridPoints_StateSpaceLowerBoundEqualToUpperBound_ReturnsSinglePoint() { const double spacing = 15.0; const double stateSpaceLowerBound = 121.2; const double stateSpaceUpperBound = stateSpaceLowerBound; var gridCalc = new FixedSpacingStateSpaceGridCalc(spacing); var gridPoints = gridCalc.GetGridPoints(stateSpaceLowerBound, stateSpaceUpperBound); var expectedGridPoints = new[] { stateSpaceLowerBound }; Assert.Equal(expectedGridPoints, gridPoints); }
public void GetGridPoints_StateSpaceUpperEqualsLowerPlusSpacing_ReturnsStateSpaceLowerAndUpperBounds() { const double spacing = 15.0; const double stateSpaceLowerBound = 121.2; const double stateSpaceUpperBound = stateSpaceLowerBound + spacing; var gridCalc = new FixedSpacingStateSpaceGridCalc(spacing); var gridPoints = gridCalc.GetGridPoints(stateSpaceLowerBound, stateSpaceUpperBound); var expectedGridPoints = new[] { stateSpaceLowerBound, stateSpaceUpperBound }; Assert.Equal(expectedGridPoints, gridPoints); }
public void GetGridPoints_ReturnsStateSpaceLowerAndUpperBoundsSeparatedBySpacing() { const double spacing = 15.0; const double stateSpaceLowerBound = 121.2; const double stateSpaceUpperBound = 174.89; var gridCalc = new FixedSpacingStateSpaceGridCalc(spacing); var gridPoints = gridCalc.GetGridPoints(stateSpaceLowerBound, stateSpaceUpperBound); var expectedGridPoints = new[] { stateSpaceLowerBound, 136.2, 151.2, 166.2, stateSpaceUpperBound, }; Assert.Equal(expectedGridPoints, gridPoints); }
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; })); }