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[Order], market_products: list[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[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

Complex Clearing Algorithm#

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

Bases: MarketRole

This class defines an optimization-based market clearing algorithm with support for complex bid types, including block bids, linked bids, minimum acceptance ratios, and profiled volumes. It supports network representations with either zonal or nodal configurations, enabling the modeling of complex markets with multiple zones and power flow constraints.

The market clearing algorithm accepts additional arguments via the param_dict in the market configuration.

Parameters:

marketconfig (MarketConfig) – The market configuration object containing all parameters for the market clearing process.

marketconfig#

The market configuration.

Type:

MarketConfig

incidence_matrix#

The incidence matrix representing the power network connections.

Type:

pd.DataFrame

nodes#

List of nodes or zones in the network, depending on the selected representation.

Type:

list

Supported Parameters in param_dict:
  • solver (str): Specifies the solver to be used for the optimization problem. Default is ‘appsi_highs’.

  • log_flows (bool): Indicates whether to log the power flows on the lines. Default is False.

  • pricing_mechanism (str): Defines the pricing mechanism to be used. Default is ‘pay_as_clear’, with an alternative option of ‘pay_as_bid’.

  • zones_identifier (str): The key in the bus data that identifies the zone each bus belongs to. Used for zonal representation.

Example market configuration:

market_mechanism: complex_clearing
param_dict:
    solver: apps_highs
    log_flows: true
    pricing_mechanism: pay_as_clear
    zones_identifier: zone_id
Network Representations:
  • Zonal Representation: The network is divided into zones, and the incidence matrix represents the connections between these zones.
    • If a zones_identifier is provided, buses are grouped into zones based on this identifier.

    • The incidence matrix is 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.

  • Nodal Representation: If no zones_identifier is provided, each bus is treated as a separate node, and the incidence matrix represents the connections between these nodes.

clear(orderbook: list[Order], market_products) tuple[list[Order], list[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. flows (dict): The power flows on the lines.

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

define_solver(solver: str)#
required_fields: list[str] = ['bid_type']#
validate_orderbook(orderbook: list[Order], agent_addr: AgentAddress) 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_addr (AgentAddress) – The agent address of the market.

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[Order], rejected_orders: list[Order], market_products: list[MarketProduct], market_clearing_prices: dict, pricing_mechanism: str = 'pay_as_clear', log_flows: bool = False)#

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[Order], market_products: list[MarketProduct], mode: str, with_linked_bids: bool, incidence_matrix: DataFrame = None, lines: DataFrame = None, solver: str = 'appsi_highs', solver_options: dict = {})#

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 (HIGHS 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(accepted: list[Order], market_products: list[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[Order], market_products) tuple[list[Order], list[Order], list[dict], dict[tuple, float]]#

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#