# Settlement How every firefly's day is turned into money. Everything is in RON; EUR is shown using the BNR reference rate in force on the delivery day. Code: `src/fireflies/settlement/engine.py`. Hand-computed tests: `tests/test_settlement.py`. ## 1. Day-ahead (PZU) For each 15-minute interval *i* a firefly offers a quantity `q_i` (0 ≤ q_i ≤ forecast_i) with a minimum price `m_i`. OPCOM publishes the clearing price `P_i`. ``` accepted_i = q_i > 0 and m_i ≤ P_i sold_i = accepted_i ? q_i : 0 revenue_da_i = sold_i × P_i (negative when P_i < 0 and the offer allowed it) ``` We assume the park is a price-taker: its offer doesn't move the clearing price. For 10 MW in a market that clears about 1.5–2.5 GW per interval, that's a fair assumption. ## 2. Physical production `produced_i` = the pvlib model run on the "actual" weather (see data-sources.md), unless the firefly chose to **curtail** that interval, in which case `produced_i = 0`. Curtailing is how a park avoids spilling energy into negative prices. Without it, unsold production is still produced and becomes an imbalance surplus. - `naive`, `prudent` never curtail: that is what an unmanaged small park does. - `curtailer` curtails the intervals it withheld because it expected negative prices. - `llm` curtails the daylight intervals where it chose fraction 0. ## 3. Imbalance ``` imbalance_i = produced_i − sold_i (> 0 surplus / long, < 0 deficit / short) imbalance_ron_i = imbalance_i × P_surplus_i if imbalance_i > 0 imbalance_i × P_deficit_i if imbalance_i < 0 final_i = revenue_da_i + imbalance_ron_i ``` So a short park pays |imbalance| × P_deficit, and receives money if P_deficit is negative. A long park receives imbalance × P_surplus, and pays if P_surplus is negative. ### Romanian rules we rely on (researched 2026-09-26) - The imbalance settlement period (ISP) has been 15 minutes since 2021-02-01. - Legal basis: ANRE Order 127/2021 (BRP regulation), amended by ANRE Order 9/2025 (final-price art. 195 from 2025-04-01; estimated/initial prices, arts. 187/189, from 2025-05-01). Applied by Transelectrica procedure TEL-01.22. - **Estimated price.** This is what Transelectrica publishes in near real time: - If only upward balancing energy is activated: the volume-weighted average of the upward marginal prices. - If only downward is activated: the same for downward. - If both are activated: follow the system direction. - If nothing is activated: (lowest upward bid + |highest downward bid|) / 2. - In practice it is almost always a **single price**: every interval on 23–25 Sep 2026 had deficit = surplus. - **Final price.** The estimate plus a TSO financial-neutrality component. It becomes **dual** (a deficit price from upward activations, a surplus price from downward ones) when a system-consistency check fails. Finals appear about 45–60 days after month end. - The day-ahead price has no role in the imbalance price (no PIP cap or component). ### Assumptions (simplifications) 1. **We settle on Transelectrica's estimated imbalance prices**, not the finals. The finals come about two months later, only through an undocumented ENTSO-E page, and can differ a lot (on 2025-09-25 only 64 of 96 intervals were unchanged). A re-settlement on final prices is stubbed for later. 2. **Our park is its own balance responsible party (BRP).** Real small parks usually sit in an aggregator's balancing group, which nets their imbalances against other members' and charges a fee. We apply the raw TSO price with no netting and no fee. 3. Up to 8 intervals per day published as "N/A" are filled by linear interpolation between their neighbours. A day with more gaps waits for data. 4. There are no grid tariffs, green certificates, contracts for difference (CfD) or OPCOM/Transelectrica fees. Revenue is energy-only. 5. Days follow OPCOM's own interval count: 96 on normal days, 92 on the spring clock-change day and 100 on the autumn one (OPCOM publishes exactly that). ## 4. Baseline: perfect foresight The park sells exactly its actual production at the clearing price, stays off when the price is negative, and has zero imbalance: ``` final = Σ max(P_i, 0) × actual_i ``` The leaderboard reports each firefly's cumulative final revenue as a percentage of this. **It is a reference point, not a strict ceiling.** When imbalance prices sit below day-ahead prices, as they often do at midday in solar-heavy hours, selling more than you produce and buying the shortfall back at the imbalance price *earns* money. A firefly can then beat "perfect" foresight by being short. The backtest shows this happening; see the CHANGELOG notes for phase 3. "National pro-rata" (a baseline using the national solar profile) is planned. ## 5. Metrics - **% of perfect foresight** = Σ final / Σ final(perfect foresight), over the same park-days. - **Imbalance** = Σ imbalance_ron (negative means cost). - **Captured price** = Σ final / Σ produced MWh, compared with the **base price** (the day's mean clearing price).