0. Overview
Southern African Power Pool (SAPP) participation is a toolkit, not a second market inside the platform. The Coordination Centre in Harare clears the competitive markets, publishes rates and issues the monthly statement. This platform holds a book, submits before the gate, nominates against real transfer capability, and shadows the statement closely enough to argue with it line by line.
It does not operate the pool. It does not hedge. Completing against the in-process simulator is completion: the behaviours, the persistence, the gate and the screens are real; only the transport is simulated. Live participation is a configuration change, gated on membership.
Why currency before the pool
The two-layer money model stays intact:
- engines compute in
Decimal; - documents persist integer minor units.
Currency is a denomination of those minor units, not a third layer and not a foreign-exchange conversion. Conversion is an explicit step against a published rate set. Until then, mixed-currency arithmetic is refused by name.
A dollar-priced pool trade billed in Rands is two numbers. Without a currency on every document they would share a totals column, and the arithmetic would be a silent error. That is why this volume opens with denomination, then rates, then the desk.
What this volume covers
| Chapter | For the trader seat |
|---|---|
| §1 The pool and membership | Sponsored vs direct; who transmits |
| §2 Four markets and their gates | DAM 09:30 CAT; FPM monthly and weekly |
| §3 Currency risk | Booked vs current; what the platform will not do |
| §4 The wheeling path | Why delivery is smaller than dispatch |
| §5 The monthly statement | Shadow, variance, :FX |
| §6 The Regional desk | /org/regional screen by screen |
| §7 Reference card | Routes, pins, refusals |
| §8 Terms | Vocabulary |
Bridges: V9 (domestic market), V10 (Bid Desk beside this desk), V8 (domestic reconciliation vocabulary), V15 (document denomination).
1. The pool and membership
The Southern African Power Pool is a competitive market run by the Coordination Centre in Harare. Members trade day-ahead, intraday and forward physical products. Clearing is in US dollars. A South African trader reaches that market through one of two channels:
| Channel | Who you are | Who transmits | Whose statement you shadow |
|---|---|---|---|
| Sponsored | Trading under an operating member | The sponsor | The sponsor’s pass-through |
| Direct | A Market Participant in your own right (possible since 2021) | You | The Coordination Centre’s statement |
The channel is configuration, not a fork. The bid you build is the Coordination Centre’s bid either way. Only the transmitting identity changes. If the two channels ever became two code paths, the platform would have two bid builders to keep in agreement and would discover the disagreement on a day when a bid did not arrive.
The participation profile
One organisation, one pool participation. Two profiles would mean two books that no statement could be reconciled against.
The sponsor is data on the profile, not an assumption inside the client. Switching sponsors later is a row change. The demo estate names an illustrative sponsor so replacing it is data.
Follow along. This release does not list Regional under Trading. An organisation with no pool profile, on
/org/regional, sees Not participating — that is not a zero position; it is not in the pool.
What membership is not
Membership is a commercial event. Until it exists, setup, test and
demo talk to SappSim — the same shapes, deterministic,
never a socket. Swapping the adapter is configuration. Nothing here is
behind a feature flag.
2. Four markets and their gates
The pool runs four competitive products. This toolkit prepares and submits day-ahead and lodges forward physical (monthly and weekly). Intraday results can be retrieved; intraday strategy is not in this programme.
| Product | Gate (CAT) | What you send | What you hold |
|---|---|---|---|
| Day-ahead (DAM) | 09:30 the day before delivery | A 24-hour bid | A Trade / netted Position |
| FPM-Monthly | The pool’s forward window | A monthly base or peak shape | A ForwardSchedule (stage 11’s shape) |
| FPM-Weekly | The pool’s forward window | A weekly base or peak shape | The same register |
| Intraday | Continuous | Results retrieval only | Trades when the file arrives |
CAT equals SAST: both are a fixed UTC+02:00 with no daylight saving. The platform’s existing clock carries over. There is no second timezone database.
The 09:30 gate is data
The day-ahead gate is a parameter register row, not
a hardcoded 09:30. A regulated time that moves must move as
data. A build that completes past the gate is expired
and raises the same critical gate-miss alert the domestic DAM cycle
raises. Missing a gate silently is how a desk discovers at 10:00 that it
has no position and no hedge.
The function that decides is clock-free: tests inject the clock. You do not wait until 09:31 to prove the miss.
Forward products are not a second register
FPM-Monthly and FPM-Weekly expand to the same per-Trading-Period MW
profile the domestic Forward Physical Market already uses. Base is every
hour at the contracted MW. Peak is the peak window from the same
parameter register. An FPM contract is a ForwardSchedule
plus a foreign-currency price and a cross-border path —
not a parallel forward model. Two forward models would
give two answers to “what have we committed for Tuesday at 18:00”.
Lodgement is idempotent on the 24-hour key
{profile, trading_date, product}. A retried worker replays;
it does not lodge twice.
Follow along. Regional desk → Positions. A seeded demo book shows DAM and FPM rows by product and delivery period.
3. Currency risk
A dollar trade settled next month is not a dollar trade settled today. The Coordination Centre publishes daily rates at 08:30 CAT. You are exposed from the rate stamped when the trade was booked to the rate on the day the month is translated. That difference is real money. Nobody in this programme has decided who owns it, and the platform will not pretend to.
What the exposure report shows
Per settlement cycle, per foreign currency:
- Notional in the foreign currency
- Booked home-currency value (each position at the stamped rate)
- Current home-currency value (at the latest published set)
- Difference
The booked rate is the one on the trade. Moving today’s register does not move yesterday’s booking. A report that re-derived the booked rate from today’s register would show zero exposure every day — both wrong and reassuring, the worst combination.
What the platform will not do
It will not hedge, propose a hedge, or price one. The report is a measurement. Automatic hedging is treasury policy and out of scope. The Regional desk has no hedge button.
A missing rate blocks, it does not invent
A rate that was not published does not exist. There is no interpolation, no carry-forward of yesterday, no nearest-date search and no fallback to 1. The refusal names which date and which pair — “no USD/ZAR rate published for 2026-08-17”. The shadow statement cannot be built for a month with a gap. The exposure tile renders no rate published for this date and names the date, never a stale figure and never a zero.
Follow along. Regional desk → Rates and Exposure. Booked sits beside current. A gap date says so in words.
Reference publishers and provenance
The platform includes SARB direct rates and Frankfurter’s ECB fallback, plus a SARB historical mirror for backfill. The publisher stays SARB or ECB; the channel records direct or Frankfurter. Adapters refuse a response whose publication date differs from the requested day. Weekends and holidays can therefore remain missing. EUR, GBP and JPY have explicit currency precision in the register alongside ZAR and USD.
Mocks remain the default, and setup/demo runs prohibit external FX traffic. The source policy controls live fetch selection; it does not arm the trading valuation path. PD-F8-1 and the later conversion-policy integration remain go-live gates. No backfill rewrites a trade’s booked rate.
4. The wheeling path
A megawatt-hour sold into the pool and delivered across a border is not the megawatt-hour that arrives. It crosses one or more national grids. Each hop takes losses and may charge wheeling. Delivery is a path, not a destination: an ordered list of interconnector hops.
net_delivered = E_sent × Π(1 − TLF_hop)
The product runs unrounded. Rounding happens once, at the end, the same three-decimal half-up the domestic energy figures use. Rounding each hop instead accumulates an error neither party can reproduce from the other’s inputs.
A hop missing its loss factor is a refusal that names the hop. Missing is not zero loss — treating it as zero silently over-states delivery, which is the direction that loses money.
Wheeling charges stay per hop, in their own currencies. They are not summed here. They become their own lines on the shadow statement, where a rate exists to translate them.
Available transfer capability
What can flow is bounded by available transfer capability on each interconnector in each direction, per Trading Period:
ATC = declared capability − firm bilateral usage
Declared capability is what the System Operator already publishes
(max_import_mw / max_export_mw). Firm usage is
what the domestic forward register already holds — plus any FPM schedule
on this path. Spot sees the remainder. Bilateral priority is not a
tie-break; it is arithmetic.
A nomination that does not fit is refused with which hop, which interconnector, which direction and which period. An assumed (undeclared) capability is labelled and is not published as a network limit.
Follow along. Regional desk → Nominations, and System Operator → Network Model → Usage (
/so/network-model?tab=usage). Assumed rows wear an amber chip.
5. The monthly statement
Once a month the Coordination Centre issues a settlement statement, and the participant either believes it or cannot say why not. Shadowing is what makes the second option possible: the platform reconstructs what the statement should say, from its own positions × published clearing prices × published exchange rates, then joins reconstruction to the received file line by line.
This is the same pattern the domestic Market Operator reconciliation
already uses. The join is on {period, product} — an hourly
join, because a net of R 0 can hide two offsetting errors. Vocabulary is
unchanged: :MATCHED, :WITHIN_TOLERANCE,
:VARIANCE, :MISSING_INTERNAL,
:MISSING_MO.
The pool adds one hint the domestic reconciler cannot produce:
:FX, where quantity and foreign price both
match and the home-currency figure does not. That is why currency had to
land before the pool.
Every shadow line carries the rate it was translated at: foreign amount, rate, rate date, source, home amount. A translated figure stored without its rate is a number that cannot be re-derived.
A variance is a finding
Nothing writes back to a trade or a position. The platform does not decide who wins a disagreement. It produces the line-by-line evidence with which somebody argues.
Sponsored channel: two owners
Under sponsored participation the Coordination Centre addresses the sponsor. The participant shadows the sponsor’s pass-through. That produces two separately owned variances:
| Run | Owner | Counterpart |
|---|---|---|
| Participant vs sponsor | You | The sponsor’s pass-through |
| Sponsor vs pool | The sponsor | The Coordination Centre |
If the pool statement is absent, the second run is not invented.
A month with a missing rate cannot be built. A partially-translated statement that presents itself as complete would have its variances attributed to the pool.
Follow along. Demo step S18 seeds a shadowed month with at least one deliberate variance. The Regional desk is the place you read the book; the finding lives on the reconciliation run.
6. The Regional desk
The address is /org/regional. It is not a row in the
organisation sidebar for this release. Four boards, one LiveView, the
same chrome idiom as the Bid Desk.
| Board | Address | What you see |
|---|---|---|
| Positions | /org/regional |
Product, delivery period, signed MW, currency |
| Rates | /org/regional/rates |
Booked rate as stamped; current from the latest set |
| Exposure | /org/regional/exposure |
Notional, booked, current, difference — measurement only |
| Nominations | /org/regional/nominations |
Per hop, per direction, per period: declared, used, ATC, basis |
The Bid Desk is the domestic market. This desk is the pool. They are not side by side in the sidebar for this release. Which gate belongs to which market: domestic DAM is the Market Code gate on the Bid Desk; pool DAM is 09:30 CAT on this desk.
Not participating is not a zero book
An organisation with no participation profile sees a plain explanation, not an empty table of zeros. “Not in the pool” and “flat position” are different claims.
Access
Organisation membership, own-party read. Another organisation’s desk is a 404, not a 403. A 403 would disclose that the other organisation exists and trades in the pool.
Missing rates on screen
Where a rate is missing the tile says no rate published for this date and names the date. It does not show yesterday’s figure and it does not show zero.
Follow along. This release does not put Regional in the Trading sidebar. The boards, when opened at
/org/regional, are Positions, Rates, Exposure and Nominations. There is no hedge action on any board.
The hydrology regime appears above the tabs for participants; the Exposure tab adds source-dated indicators and the register uplift.
7. Reference card
Routes
| Path | Seat | Board |
|---|---|---|
/org/regional |
Organisation | Positions |
/org/regional/rates |
Organisation | Booked vs current |
/org/regional/exposure |
Organisation | Exposure tile |
/org/regional/nominations |
Organisation | ATC / nomination board |
/so/network-model?tab=usage |
System Operator | Declared interconnector usage |
No new SO route: usage is a tab on the existing Network Model screen.
Transports (never the network in setup or test)
| Seam | Config | Default |
|---|---|---|
| Coordination Centre | :sapp_client |
WB.Sim.SappSim |
| Daily FX rates | :fx_provider |
WB.Fx.Provider.Mock |
Live participation is two adapter swaps, gated on membership.
Refusals that name what is missing
| Situation | Shape |
|---|---|
| Mixed currencies, no rate | {:currency_mismatch, expected, actual} |
| No published rate | {:no_rate, date, {from, to}} |
| Hop without a loss factor | {:missing_loss_factor, sequence, interconnector} |
| Nomination over ATC | hop, interconnector, direction, period |
| Past 09:30 CAT | {:gate_missed, …} plus critical log |
| Unknown ISO 4217 code | refused; never defaults to two decimals |
Identities (do not “fix” these)
| Resource | Identity |
|---|---|
| Billing document | unchanged — currency is not in the tuple |
| FX rate set | {source, rate_date} |
| FX rate | {rate_set_id, base, quote} — inverse derived, never
stored |
| Participation profile | {organization_id} |
| Trade | {profile, external_trade_ref} |
| Position | {profile, product, delivery_period_start} |
| Cross-border path | {source_code, sink_code, direction} |
| Cross-border hop | {path_id, sequence} |
| Submission | 24-hour key {profile, date, product} |
Demo
S18 · Regional desk — sponsored profile, small FPM + DAM book, a cross-border path, a shadowed month with a classified variance. The sponsor is labelled illustrative.
Hydrology: /operator/hydrology records observations
keyed by indicator, source, date and revision. Mock is the default; ZRA
weekly is opt-in. Missing evidence, out-of-range observations and
changed table shapes are refused.
8. Terms used in this volume
ATC (available transfer capability). Declared interconnector capability minus firm bilateral (and FPM) usage, per Trading Period and direction.
Booked rate. The exchange rate stamped on a trade when it was booked. Does not move when the current register moves.
CAT. Central African Time. Equal to SAST: fixed UTC+02:00, no daylight saving.
Channel. :SPONSORED or
:DIRECT on the participation profile. Configuration, not a
fork. The Coordination Centre payload is identical; only the
transmitting identity differs.
Coordination Centre. The SAPP market operator in Harare. Publishes rates, runs the competitive markets, issues the monthly statement.
Currency. ISO 4217 denomination of a document’s
minor units. Not a dimension of billing identity. Default
"ZAR".
:FX hint. Reconciliation root cause:
quantity and foreign price match, home-currency figure does not.
FPM. Forward Physical Market products at the pool (monthly and weekly, base and peak). Same per-period shape as the domestic forward register.
Loss factor (TLF). Per-hop transmission loss. Composite delivery is the unrounded product, rounded once.
No-invention rule. A missing rate, hop or capability is a named refusal. Nothing interpolates, carries forward or defaults to 1.
Participation profile. One organisation’s pool membership: channel, sponsor, submitting party, statement source.
SappSim. In-process Coordination Centre mock. Default in test, setup and demo. Can be wrong on purpose so reconciliation has variances.
Shadow statement. Reconstruction of the monthly pool statement from own positions × prices × published rates. Every line carries its rate.
Sponsor. Under :SPONSORED, the
operating member who transmits. An attribute of the profile (GD7), never
a client literal.
Regime is the dated wet/normal/dry/critical classification. Live storage is usable reservoir storage. An uplift raises simulated pool prices; its evidence URL identifies the source observation. An unvalued hour lacks a required exchange rate.
9. Regional hydrology
The Regional desk shows a hydrology chip for organisations participating in SAPP. Its Exposure tab lists the observations and source links. Kariba live storage alone determines the regime. Other indicators provide context rather than votes in a combined model.
The dated parameter register starts with critical below 12%, dry below 25%, wet at or above 45%, and normal between those thresholds. Missing Kariba storage or missing parameters gives UNKNOWN. The dry uplift is 30%; critical is 100%. Those are editable register assumptions, not forecasts of the Zambezi.
A simulated feed is labelled in words. A stale observation retains its date; the Lab refuses to suggest an uplift from a stale or unknown regime. The default feed is Mock. The optional ZRA adapter reads its five-column weekly table; rejected access or a changed table leaves the previous observations intact. A feed outage does not stop the nightly risk calculation.
Operators capture a new observation at
/operator/hydrology with its observation date and evidence
URL. Corrections create revisions. Replaying identical content creates
no new row; manual evidence wins a same-date tie. Superseding closes the
effective window and requires a reason. Fetch now is queued and limited
to three manual calls per day, in addition to one scheduled weekly
fetch.
A regional-hydrology shock raises only prices on the book’s SAPP trade hours. A 10 MW purchase at 93 c/kWh loses R2,790 under a 30% uplift and R9,300 under 100%; a sale reverses the sign. The pool cap is converted from US cents/kWh using the applicable USD/ZAR rate. Missing price or cap conversions are recorded as unvalued hours and are never filled from another date. Books without pool exposure retain their existing KPI values.
In Scenario Lab, set a fixed regional uplift or choose Use
the hydrology register on the scenario start date. The register
choice refuses stale or unknown regimes. A ten-MW purchase for one hour
at 93 c/kWh loses R2,790 under a 30% uplift and R9,300 under a 100%
uplift, before any price-cap clipping. The Regional Desk accepts an
as_of date in its URL for dated review, for example
?as_of=2026-07-14; the card states the date being
classified.
