Market Mechanisms

Contents

Market Mechanisms#

A Market Mechanism is used to execute the clearing, scheduled by the MarketRole in base_market.py

The method signature for the market_mechanism is given as:

def clearing_mechanism_name(
  market_agent: MarketRole,
  market_products: list[MarketProduct],
):
  accepted_orders: Orderbook = []
  rejected_orders: Orderbook = []
  meta: list[Meta] = []
  return accepted_orders, rejected_orders, meta

The market_mechanism is called by the MarketRole, which is the agent that is responsible for the market. It is called with the market_agent and the market_products, which are the products that are traded in the current opening of the market. This gives maximum flexbility as it allows to access properties from the MarketRole directly. The market_mechanism returns a list of accepted orders, a list of rejected orders and a list of meta information (for each tradable market product or trading zone, if needed). The meta information is used to store information about the clearing, e.g. the min and max price, the cleared demand volume and supply volume, as well as the information about the cleared product.

In the Market Mechanism, the MarketRole is available to access the market configuration with market_agent.marketconfig and the available Orders from previous clearings through market_agent.all_orders. In the future, the MarketMechanism will be a class which contains the additional information like grid information without changing the MarketRole.

The available market mechanisms are the following:

  1. assume.markets.clearing_algorithms.simple.PayAsClearRole()

  2. assume.markets.clearing_algorithms.simple.PayAsBidRole()

  3. assume.markets.clearing_algorithms.all_or_nothing.PayAsClearAonRole()

  4. assume.markets.clearing_algorithms.all_or_nothing.PayAsBidAonRole()

  5. assume.markets.clearing_algorithms.complex_clearing.ComplexClearingRole()

  6. assume.markets.clearing_algorithms.complex_clearing_dmas.ComplexDmasClearingRole()

  7. assume.markets.clearing_algorithms.redispatch.RedispatchMarketRole()

  8. assume.markets.clearing_algorithms.nodal_pricing.NodalMarketRole()

  9. assume.markets.clearing_algorithms.contracts.PayAsBidContractRole()

The PayAsClearRole performs an electricity market clearing using a pay-as-clear mechanism. This means that the clearing price is the highest price that is still accepted. This price is then valid for all accepted orders. For this, the demand and supply are separated, before the demand is sorted from highest to lowest order price and the supply lowest to highest order price. Where those two curves in a price over power plot meet, the market is cleared for the price at the intersection. All supply orders with a price below and all demand orders above are accepted. Where the price is equal, only partial volume is accepted.

The PayAsBidRole cleares the market in the same manner as the pay-as-clear mechanism, but the accepted_price is the price of the supply order for both the demand order and the supply orders that meet this demand.

The PayAsClearAonRole performs an electricity market clearing using a pay-as-clear mechanism where each bids volume needs an exactly matching order with the same volume. Partial clearing is not allowed here. This has the side effect, that the cleared price can be much higher if bids with different volume are accepted.

The PayAsBidAonRole performs an electricity market clearing using a pay-as-bid mechanism where each bids volume needs an exactly matching order with the same volume as in PayAsClearAonRole.

Complex clearing#

The ComplexClearingRole performs an electricity market clearing using an optimization to clear the market. Here, also profile block and linked orders are supported. The objective function is a social welfare maximization, which is equivalent to a cost minimization:

\[\min \left( {\sum_{b \in \mathcal{B}}\quad{u_b \: C_{b} \: P_{b, t}} \: T} \right),\]

where \(\mathcal{B}\) is the set of all submitted bids, \(C_{b}\) is the bid price, \(P_{b, t}\) is the volume offered (demand is negative) and \(T\) is the clearing horizon of 24 hours. Decision variables are the acceptance ratio \(u_b\) with \(u_b \in [0, 1] \quad \forall \: b \in \mathcal{B}\), and the clearing status \(x_b\) with \(x_b \in \{0, 1\} \: \forall \: b \in \mathcal{B}\).

The optimization problem is subject to the following constraints:

The energy balance constraint: \(\quad \sum_{b \in \mathcal{B}} P_{b, t} \: u_b = 0 \quad \forall \: t \in \mathcal{T}\),

The minimum acceptance ratio constraint: \(\quad u_{b} \geq U_{b} \: x_{b} \quad \mathrm{and} \quad u_{b} \leq x_{b} \quad \forall \: b \in \mathcal{B}\),

with the minimum acceptance ratio \(U_{b}\) defined for each bid b.

The linked bid contraint, ensuring that the acceptance of child bids c is below the acceptance of their parent bids p is given by: \(\mathbf{a}_{c, p} \: u_c \leq u_{p} \quad \forall \: c, p \in \mathcal{B}\),

with the incidence matrix \(\mathbf{a}_{c, p}\) defining the linkes between bids as 1, if c is linked as child to p, 0 else.

Because with this algorithm, paradoxically accepted bids (PABs) can occur, the objective is solved in an iterative manner:

  1. The optimization problem is solved with the objective function and all constraints.

  2. The binary variables \(x_b\) are fixed to the current solution.

  3. The optimization problem is solved again without the minimum acceptance ratio constraint.

  4. The market clearing prices are given as the dual variables of the energy balance constraint.

  5. The surplus of each bid is calculated as the difference between the bid price and the market clearing price.

  6. If the surplus for one or more bids is negative, the clearing status \(x_b\) for those bids is set to 0 and the algorithm starts again with step 1.

If you want a hands-on use-case of the complex clearing check out the prepared tutorial in Colab: https://colab.research.google.com/github/assume-framework/assume