optimise_arbitrage maximises the income from a battery storage solution by using a linear programming based optimisation.

optimise_arbitrage(
  data,
  price_from,
  exclude_from = NULL,
  max_charge_from = NULL,
  min_charge_from = NULL,
  capacity,
  c_rate,
  efficiency = 1,
  t_period = 0.5,
  init_charge = 0,
  deg_cost_per_cycle = 0
)

Arguments

data

data frame, with a row for each settlement period and columns for:

Spot Price.

Numeric, mandatory. Electricity spot price for each settlement period.

Excluded Settlement Periods.

Logical, optional. Should the settlement period be excluded from arbitrage optimisation?

Minimum Charge.

Numeric, optional. Minimum charge at beginning of settlement period.

Maximum Charge.

Numeric, optional. Maximum charge at beginning of settlement period.

price_from

string. Name of column in data which refers to the spot price.

exclude_from

string. Name of column in data which refers to excluded settlement periods, if applicable.

max_charge_from

string. Name of column in data which refers to maximum charge, if applicable.

min_charge_from

string. Name of column in data which refers to minimum charge, if applicable.

capacity

numeric scalar, battery capacity.

c_rate

numeric scalar, battery charge rate.

efficiency

numeric scalar, charge/discharge efficiency of battery.

t_period

numeric scalar, duration of a settlement period.

init_charge

numeric scalar, initial charge on battery.

deg_cost_per_cycle

numeric scalar, degradation cost per complete charge/discharge cycle.

Value

Returns a data.frame with the same data as the data argument, as well additional data describing the battery operation for optimal arbitrage income. The battery operation data is:

charge_state

numeric, the state of charge at the beginning of the settlement period for optimal arbitrage.

discharge

numeric, the proportion of the settlement period that the battery should discharge for optimal arbitrage.

charge

numeric, the proportion of the settlement period that the battery should charge for optimal arbitrage.

opt_arb

numeric, income during settlement period for optimal arbitrage.

deg_cost

numeric, cost of degradation during settlement period.

Details

The arbitrage market involves charging the battery when the price of electricity is low and discharging when it is high. The amount of energy that the battery can store is limited by its capacity. The charge rate is the battery power normalised by capacity. For example, a battery with a:

  • Charge rate of 1 will fully charge/discharge in 1 hour.

  • Charge rate of 2 will fully charge/discharge in 30 minutes.

  • Charge rate of .5 will fully charge/discharge in 2 hours.

The efficiency of the battery will impact the profitability of charging/discharging since a certain amount of energy is lost as heat during the process with comes at a cost.

The battery degrades as it is used. In this simple model, a degradation cost per charge/discharge cycle is assumed i.e. deg_cost_per_cycle. For each settlement period, the cost of degradation is calculated based on the proportion of a charge/discharge cycle occurring in the period.

Optionally, the exclude_from column of data can be used to control whether settlement periods should be excluded from arbitrage optimisation. If the value is TRUE, the settlement period will be excluded from arbitrage, or FALSE otherwise.

Optionally, the max_charge_from and/or min_charge_from columns of data can be supplied. If these arguments are not provided, then for every settlement period, the minimum charge will be zero and the maximum charge will be the value provided by the capacity argument. If max_charge_from and/or min_charge_from are set, then values specify the maximum and minimum charge, respectively, at the beginning of the corresponding settlement period. Any value that is NA is default to be zero for the minimum charge and the value provided by the capacity argument for the maximum charge.

Examples

optimise_arbitrage(data = data.frame(price = c(5.0, 5.0, 10.0, 10.0)), price_from = 'price', capacity = 1, c_rate = 1)
#> price charge_state discharge charge arb_income deg_cost #> 1 5 0.0 0 1 -2.5 0 #> 2 5 0.5 0 1 -2.5 0 #> 3 10 1.0 1 0 5.0 0 #> 4 10 0.5 1 0 5.0 0
optimise_arbitrage(data = data.frame(price = c(5.0, 5.0, 10.0, 10.0)), price_from = 'price', capacity = 1, c_rate = 1, efficiency = .7)
#> price charge_state discharge charge arb_income deg_cost #> 1 5 0 0 0 0 0 #> 2 5 0 0 0 0 0 #> 3 10 0 0 0 0 0 #> 4 10 0 0 0 0 0
optimise_arbitrage(data = data.frame(price = c(5.0, 5.0, 10.0, 10.0), exclude = c(0, 1, 1, 0)), price_from = 'price', capacity = 1, c_rate = 1, efficiency = .7)
#> price exclude charge_state discharge charge arb_income deg_cost #> 1 5 0 0 0 0 0 0 #> 2 5 1 0 0 0 0 0 #> 3 10 1 0 0 0 0 0 #> 4 10 0 0 0 0 0 0
optimise_arbitrage(data = data.frame(price = c(5.0, 5.0, 10.0, 10.0), exclude = c(0, 1, 1, 0), max_charge = c(NA, .4, NA, NA), min_charge = c(NA, .2, NA, NA)), price_from = 'price', capacity = 1, c_rate = 1, efficiency = .7)
#> price exclude max_charge min_charge charge_state discharge charge arb_income #> 1 5 0 NA NA 0 0 0 0 #> 2 5 1 0.4 0.2 0 0 0 0 #> 3 10 1 NA NA 0 0 0 0 #> 4 10 0 NA NA 0 0 0 0 #> deg_cost #> 1 0 #> 2 0 #> 3 0 #> 4 0
optimise_arbitrage(data = data.frame(price = c(5.0, 5.0, 10.0, 10.0)), price_from = 'price', capacity = 1, c_rate = 1, deg_cost_per_cycle = 2.0)
#> price charge_state discharge charge arb_income deg_cost #> 1 5 0.0 0 1 -2.5 -0.5 #> 2 5 0.5 0 1 -2.5 -0.5 #> 3 10 1.0 1 0 5.0 -0.5 #> 4 10 0.5 1 0 5.0 -0.5