Exemplo n.º 1
0
        public void GetInjectWithdrawRange_ConstantInjectWithdrawRange_HasConstantRates()
        {
            CmdtyStorage <Day> cmdtyStorage = BuildCmdtyStorageWithAllConstantValues();
            // TODO make parameterised
            var    date      = new Day(2019, 6, 1);
            double inventory = 548.54;
            InjectWithdrawRange injectWithdrawRange = cmdtyStorage.GetInjectWithdrawRange(date, inventory);

            Assert.Equal(ConstantMaxInjectRate, injectWithdrawRange.MaxInjectWithdrawRate);
            Assert.Equal(-ConstantMaxWithdrawRate, injectWithdrawRange.MinInjectWithdrawRate);
        }
        GenerateValuationResults_CurrentPeriodEqualToStorageEndStorageInventoryHasTerminalValue(double startingInventory,
                                                                                                double forwardPrice)
        {
            var storageStart = new Day(2019, 9, 1);
            var storageEnd   = new Day(2019, 9, 30);

            TimeSeries <Month, Day> settlementDates = new TimeSeries <Month, Day> .Builder
            {
                { new Month(2019, 9), new Day(2019, 10, 5) }
            }.Build();

            CmdtyStorage <Day> storage = CmdtyStorage <Day> .Builder
                                         .WithActiveTimePeriod(storageStart, storageEnd)
                                         .WithConstantInjectWithdrawRange(-45.5, 56.6)
                                         .WithConstantMinInventory(0.0)
                                         .WithConstantMaxInventory(1000.0)
                                         .WithPerUnitInjectionCost(0.8, injectionDate => injectionDate)
                                         .WithNoCmdtyConsumedOnInject()
                                         .WithPerUnitWithdrawalCost(1.2, withdrawalDate => withdrawalDate)
                                         .WithNoCmdtyConsumedOnWithdraw()
                                         .WithNoCmdtyInventoryLoss()
                                         .WithNoInventoryCost()
                                         .WithTerminalInventoryNpv((cmdtyPrice, terminalInventory) => cmdtyPrice * terminalInventory - 999.0)
                                         .Build();

            var forwardCurve = new TimeSeries <Day, double> .Builder(1)
            {
                { storageEnd, forwardPrice }
            }

            .Build();

            IntrinsicStorageValuationResults <Day> valuationResults = IntrinsicStorageValuation <Day>
                                                                      .ForStorage(storage)
                                                                      .WithStartingInventory(startingInventory)
                                                                      .ForCurrentPeriod(storageEnd)
                                                                      .WithForwardCurve(forwardCurve)
                                                                      .WithMonthlySettlement(settlementDates)
                                                                      .WithDiscountFactorFunc((valuationDate, cashFlowDate) => 1.0) // No discounting
                                                                      .WithFixedGridSpacing(10.0)
                                                                      .WithLinearInventorySpaceInterpolation()
                                                                      .WithNumericalTolerance(1E-10)
                                                                      .Calculate();

            return(valuationResults);
        }
Exemplo n.º 3
0
        private static CmdtyStorage <Day> BuildCmdtyStorageWithAllConstantValues()
        {
            CmdtyStorage <Day> storage = CmdtyStorage <Day> .Builder
                                         .WithActiveTimePeriod(new Day(2019, 10, 1), new Day(2019, 11, 1))
                                         .WithConstantInjectWithdrawRange(-ConstantMaxWithdrawRate, ConstantMaxInjectRate)
                                         .WithConstantMinInventory(ConstantMinInventory)
                                         .WithConstantMaxInventory(ConstantMaxInventory)
                                         .WithPerUnitInjectionCost(ConstantInjectionCost, injectionDate => injectionDate)
                                         .WithNoCmdtyConsumedOnInject()
                                         .WithPerUnitWithdrawalCost(ConstantWithdrawalCost, withdrawalDate => withdrawalDate)
                                         .WithNoCmdtyConsumedOnWithdraw()
                                         .WithNoCmdtyInventoryLoss()
                                         .WithNoInventoryCost()
                                         .MustBeEmptyAtEnd()
                                         .Build();

            return(storage);
        }
Exemplo n.º 4
0
                Category = AddIn.ExcelFunctionCategory, IsThreadSafe = false, IsVolatile = false, IsExceptionSafe = true)] // TODO turn IsThreadSafe to true and use ConcurrentDictionary?
 public static object CreateStorage(
     [ExcelArgument(Name = "Storage_name", Description = "Name of storage object to create.")] string name,
     [ExcelArgument(Name = ExcelArg.StorageStart.Name, Description = ExcelArg.StorageStart.Description)] DateTime storageStart,
     [ExcelArgument(Name = ExcelArg.StorageEnd.Name, Description = ExcelArg.StorageEnd.Description)] DateTime storageEnd,
     [ExcelArgument(Name = ExcelArg.Ratchets.Name, Description = ExcelArg.Ratchets.Description)] object ratchets,
     [ExcelArgument(Name = ExcelArg.RatchetInterpolation.Name, Description = ExcelArg.RatchetInterpolation.Description)] string ratchetInterpolation,
     [ExcelArgument(Name = ExcelArg.InjectionCost.Name, Description = ExcelArg.InjectionCost.Description)] double injectionCostRate,
     [ExcelArgument(Name = ExcelArg.CmdtyConsumedInject.Name, Description = ExcelArg.CmdtyConsumedInject.Description)] double cmdtyConsumedOnInjection,
     [ExcelArgument(Name = ExcelArg.WithdrawalCost.Name, Description = ExcelArg.WithdrawalCost.Description)] double withdrawalCostRate,
     [ExcelArgument(Name = ExcelArg.CmdtyConsumedWithdraw.Name, Description = ExcelArg.CmdtyConsumedWithdraw.Description)] double cmdtyConsumedOnWithdrawal,
     [ExcelArgument(Name = ExcelArg.NumericalTolerance.Name, Description = ExcelArg.NumericalTolerance.Description)] object numericalToleranceIn)
 {
     return(StorageExcelHelper.ExecuteExcelFunction(() =>
     {
         double numericalTolerance = StorageExcelHelper.DefaultIfExcelEmptyOrMissing(numericalToleranceIn, 1E-10, "Numerical_tolerance");
         CmdtyStorage <Day> storage = StorageExcelHelper.CreateCmdtyStorageFromExcelInputs <Day>(storageStart,
                                                                                                 storageEnd, ratchets, ratchetInterpolation, injectionCostRate, cmdtyConsumedOnInjection,
                                                                                                 withdrawalCostRate, cmdtyConsumedOnWithdrawal, numericalTolerance);
         _storageObjects[name] = storage;
         return name;
     }));
 }
Exemplo n.º 5
0
        public static CmdtyStorage <T> CreateCmdtyStorageFromExcelInputs <T>(DateTime storageStartDateTime,
                                                                             DateTime storageEndDateTime,
                                                                             object injectWithdrawConstraintsIn,
                                                                             string injectWithdrawInterpolationIn,
                                                                             double injectionCostRate,
                                                                             double cmdtyConsumedOnInjection,
                                                                             double withdrawalCostRate,
                                                                             double cmdtyConsumedOnWithdrawal,
                                                                             double newtonRaphsonAccuracy)
            where T : ITimePeriod <T>
        {
            T storageStart = TimePeriodFactory.FromDateTime <T>(storageStartDateTime);
            T storageEnd   = TimePeriodFactory.FromDateTime <T>(storageEndDateTime);

            if (injectWithdrawConstraintsIn is ExcelMissing || injectWithdrawConstraintsIn is ExcelEmpty)
            {
                throw new ArgumentException("Inject/withdraw constraints haven't been specified.");
            }

            if (!(injectWithdrawConstraintsIn is object[,] injectWithdrawArray))
            {
                throw new ArgumentException("Inject/withdraw constraints have been incorrectly entered. Argument value should be of a range with 4 columns, the first containing dates, the rest containing numbers.");
            }

            if (injectWithdrawArray.GetLength(1) != 4)
            {
                throw new ArgumentException("Inject/withdraw constraints have been incorrectly entered. Argument value should be a range 4 columns.");
            }

            var injectWithdrawGrouped = TakeWhileNotEmptyOrError(injectWithdrawArray).Select((row, i) => new
            {
                period       = ObjectToDateTime(row[0], $"Row {i + 1} of inject/withdraw/inventory constrains contains invalid date time in 1st column."),
                inventory    = ObjectToDouble(row[1], $"Row {i + 1} of inject/withdraw/inventory constraints contains invalid inventory in 2nd column as is not a number."),
                injectRate   = ObjectToDouble(row[2], $"Row {i + 1} of inject/withdraw/inventory constraints contains invalid injection rate in 3rd column as is not a number."),
                withdrawRate = ObjectToDouble(row[3], $"Row {i + 1} of inject/withdraw/inventory constraints contains invalid withdrawal in 4th column as is not a number.")
            }).GroupBy(arg => arg.period);

            var injectWithdrawConstraints = new List <InjectWithdrawRangeByInventoryAndPeriod <T> >();

            foreach (var injectWithdrawGroup in injectWithdrawGrouped)
            {
                T period = TimePeriodFactory.FromDateTime <T>(injectWithdrawGroup.Key);
                IEnumerable <InjectWithdrawRangeByInventory> injectWithdrawByInventory = injectWithdrawGroup.Select(arg =>
                                                                                                                    new InjectWithdrawRangeByInventory(arg.inventory, new InjectWithdrawRange(-arg.withdrawRate, arg.injectRate)));
                injectWithdrawConstraints.Add(new InjectWithdrawRangeByInventoryAndPeriod <T>(period, injectWithdrawByInventory));
            }

            InterpolationType interpolationType;

            if (injectWithdrawInterpolationIn == "PiecewiseLinear")
            {
                interpolationType = InterpolationType.PiecewiseLinear;
            }
            else if (injectWithdrawInterpolationIn == "Polynomial")
            {
                interpolationType = InterpolationType.PolynomialWithParams(newtonRaphsonAccuracy);
            }
            else
            {
                throw new ArgumentException($"Value of Inject_withdraw_interpolation '{injectWithdrawInterpolationIn}' not recognised. Must be either 'PiecewiseLinear' or 'Polynomial'.");
            }

            CmdtyStorage <T> storage = CmdtyStorage <T> .Builder
                                       .WithActiveTimePeriod(storageStart, storageEnd)
                                       .WithTimeAndInventoryVaryingInjectWithdrawRates(injectWithdrawConstraints, interpolationType)
                                       .WithPerUnitInjectionCost(injectionCostRate)
                                       .WithFixedPercentCmdtyConsumedOnInject(cmdtyConsumedOnInjection)
                                       .WithPerUnitWithdrawalCost(withdrawalCostRate)
                                       .WithFixedPercentCmdtyConsumedOnWithdraw(cmdtyConsumedOnWithdrawal)
                                       .WithNoCmdtyInventoryLoss()
                                       .WithNoInventoryCost()
                                       .MustBeEmptyAtEnd()
                                       .Build();

            return(storage);
        }
Exemplo n.º 6
0
                       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;
            }));
        }
Exemplo n.º 7
0
        static void Main(string[] args)
        {
            const double constantMaxInjectRate   = 5.26;
            const double constantMaxWithdrawRate = 14.74;
            const double constantMaxInventory    = 1100.74;
            const double constantMinInventory    = 0.0;
            const double constantInjectionCost   = 0.48;
            const double constantWithdrawalCost  = 0.74;

            CmdtyStorage <Day> storage = CmdtyStorage <Day> .Builder
                                         .WithActiveTimePeriod(new Day(2019, 9, 1), new Day(2019, 10, 1))
                                         .WithConstantInjectWithdrawRange(-constantMaxWithdrawRate, constantMaxInjectRate)
                                         .WithConstantMinInventory(constantMinInventory)
                                         .WithConstantMaxInventory(constantMaxInventory)
                                         .WithPerUnitInjectionCost(constantInjectionCost, injectionDate => injectionDate)
                                         .WithNoCmdtyConsumedOnInject()
                                         .WithPerUnitWithdrawalCost(constantWithdrawalCost, withdrawalDate => withdrawalDate)
                                         .WithNoCmdtyConsumedOnWithdraw()
                                         .WithNoCmdtyInventoryLoss()
                                         .WithNoCmdtyInventoryCost()
                                         .MustBeEmptyAtEnd()
                                         .Build();

            var currentPeriod = new Day(2019, 9, 15);

            const double lowerForwardPrice = 56.6;
            const double forwardSpread     = 87.81;

            double higherForwardPrice = lowerForwardPrice + forwardSpread;

            var forwardCurveBuilder = new TimeSeries <Day, double> .Builder();

            foreach (var day in new Day(2019, 9, 15).EnumerateTo(new Day(2019, 9, 22)))
            {
                forwardCurveBuilder.Add(day, lowerForwardPrice);
            }

            foreach (var day in new Day(2019, 9, 23).EnumerateTo(new Day(2019, 10, 1)))
            {
                forwardCurveBuilder.Add(day, higherForwardPrice);
            }

            const double startingInventory = 50.0;

            IntrinsicStorageValuationResults <Day> valuationResults = IntrinsicStorageValuation <Day>
                                                                      .ForStorage(storage)
                                                                      .WithStartingInventory(startingInventory)
                                                                      .ForCurrentPeriod(currentPeriod)
                                                                      .WithForwardCurve(forwardCurveBuilder.Build())
                                                                      .WithCmdtySettlementRule(day => day.First <Month>().Offset(1).First <Day>().Offset(5)) // Commodity is settled on the 5th day of the next month
                                                                      .WithDiscountFactorFunc(day => 1.0)                                                    // Assumes to discounting
                                                                      .WithFixedGridSpacing(10.0)
                                                                      .WithLinearInventorySpaceInterpolation()
                                                                      .WithNumericalTolerance(1E-12)
                                                                      .Calculate();

            Console.WriteLine("Calculated intrinsic storage NPV: " + valuationResults.NetPresentValue.ToString("F2"));
            Console.WriteLine();
            Console.WriteLine("Decision profile:");
            Console.WriteLine(valuationResults.DecisionProfile.FormatData("F2", -1));

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }