Market Clearing Algorithms#

Overview#

This document provides an overview of various market clearing algorithms used in the ASSUME framework.

Simple Market Clearing Algorithms#

Pay-as-Bid#

This class implements the pay-as-bid mechanism in a simple way using iterative clearing. It is a simple clearing algorithm that clears the market by sorting the bids and offers in ascending order and then matching them one by one until the market is cleared.

class assume.markets.clearing_algorithms.simple.PayAsBidRole(marketconfig: MarketConfig)#
clear(orderbook: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct])#

Simulates electricity market clearing using a pay-as-bid mechanism.

Parameters:
  • orderbook (Orderbook) – the orders to be cleared as an orderbook

  • market_products (list[MarketProduct]) – the list of products which are cleared in this clearing

Returns:

accepted orderbook, rejected orderbook and clearing meta data

Return type:

tuple[Orderbook, Orderbook, list[dict]]

Pay-as-Clear#

This class implements the pay-as-clear mechanism within the merit order clearing algorithm. It is a simple clearing algorithm that clears the market by sorting the bids and offers in ascending order and then matching them one by one until the market is cleared.

class assume.markets.clearing_algorithms.simple.PayAsClearRole(marketconfig: MarketConfig)#
clear(orderbook: list[assume.common.market_objects.Order], market_products)#

Performs electricity market clearing using a pay-as-clear mechanism. This means that the clearing price is the highest price that is still accepted. The clearing price is the same for all accepted orders.

Parameters:
  • orderbook (Orderbook) – the orders to be cleared as an orderbook

  • market_products (list[MarketProduct]) – the list of products which are cleared in this clearing

Returns:

accepted orderbook, rejected orderbook and clearing meta data

Return type:

tuple

All-or-Nothing Market Clearing Algorithms#

Pay-as-Bid#

This class implements the pay-as-bid mechanism where each bid’s volume requires an exactly matching order with the same volume. Partial clearing is not allowed here.

class assume.markets.clearing_algorithms.all_or_nothing.PayAsBidAonRole(marketconfig: MarketConfig)#
clear(orderbook: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct])#

This implements pay-as-bid where each bids volume needs an exactly matching order with the same volume. Partial clearing is not allowed here.

Parameters:
  • orderbook (Orderbook) – the orders to be cleared as an orderbook

  • market_products (list[MarketProduct]) – the list of products which are cleared in this clearing

Returns:

accepted orderbook, rejected orderbook and clearing meta data

Return type:

tuple[Orderbook, Orderbook, list[dict]]

Pay-as-Clear#

This class implements the pay-as-clear mechanism within the all-or-nothing clearing algorithm.

class assume.markets.clearing_algorithms.all_or_nothing.PayAsClearAonRole(marketconfig: MarketConfig)#
clear(orderbook: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct])#

This implements pay-as-clear 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

Parameters:
  • orderbook (Orderbook) – the orders to be cleared as an orderbook

  • market_products (list[MarketProduct]) – the list of products which are cleared in this clearing

Returns:

accepted orderbook, rejected orderbook and clearing meta data

Return type:

tuple[Orderbook, Orderbook, list[dict]]

Complex Clearing Algorithm#

class assume.markets.clearing_algorithms.complex_clearing.ComplexClearingRole(marketconfig: MarketConfig)#

Bases: MarketRole

Defines the clearing algorithm for the complex market.

The complex market is a pay-as-clear market with more complex bid structures, including minimum acceptance ratios, bid types, and profiled volumes.

The class supports two types of network representations:

  1. Zonal Representation: The network is divided into zones, and the incidence matrix represents the connections between these zones.

  2. Nodal Representation: Each bus in the network is treated as a node, and the incidence matrix represents the connections between these nodes.

Zonal Representation:

If a zones_identifier is provided in the market configuration param_dict, the buses are grouped into zones based on this identifier. The incidence matrix is then constructed to represent the power connections between these zones. The total transfer capacity between zones is determined by the sum of the capacities of the lines connecting the zones. - zones_identifier (str): The key in the bus data that identifies the zone to which each bus belongs.

Nodal Representation:

If no zones_identifier is provided, each bus is treated as a separate node. The incidence matrix is constructed to represent the power connections between these nodes.

marketconfig#

The market configuration.

Type:

MarketConfig

incidence_matrix#

The incidence matrix representing the network connections.

Type:

pd.DataFrame

nodes#

List of nodes or zones in the network.

Type:

list

Parameters:

marketconfig (MarketConfig) – The market configuration.

clear(orderbook: list[assume.common.market_objects.Order], market_products) tuple[list[assume.common.market_objects.Order], list[assume.common.market_objects.Order], list[dict]]#

Implements pay-as-clear with more complex bid structures, including acceptance ratios, bid types, and profiled volumes.

Parameters:
  • orderbook (Orderbook) – The orderbook to be cleared.

  • market_products (list[MarketProduct]) – The products to be traded.

Raises:

Exception – If the problem is infeasible.

Returns:

The accepted orders. rejected_orders (Orderbook): The rejected orders. meta (list[dict]): The market clearing results.

Return type:

accepted_orders (Orderbook)

Notes

First the market clearing is solved using the cost minimization with the pyomo model market_clearing_opt. Then the market clearing prices are extracted from the solved model as dual variables of the energy balance constraint. Next the surplus of each order and its children is calculated and orders with negative surplus are removed from the orderbook. This is repeated until all orders remaining in the orderbook have positive surplus. Optional additional fields are: min_acceptance_ratio, parent_bid_id, node

required_fields: list[str] = ['bid_type']#
validate_orderbook(orderbook: list[assume.common.market_objects.Order], agent_tuple) None#

Checks whether the bid types are valid and whether the volumes are within the maximum bid volume.

Parameters:
  • orderbook (Orderbook) – The orderbook to be validated.

  • agent_tuple (tuple[str, str]) – The agent tuple of the market (agent_addr, agent_id).

Raises:

ValueError – If the bid type is invalid.

assume.markets.clearing_algorithms.complex_clearing.calculate_order_surplus(order: dict, market_clearing_prices: dict, instance: ConcreteModel, children: list[dict])#

Calculates the surplus of an order given the market clearing prices and results of the market clearing.

Parameters:
  • order (dict) – The order

  • market_clearing_prices (dict) – The market clearing prices.

  • instance (pyomo.core.base.PyomoModel.ConcreteModel) – The solved pyomo model containing the results of the market clearing.

  • children (list[dict]) – The linked child bids of the given order.

Returns:

The surplus of the order as (market_clearing_price - order_price) * order_volume * order_acceptance

Return type:

float

Note

The surplus of children linked to the given order is added if it is positive to account for the rule that children can ‘save’ their parent bid.

assume.markets.clearing_algorithms.complex_clearing.extract_results(model: ConcreteModel, orders: list[assume.common.market_objects.Order], rejected_orders: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct], market_clearing_prices: dict)#

Extracts the results of the market clearing from the solved pyomo model.

Parameters:
  • model (pyomo.core.base.PyomoModel.ConcreteModel) – The solved pyomo model containing the results of the market clearing

  • orders (Orderbook) – List of the orders

  • rejected_orders (Orderbook) – List of the rejected orders

  • market_products (list[MarketProduct]) – The products to be traded

  • market_clearing_prices (dict) – The market clearing prices

Returns:

The accepted orders, rejected orders, and meta information

Return type:

tuple[Orderbook, Orderbook, list[dict]]

assume.markets.clearing_algorithms.complex_clearing.market_clearing_opt(orders: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct], mode: str, with_linked_bids: bool, incidence_matrix: DataFrame = None, lines: DataFrame = None, solver: str = 'glpk')#

Sets up and solves the market clearing optimization problem.

Parameters:
  • orders (Orderbook) – The list of the orders.

  • market_products (list[MarketProduct]) – The products to be traded.

  • mode (str) – The mode of the market clearing determining whether the minimum acceptance ratio is considered.

  • with_linked_bids (bool) – Whether the market clearing should include linked bids.

  • incidence_matrix (pd.DataFrame) – The incidence matrix of the network. (Shows the connections between nodes.)

  • lines (pd.DataFrame) – The lines and their capacities of the network.

Returns:

The solved pyomo model and the solver results

Return type:

tuple[pyomo.core.base.PyomoModel.ConcreteModel, pyomo.opt.results.SolverResults]

Notes

The problem is formulated as a mixed-integer linear program (MILP) and solved using the pyomo package. The objective function is to maximize the social welfare and defined as the sum of the product of the price, volume, and acceptance ratio of each order. The decision variables are given by the acceptance ratio of each order bounded by 0 and 1 and the acceptance as a binary variable.

The energy balance constraint ensures that the sum of the accepted volumes of all orders is zero. The acceptance of each order is bounded by 0 and 1.

If the mode is ‘with_min_acceptance_ratio’, the minimum acceptance ratio is considered. The minimum acceptance ratio is defined as the ratio of the minimum volume to accept to the total volume of the order.

If linked bids are considered, the acceptance of a child bid is bounded by the acceptance of its parent bid.

The market clearing is solved using pyomo with the specified solver (glpk is used by default). If the specified solver is not available, the model is solved using available solver. If none of the solvers are available, an exception is raised.

After solving the model, the acceptance of each order is fixed to the value in the solution and the model is solved again. This removes all binary variables from the model and allows to extract the market clearing prices from the dual variables of the energy balance constraint.

Complex Clearing from DMAS model#

class assume.markets.clearing_algorithms.complex_clearing_dmas.ComplexDmasClearingRole(marketconfig: MarketConfig, verbose: bool = False)#

Bases: MarketRole

clear(orderbook: list[assume.common.market_objects.Order], market_products: list[assume.common.market_objects.MarketProduct])#

This performs the process of “market clearing” for a given market agent and its orders. During this process, incoming orders are matched against each other and allocations are determined to adhere to market rules. Linked orders are respected to be only taken if the prior block was also taken. Orders with the same exclusive ID from the same agent can only be taken together, in which case no other exclusive blocks can be taken. The result are an orderbook, the rejected orders and market metadata.

Limitations:
  • The clearing is currently one-sided, in the way that the price of the demand is not respected

  • A per-agent-unique bid_id is required for standard bids

  • The cost of taking additional blocks is taken individually instead (like pay-as-bid) instead of applying uniform pricing during the calculation

Parameters:
  • orderbook (Orderbook) – the orders to be cleared as an orderbook

  • market_products (list[MarketProduct]) – the list of products which are cleared in this clearing

Returns:

accepted orderbook, rejected orderbook and clearing meta data

Return type:

tuple[Orderbook, Orderbook, list[dict]]

required_fields: list[str] = ['link', 'block_id', 'exclusive_id']#

Redispatch Clearing Algorithm#

class assume.markets.clearing_algorithms.redispatch.RedispatchMarketRole(marketconfig: MarketConfig)#

Bases: MarketRole

A market role that performs redispatch to resolve congestion in the electricity market. It uses PyPSA to model the electricity network and perform the redispatch. The redispatched is based on the price the units submit in their orders. This allows this to be a cost based redispatch if units submit their marginal costs as prices. Or it can be a price based redispatch if units submit actual bid prices.

Parameters:

marketconfig (MarketConfig) – The market configuration.

Notes

Users can also configure the path to the network data, the solver to be used, and the backup marginal cost in the param_dict of the market configuration.

clear(orderbook: list[assume.common.market_objects.Order], market_products) tuple[list[assume.common.market_objects.Order], list[assume.common.market_objects.Order], list[dict]]#

Performs redispatch to resolve congestion in the electricity market. It first checks for congestion in the network and if it finds any, it performs redispatch to resolve it. The returned orderbook contains accepted orders with the redispatched volumes and prices. The prices are positive for upward redispatch and negative for downward redispatch.

Parameters:
  • orderbook (Orderbook) – The orderbook to be cleared.

  • market_products (list[MarketProduct]) – The products for which clearing happens.

Returns:

The accepted orderbook, rejected orderbook and market metadata.

Return type:

Tuple[Orderbook, Orderbook, List[dict]]

process_dispatch_data(network: Network, orderbook_df: DataFrame)#

This function processes the dispatch data to calculate the redispatch volumes and prices and update the orderbook with the accepted volumes and prices.

Parameters:

orderbook_df (pd.DataFrame) – The orderbook to be cleared.

required_fields: list[str] = ['node', 'max_power', 'min_power']#
setup()#

Sets up the initial configuration and subscriptions for the market role.

This method performs the following actions:
  • Sets the address and agent ID of the market configuration to match the current context.

  • Validates that all required fields are present in the market configuration.

  • Defines filter methods (accept_orderbook, accept_registration, accept_get_unmatched, accept_data_request)

that serve as validation steps for different types of incoming messages. - Subscribes the role to handle incoming messages using the appropriate handler methods. - Schedules the opening() method to run at the next opening time of the market. - Sends grid topology data once, if available.

Raises:

ValueError – If a required field is missing from the market configuration.

Additional Details#

For more details on the market clearing algorithms, refer to the module contents.

Module Contents#