PayAsClearRole.clear() calculates the uniform clearing price as the maximum bid price across all accepted_supply_orders:
clear_price = float(max(map(itemgetter("price"), accepted_supply_orders)))
The calculation does not exclude supply orders with an economically zero accepted volume.
In an EOM run with storage, floating-point SOC/ramping arithmetic produced an accepted BESS volume of 1.1247e-14 MW. Although this is physically zero, the BESS offer remained in accepted_supply_orders and set the uniform price.
Observed examples:
Timestamp Published price BESS accepted volume Highest materially accepted supply bid
━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2027-01-03 19:00 1000.00 €/MWh 1.1247e-14 MW 290.36 €/MWh
────────────────── ───────────────── ────────────────────── ────────────────────────────────────────
2027-10-26 19:00 778.18 €/MWh 1.1247e-14 MW 281.74 €/MWh
This is economically material: in a pay-as-clear market, a numerical residual with no physical dispatch should not become the marginal unit and determine settlement for all accepted
supply.
Suggested fix: canonicalize near-zero accepted volumes using a configurable volume tolerance, and exclude orders with abs(accepted_volume) <= tolerance from price formation (and preferably from accepted-order/dispatch output). The tolerance should apply generically to all units, not only storage.
A regression test should cover a high-price supply bid with an accepted volume below tolerance and assert that it cannot set the clearing price.
PayAsClearRole.clear()calculates the uniform clearing price as the maximum bid price across allaccepted_supply_orders: