Exemplo n.º 1
0
    def test_intrinsic_value_runs(self):

        ratchets = [
                            (date(2019, 8, 28),
                                        [
                                            (0.0, -150.0, 255.2),
                                            (2000.0, -200.0, 175.0),
                                        ]),
                            (date(2019, 9, 10), 
                                     [
                                         (0.0, -170.5, 235.8),
                                         (700.0, -180.2, 200.77),
                                         (1800.0, -190.5, 174.45),
                                    ])
                ]

        storage_start = date(2019, 8, 28)
        storage_end = date(2019, 9, 25)
        constant_injection_cost = 0.015
        constant_pcnt_consumed_inject = 0.0001
        constant_withdrawal_cost = 0.02
        constant_pcnt_consumed_withdraw = 0.000088
        constant_pcnt_inventory_loss = 0.001;
        constant_pcnt_inventory_cost = 0.002;

        def terminal_npv_calc(price, inventory):
            return price * inventory - 15.4 # Some arbitrary calculation

        cmdty_storage = cs.CmdtyStorage('D', storage_start, storage_end, constant_injection_cost, constant_withdrawal_cost,
                                        ratchets, ratchet_interp=cs.RatchetInterp.LINEAR,
                                cmdty_consumed_inject=constant_pcnt_consumed_inject, cmdty_consumed_withdraw=constant_pcnt_consumed_withdraw,
                                terminal_storage_npv=terminal_npv_calc,
                                inventory_loss=constant_pcnt_inventory_loss, inventory_cost=constant_pcnt_inventory_cost)

        inventory = 650.0
        val_date = date(2019, 9, 2)

        forward_curve = utils.create_piecewise_flat_series([58.89, 61.41, 59.89, 59.89], [val_date, date(2019, 9, 12), date(2019, 9, 18), storage_end], freq='D')
        
        # TODO test with proper interest rate curve
        flat_interest_rate = 0.03
        interest_rate_curve = pd.Series(index = pd.period_range(val_date, storage_end + timedelta(days=60), freq='D'))
        interest_rate_curve[:] = flat_interest_rate

        twentieth_of_next_month = lambda period: period.asfreq('M').asfreq('D', 'end') + 20
        intrinsic_results = cs.intrinsic_value(cmdty_storage, val_date, inventory, forward_curve, settlement_rule=twentieth_of_next_month,
                        interest_rates=interest_rate_curve, num_inventory_grid_points=100)
Exemplo n.º 2
0
    def test_storage_value_date_equals_storage_end_returns_zero_npv_empty_profile(
            self):
        storage_start = date(2019, 8, 28)
        storage_end = date(2019, 9, 25)
        cmdty_storage = cs.CmdtyStorage('D',
                                        storage_start,
                                        storage_end,
                                        injection_cost=0.1,
                                        withdrawal_cost=0.2,
                                        min_inventory=0,
                                        max_inventory=1000,
                                        max_injection_rate=2.5,
                                        max_withdrawal_rate=3.6)

        inventory = 0.0
        val_date = date(2019, 9, 25)

        forward_curve = utils.create_piecewise_flat_series(
            [58.89, 61.41, 70.89, 70.89],
            [storage_start,
             date(2019, 9, 12),
             date(2019, 9, 18), storage_end],
            freq='D')

        flat_interest_rate = 0.03
        interest_rate_curve = pd.Series(index=pd.period_range(
            val_date, storage_end + timedelta(days=60), freq='D'))
        interest_rate_curve[:] = flat_interest_rate

        twentieth_of_next_month = lambda period: period.asfreq('M').asfreq(
            'D', 'end') + 20
        intrinsic_results = cs.intrinsic_value(
            cmdty_storage,
            val_date,
            inventory,
            forward_curve,
            settlement_rule=twentieth_of_next_month,
            interest_rates=interest_rate_curve,
            num_inventory_grid_points=100)

        self.assertEqual(0.0, intrinsic_results.npv)
        self.assertEqual(0, len(intrinsic_results.profile))
Exemplo n.º 3
0
    def test_trinomial_value_runs(self):
        constraints = [(date(2019, 8, 28), [
            (0.0, -150.0, 255.2),
            (2000.0, -200.0, 175.0),
        ]),
                       (date(2019, 9, 10), [
                           (0.0, -170.5, 235.8),
                           (700.0, -180.2, 200.77),
                           (1800.0, -190.5, 174.45),
                       ])]

        storage_start = date(2019, 8, 28)
        storage_end = date(2019, 9, 25)
        constant_injection_cost = 0.015
        constant_pcnt_consumed_inject = 0.0001
        constant_withdrawal_cost = 0.02
        constant_pcnt_consumed_withdraw = 0.000088
        constant_pcnt_inventory_loss = 0.001
        constant_pcnt_inventory_cost = 0.002

        def terminal_npv_calc(price, inventory):
            return price * inventory - 15.4  # Some arbitrary calculation

        cmdty_storage = cs.CmdtyStorage(
            'D',
            storage_start,
            storage_end,
            constant_injection_cost,
            constant_withdrawal_cost,
            constraints,
            cmdty_consumed_inject=constant_pcnt_consumed_inject,
            cmdty_consumed_withdraw=constant_pcnt_consumed_withdraw,
            terminal_storage_npv=terminal_npv_calc,
            inventory_loss=constant_pcnt_inventory_loss,
            inventory_cost=constant_pcnt_inventory_cost)

        inventory = 650.0
        val_date = date(2019, 9, 2)

        forward_curve = utils.create_piecewise_flat_series(
            [58.89, 61.41, 59.89, 59.89],
            [val_date,
             date(2019, 9, 12),
             date(2019, 9, 18), storage_end],
            freq='D')

        # TODO test with proper interest rate curve
        flat_interest_rate = 0.03
        interest_rate_curve = pd.Series(index=pd.period_range(
            val_date, storage_end + timedelta(days=60), freq='D'))
        interest_rate_curve[:] = flat_interest_rate

        # Trinomial Tree parameters
        mean_reversion = 14.5
        spot_volatility = utils.create_piecewise_flat_series(
            [1.35, 1.13, 1.24, 1.24],
            [val_date,
             date(2019, 9, 12),
             date(2019, 9, 18), storage_end],
            freq='D')
        time_step = 1.0 / 365.0

        twentieth_of_next_month = lambda period: period.asfreq('M').asfreq(
            'D', 'end') + 20
        trinomial_value = cs.trinomial_value(
            cmdty_storage,
            val_date,
            inventory,
            forward_curve,
            spot_volatility,
            mean_reversion,
            time_step,
            settlement_rule=twentieth_of_next_month,
            interest_rates=interest_rate_curve,
            num_inventory_grid_points=100)
        self.assertTrue(isinstance(trinomial_value, float))
Exemplo n.º 4
0
    def test_trinomial_delta_deep_itm_equals_intrinsic_delta(self):
        storage_start = '2019-12-01'
        storage_end = '2020-04-01'
        constant_injection_rate = 700.0
        constant_withdrawal_rate = 700.0
        constant_injection_cost = 1.23
        constant_withdrawal_cost = 0.98
        min_inventory = 0.0
        max_inventory = 100000.0

        cmdty_storage = cs.CmdtyStorage(
            'D',
            storage_start,
            storage_end,
            constant_injection_cost,
            constant_withdrawal_cost,
            min_inventory=min_inventory,
            max_inventory=max_inventory,
            max_injection_rate=constant_injection_rate,
            max_withdrawal_rate=constant_withdrawal_rate)
        inventory = 0.0
        val_date = '2019-08-29'
        low_price = 23.87
        high_price = 150.32
        num_days_at_high_price = 20
        date_switch_high_price = '2020-03-12'  # TODO calculate this from num_days_at_high_price
        forward_curve = utils.create_piecewise_flat_series(
            [low_price, high_price, high_price],
            [val_date, date_switch_high_price, storage_end],
            freq='D')

        flat_interest_rate = 0.00
        interest_rate_curve = pd.Series(
            index=pd.period_range(val_date, '2020-06-01', freq='D'))
        interest_rate_curve[:] = flat_interest_rate
        # Trinomial Tree parameters
        mean_reversion = 14.5
        spot_volatility = pd.Series(
            index=pd.period_range(val_date, '2020-06-01', freq='D'))
        spot_volatility[:] = 1.15
        time_step = 1.0 / 365.0
        twentieth_of_next_month = lambda period: period.asfreq('M').asfreq(
            'D', 'end') + 20

        delta_fwd_contracts = [(storage_start, '2020-03-11'),
                               (date_switch_high_price, storage_end)]
        trinomial_deltas = cs.trinomial_deltas(
            cmdty_storage,
            val_date,
            inventory,
            forward_curve,
            spot_volatility,
            mean_reversion,
            time_step,
            interest_rates=interest_rate_curve,
            settlement_rule=twentieth_of_next_month,
            fwd_contracts=delta_fwd_contracts,
            num_inventory_grid_points=500)
        withdraw_delta = trinomial_deltas[1]
        expected_withdraw_delta = constant_withdrawal_rate * num_days_at_high_price
        pcnt_error = (withdraw_delta -
                      expected_withdraw_delta) / expected_withdraw_delta
        self.assertAlmostEqual(pcnt_error, 0.0, 3)
        self.assertTrue(isinstance(trinomial_deltas, list))
Exemplo n.º 5
0
class TestCmdtyStorage(unittest.TestCase):

    _default_freq = 'D'
    _default_ratchets = (
                                    (date(2019, 8, 28),
                                     (
                                            (0.0, -150.0, 255.2),
                                            (2000.0, -200.0, 175.0),
                                     )),
                            (date(2019, 9, 10),
                                    (
                                         (0.0, -170.5, 235.8),
                                         (700.0, -180.2, 200.77),
                                         (1800.0, -190.5, 174.45),
                                    ))
                            )

    _constant_min_inventory = 2.54
    _constant_max_inventory = 1234.56
    _constant_max_injection_rate = 65.64
    _constant_max_withdrawal_rate = 107.07

    _series_min_inventory = utils.create_piecewise_flat_series([2.4, 1.2, 0.0, 0.0],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_max_inventory = utils.create_piecewise_flat_series([1250.5, 1358.5, 54.5, 54.5],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_max_injection_rate = utils.create_piecewise_flat_series([125.5, 100, 120.66, 120.66],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_max_withdrawal_rate = utils.create_piecewise_flat_series([211.52, 200, 220.66, 220.66],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')

    _default_storage_start = date(2019, 8, 28)
    _default_storage_end = date(2019, 9, 25)
    _default_ratchets_interp = cs.RatchetInterp.LINEAR

    _constant_injection_cost = 0.015
    _constant_cmdty_consumed_inject = 0.0001
    _constant_withdrawal_cost = 0.02
    _constant_cmdty_consumed_withdraw = 0.000088
    _constant_inventory_loss = 0.001
    _constant_inventory_cost = 0.002


    _series_injection_cost = utils.create_piecewise_flat_series([1.41384, 2.284, 0.75, 0.75],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_cmdty_consumed_inject = utils.create_piecewise_flat_series([0.438, 0.413, 4.434, 4.434],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_withdrawal_cost = utils.create_piecewise_flat_series([0.143, 0.248, 5, 5],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_cmdty_consumed_withdraw = utils.create_piecewise_flat_series([0.045, 0.0415, 2, 2],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_inventory_loss = utils.create_piecewise_flat_series([0.003, 0.0015, 0.0017, 0.0017],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')
    _series_inventory_cost = utils.create_piecewise_flat_series([0.04, 0.02, 0.055, 0.055],
                            [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 10), date(2019, 9, 25)], 'D')

    _default_terminal_npv_calc = lambda price, inventory: price * inventory - 15.4 # Some arbitrary calculation
    
    def _create_storage(cls, freq=_default_freq, storage_start=_default_storage_start, storage_end=_default_storage_end,
                        ratchets=_default_ratchets, ratchet_interp = _default_ratchets_interp,
                        min_inventory=None, max_inventory=None, max_injection_rate=None, max_withdrawal_rate=None,
                        injection_cost=_constant_injection_cost,
                        withdrawal_cost=_constant_withdrawal_cost, cmdty_consumed_inject=_constant_cmdty_consumed_inject,
                        cmdty_consumed_withdraw=_constant_cmdty_consumed_withdraw, terminal_storage_npv=_default_terminal_npv_calc,
                        inventory_loss=_constant_inventory_loss, inventory_cost=_constant_inventory_cost):

        return cs.CmdtyStorage(freq, storage_start, storage_end, injection_cost,
                               withdrawal_cost, ratchets=ratchets, ratchet_interp=ratchet_interp,
                               min_inventory=min_inventory, max_inventory=max_inventory,
                               max_injection_rate=max_injection_rate, max_withdrawal_rate=max_withdrawal_rate,
                               cmdty_consumed_inject=cmdty_consumed_inject,
                               cmdty_consumed_withdraw=cmdty_consumed_withdraw,
                               terminal_storage_npv=terminal_storage_npv, inventory_loss=inventory_loss,
                               inventory_cost=inventory_cost)

    def test_ratchets_step_interp_as_expected(self):
        step_ratchets = (('2019-08-28',
                          (
                                 (0.0, -150.0, 255.2),
                                 (2000.0, -150.0, 255.2),
                             )),
                         ('2019-09-10',
                                 (
                                     (0.0, -170.5, 235.8),
                                     (700.0, -180.2, 200.77),
                                     (1800.0, -180.2, 200.77),
                                 )))
        storage = self._create_storage(ratchets=step_ratchets, ratchet_interp=cs.RatchetInterp.STEP)
        for inventory in [0.0, 1252.5, 1999.0]:
            with_rate, inj_rate = storage.inject_withdraw_range('2019-09-05', inventory)
            self.assertEqual(-150.0, with_rate)
            self.assertEqual(255.2, inj_rate)

    def test_init_ratchets_arg_not_none_other_constraint_args_not_none_raises(self):
        with self.assertRaisesRegex(ValueError, "min_inventory parameter should not be provided if ratchets parameter is provided."):
            storage = self._create_storage(ratchets=self._default_ratchets, min_inventory=self._constant_min_inventory)
        
        with self.assertRaisesRegex(ValueError, "max_inventory parameter should not be provided if ratchets parameter is provided."):
            storage = self._create_storage(ratchets=self._default_ratchets, max_inventory=self._constant_max_inventory)
        
        with self.assertRaisesRegex(ValueError, "max_injection_rate parameter should not be provided if ratchets parameter is provided."):
            storage = self._create_storage(ratchets=self._default_ratchets, max_injection_rate=self._constant_max_injection_rate)
        
        with self.assertRaisesRegex(ValueError, "max_withdrawal_rate parameter should not be provided if ratchets parameter is provided."):
            storage = self._create_storage(ratchets=self._default_ratchets, max_withdrawal_rate=self._constant_max_withdrawal_rate)

    def test_init_ratchets_arg_none_other_constraint_args_none_raises(self):
        with self.assertRaisesRegex(ValueError, "min_inventory parameter should be provided if ratchets parameter is not provided."):
            storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=None,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        
        with self.assertRaisesRegex(ValueError, "max_inventory parameter should be provided if ratchets parameter is not provided."):
            storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=None, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        
        with self.assertRaisesRegex(ValueError, "max_injection_rate parameter should be provided if ratchets parameter is not provided."):
            storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=None, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        
        with self.assertRaisesRegex(ValueError, "max_withdrawal_rate parameter should be provided if ratchets parameter is not provided."):
            storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=None)

    def test_init_ratchets_arg_none_ratchets_interp_not_none_raises(self):
        with self.assertRaisesRegex(ValueError, "ratchet_interp should not be provided if ratchets parameter is not provided."):
            storage = self._create_storage(ratchets=None, ratchet_interp=cs.RatchetInterp.LINEAR, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate,
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)

    def test_init_ratchets_arg_not_none_ratchets_none_raises(self):
        with self.assertRaisesRegex(ValueError, "ratchet_interp parameter should be provided if ratchets parameter is provided."):
            storage = self._create_storage(ratchets=self._default_ratchets, ratchet_interp=None, min_inventory=None,
                        max_inventory=None, max_injection_rate=None, max_withdrawal_rate=None)

    def test_start_property(self):
        storage = self._create_storage()
        self.assertEqual(pd.Period(self._default_storage_start, freq='D'), storage.start)
        
    def test_end_property(self):
        storage = self._create_storage()
        self.assertEqual(pd.Period(self._default_storage_end, freq='D'), storage.end)
        
    def test_freq_property(self):
        storage = self._create_storage()
        self.assertEqual(self._default_freq, storage.freq)
        
    def test_empty_at_end_true_when_terminal_storage_npv_none(self):
        storage = self._create_storage(terminal_storage_npv=None)
        self.assertEqual(True, storage.empty_at_end)
        
    def test_empty_at_end_false_when_terminal_storage_npv_not_none(self):
        storage = self._create_storage()
        self.assertEqual(False, storage.empty_at_end)

    def test_terminal_storage_npv_always_zero_when_terminal_storage_npv_none(self):
        storage = self._create_storage(terminal_storage_npv=None)
        for cmdty_price in [0.0, 23.85, 75.9, 100.22]:
            for terminal_inventory in [0.0, 500.58, 1268.65, 1800.0]:
                self.assertEqual(0.0, storage.terminal_storage_npv(cmdty_price, terminal_inventory))

    def test_terminal_storage_npv_evaluates_to_function_specified(self):
        storage = self._create_storage()
        for cmdty_price in [0.0, 23.85, 75.9, 100.22]:
            for terminal_inventory in [0.0, 500.58, 1268.65, 1800.0]:
                self.assertEqual(TestCmdtyStorage._default_terminal_npv_calc(cmdty_price, terminal_inventory), 
                                 storage.terminal_storage_npv(cmdty_price, terminal_inventory))

    def test_inject_withdraw_range_linearly_interpolated(self):
        storage = self._create_storage()
        # Inventory half way between pillars, so assert against mean of min/max inject/withdraw at the pillars
        min_dec, max_dec = storage.inject_withdraw_range(date(2019, 8, 29), 1000.0)
        self.assertEqual(-175.0, min_dec)
        self.assertEqual((255.2 + 175.0)/2.0, max_dec)

    def test_inject_withdraw_range_from_float_init_parameters(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        
        for inventory in [2.54, 500.58, 1234.56]:
            for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
                min_dec, max_dec = storage.inject_withdraw_range(dt, inventory)
                self.assertEqual(-self._constant_max_withdrawal_rate, min_dec)
                self.assertEqual(self._constant_max_injection_rate, max_dec)

    def test_inject_withdraw_range_from_int_init_parameters(self):
        int_max_injection_rate = int(self._constant_max_injection_rate)
        int_max_withdrawal_rate = int(self._constant_max_withdrawal_rate)
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=int_max_injection_rate, 
                        max_withdrawal_rate=int_max_withdrawal_rate)
        
        for inventory in [2.54, 500.58, 1234.56]:
            for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
                min_dec, max_dec = storage.inject_withdraw_range(dt, inventory)
                self.assertEqual(-int_max_withdrawal_rate, min_dec)
                self.assertEqual(int_max_injection_rate, max_dec)

    def test_inject_withdraw_range_from_series_init_parameters(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._series_max_injection_rate, 
                        max_withdrawal_rate=self._series_max_withdrawal_rate)

        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_min_dec = -self._series_max_withdrawal_rate[dt]
            expeted_max_dec = self._series_max_injection_rate[dt]
            for inventory in [2.54, 500.58, 1234.56]:
                min_dec, max_dec = storage.inject_withdraw_range(dt, inventory)
                self.assertEqual(expected_min_dec, min_dec)
                self.assertEqual(expeted_max_dec, max_dec)
                
    def test_inject_withdraw_range_from_series_max_injection_rate_init_parameters(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._series_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)

        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_min_dec = -self._constant_max_withdrawal_rate
            expeted_max_dec = self._series_max_injection_rate[dt]
            for inventory in [2.54, 500.58, 1234.56]:
                min_dec, max_dec = storage.inject_withdraw_range(dt, inventory)
                self.assertEqual(expected_min_dec, min_dec)
                self.assertEqual(expeted_max_dec, max_dec)

    def test_inject_withdraw_range_from_series_max_withdrawal_rate_init_parameters(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._series_max_withdrawal_rate)

        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_min_dec = -self._series_max_withdrawal_rate[dt]
            expeted_max_dec = self._constant_max_injection_rate
            for inventory in [2.54, 500.58, 1234.56]:
                min_dec, max_dec = storage.inject_withdraw_range(dt, inventory)
                self.assertEqual(expected_min_dec, min_dec)
                self.assertEqual(expeted_max_dec, max_dec)

    def test_min_inventory_property_from_constraints_table(self):
        storage = self._create_storage()
        self.assertEqual(0.0, storage.min_inventory(date(2019, 8, 29)))
        self.assertEqual(0.0, storage.min_inventory(date(2019, 9, 11)))

    def test_min_inventory_property_from_float_init_param(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        self.assertEqual(self._constant_min_inventory, storage.min_inventory(date(2019, 8, 29)))
        self.assertEqual(self._constant_min_inventory, storage.min_inventory(date(2019, 9, 11)))
        
    def test_min_inventory_property_from_series_init_param(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._series_min_inventory,
                        max_inventory=self._series_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        self.assertEqual(2.4, storage.min_inventory(date(2019, 8, 29)))
        self.assertEqual(1.2, storage.min_inventory(date(2019, 9, 1)))
        self.assertEqual(0.0, storage.min_inventory(date(2019, 9, 11)))

    def test_max_inventory_property_from_float_init_param(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._constant_min_inventory,
                        max_inventory=self._constant_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        self.assertEqual(self._constant_max_inventory, storage.max_inventory(date(2019, 8, 29)))
        self.assertEqual(self._constant_max_inventory, storage.max_inventory(date(2019, 9, 11)))

    def test_max_inventory_property_from_series_init_param(self):
        storage = self._create_storage(ratchets=None, ratchet_interp=None, min_inventory=self._series_min_inventory,
                        max_inventory=self._series_max_inventory, max_injection_rate=self._constant_max_injection_rate, 
                        max_withdrawal_rate=self._constant_max_withdrawal_rate)
        self.assertEqual(1250.5, storage.max_inventory(date(2019, 8, 29)))
        self.assertEqual(1358.5, storage.max_inventory(date(2019, 9, 1)))
        self.assertEqual(54.5, storage.max_inventory(date(2019, 9, 11)))
        
    def test_max_inventory_property_from_constraints_table(self):
        storage = self._create_storage()
        self.assertEqual(2000.0, storage.max_inventory(date(2019, 8, 29)))
        self.assertEqual(1800.0, storage.max_inventory(date(2019, 9, 11)))

    def test_injection_cost_scalar_init_parameter(self):
        storage = self._create_storage()
        injected_volume = 58.74
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [0, 500.58, 1234.56, 1800]:
                injection_cost = storage.injection_cost(dt, inventory, injected_volume)
                self.assertEqual(injected_volume * self._constant_injection_cost, injection_cost)

    def test_injection_cost_series_init_parameter(self):
        storage = self._create_storage(injection_cost=self._series_injection_cost)
        injected_volume = 58.74
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_injection_cost = self._series_injection_cost[dt]*injected_volume
            for inventory in [0, 500.58, 1234.56, 1800]:
                injection_cost = storage.injection_cost(dt, inventory, injected_volume)
                self.assertEqual(expected_injection_cost, injection_cost)

    def test_cmdty_consumed_inject_scalar_init_parameter(self):
        storage = self._create_storage()
        injected_volume = 58.74
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_inject = storage.cmdty_consumed_inject(dt, inventory, injected_volume)
                self.assertEqual(injected_volume * self._constant_cmdty_consumed_inject, cmdty_consumed_inject)

    def test_cmdty_consumed_inject_none_init_parameter(self):
        storage = self._create_storage(cmdty_consumed_inject=None)
        injected_volume = 58.74
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_inject = storage.cmdty_consumed_inject(dt, inventory, injected_volume)
                self.assertEqual(0, cmdty_consumed_inject)

    def test_cmdty_consumed_inject_series_init_parameter(self):
        storage = self._create_storage(cmdty_consumed_inject=self._series_cmdty_consumed_inject)
        injected_volume = 58.74
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_cmdty_consumed_inject = self._series_cmdty_consumed_inject[dt] * injected_volume
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_inject = storage.cmdty_consumed_inject(dt, inventory, injected_volume)
                self.assertEqual(expected_cmdty_consumed_inject, cmdty_consumed_inject)

    def test_withdrawal_cost_scalar_init_parameter(self):
        storage = self._create_storage()
        withdrawn_volume = 12.05
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [0, 500.58, 1234.56, 1800]:
                withdrawal_cost = storage.withdrawal_cost(dt, inventory, withdrawn_volume)
                self.assertEqual(withdrawn_volume * self._constant_withdrawal_cost, withdrawal_cost)

    def test_withdrawal_cost_series_init_parameter(self):
        storage = self._create_storage(withdrawal_cost=self._series_withdrawal_cost)
        withdrawn_volume = 12.05
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_withdrawal_cost = self._series_withdrawal_cost[dt] * withdrawn_volume
            for inventory in [0, 500.58, 1234.56, 1800]:
                withdrawal_cost = storage.withdrawal_cost(dt, inventory, withdrawn_volume)
                self.assertEqual(expected_withdrawal_cost, withdrawal_cost)

    def test_cmdty_consumed_withdraw_scalar_init_parameter(self):
        storage = self._create_storage()
        withdrawn_volume = 12.05
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_withdraw = storage.cmdty_consumed_withdraw(dt, inventory, withdrawn_volume)
                self.assertEqual(withdrawn_volume * self._constant_cmdty_consumed_withdraw, cmdty_consumed_withdraw)

    def test_cmdty_consumed_withdraw_none_init_parameter(self):
        storage = self._create_storage(cmdty_consumed_withdraw=None)
        withdrawn_volume = 12.05
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_withdraw = storage.cmdty_consumed_withdraw(dt, inventory, withdrawn_volume)
                self.assertEqual(0, cmdty_consumed_withdraw)

    def test_cmdty_consumed_withdraw_series_init_parameter(self):
        storage = self._create_storage(cmdty_consumed_withdraw=self._series_cmdty_consumed_withdraw)
        withdrawn_volume = 12.05
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_cmdty_consumed_withdraw = self._series_cmdty_consumed_withdraw[dt] * withdrawn_volume
            for inventory in [2.54, 500.58, 1234.56]:
                cmdty_consumed_withdraw = storage.cmdty_consumed_withdraw(dt, inventory, withdrawn_volume)
                self.assertEqual(expected_cmdty_consumed_withdraw, cmdty_consumed_withdraw)

    def test_inventory_pcnt_loss_scalar_init_parameter(self):
        storage = self._create_storage()
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            inventory_loss = storage.inventory_pcnt_loss(dt)
            self.assertEqual(self._constant_inventory_loss, inventory_loss)

    def test_inventory_pcnt_loss_none_init_parameter(self):
        storage = self._create_storage(inventory_loss=None)
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            inventory_loss = storage.inventory_pcnt_loss(dt)
            self.assertEqual(0, inventory_loss)

    def test_inventory_pcnt_loss_series_init_parameter(self):
        storage = self._create_storage(inventory_loss=self._series_inventory_loss)
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            inventory_loss = storage.inventory_pcnt_loss(dt)
            expected_inventory_loss = self._series_inventory_loss[dt]
            self.assertEqual(expected_inventory_loss, inventory_loss)

    def test_inventory_cost_scalar_init_parameter(self):
        storage = self._create_storage()
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [0, 500.58, 1234.56, 1800]:
                inventory_cost = storage.inventory_cost(dt, inventory)
                self.assertEqual(self._constant_inventory_cost * inventory, inventory_cost)

    def test_inventory_cost_none_init_parameter(self):
        storage = self._create_storage(inventory_cost=None)
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            for inventory in [0, 500.58, 1234.56, 1800]:
                inventory_cost = storage.inventory_cost(dt, inventory)
                self.assertEqual(0.0, inventory_cost)

    def test_inventory_cost_series_init_parameter(self):
        storage = self._create_storage(inventory_cost=self._series_inventory_cost)
        for dt in [date(2019, 8, 28), date(2019, 9, 1), date(2019, 9, 20)]:
            expected_inventory_cost = self._series_inventory_cost[dt]
            for inventory in [0, 500.58, 1234.56, 1800]:
                inventory_cost = storage.inventory_cost(dt, inventory)
                self.assertEqual(expected_inventory_cost * inventory, inventory_cost)
Exemplo n.º 6
0
    def test_three_factor_seasonal_regression(self):
        storage_start = '2019-12-01'
        storage_end = '2020-04-01'
        constant_injection_rate = 700.0
        constant_withdrawal_rate = 700.0
        constant_injection_cost = 1.23
        constant_withdrawal_cost = 0.98
        min_inventory = 0.0
        max_inventory = 100000.0

        cmdty_storage = CmdtyStorage('D', storage_start, storage_end, constant_injection_cost,
                                     constant_withdrawal_cost, min_inventory=min_inventory,
                                     max_inventory=max_inventory,
                                     max_injection_rate=constant_injection_rate,
                                     max_withdrawal_rate=constant_withdrawal_rate)
        inventory = 0.0
        val_date = '2019-08-29'
        low_price = 23.87
        high_price = 150.32
        date_switch_high_price = '2020-03-12'
        forward_curve = utils.create_piecewise_flat_series([low_price, high_price, high_price],
                                                           [val_date, date_switch_high_price,
                                                            storage_end], freq='D')

        flat_interest_rate = 0.03
        interest_rate_curve = pd.Series(index=pd.period_range(val_date, '2020-06-01', freq='D'))
        interest_rate_curve[:] = flat_interest_rate

        # Multi-Factor parameters
        spot_mean_reversion = 16.2
        spot_volatility = 1.15
        seasonal_volatility = 0.18
        long_term_vol = 0.14

        def twentieth_of_next_month(period): return period.asfreq('M').asfreq('D', 'end') + 20

        progresses = []

        def on_progress(progress): progresses.append(progress)

        # Simulation parameter
        num_sims = 500
        seed = 11
        fwd_sim_seed = seed # Temporarily set to pass regression tests
        basis_funcs = '1 + x_st + x_sw + x_lt + x_st**2 + x_sw**2 + x_lt**2'
        discount_deltas = False

        multi_factor_val = three_factor_seasonal_value(cmdty_storage, val_date, inventory, forward_curve,
                                                       interest_rate_curve, twentieth_of_next_month,
                                                       spot_mean_reversion, spot_volatility, long_term_vol,
                                                       seasonal_volatility,
                                                       num_sims,
                                                       basis_funcs,
                                                       discount_deltas,
                                                       seed=seed,
                                                       fwd_sim_seed=fwd_sim_seed,
                                                       on_progress_update=on_progress)
        self.assertAlmostEqual(multi_factor_val.npv, 1766460.137569665, places=6)
        self.assertEqual(123, len(multi_factor_val.deltas))  # TODO look into why deltas is longer the intrinsic profile
        self.assertEqual(123, len(multi_factor_val.expected_profile))
        self.assertEqual(progresses[-1], 1.0)
        self.assertEqual(245, len(progresses))
        self.assertEqual(1703773.0757192627, multi_factor_val.intrinsic_npv)
        self.assertEqual(123, len(multi_factor_val.intrinsic_profile))
        self.assertEqual((123, num_sims), multi_factor_val.sim_spot_regress.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_spot_valuation.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_inventory.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_inject_withdraw.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_cmdty_consumed.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_inventory_loss.shape)
        self.assertEqual((123, num_sims), multi_factor_val.sim_net_volume.shape)