Linear optimization · Market analysis

Optimizing hydro storage and electricity trading

The transmission system moves energy across space. Storage moves it through time. Linear programming (LP) models can optimize when and where to move energy based on market price and system constraints.

Approach

British Columbia and Uruguay have electricity systems anchored by large hydroelectric generation facilities. Both jurisdictions trade energy across their borders, creating opportunities for optimization. The key difference between regions is that Uruguay's system sets prices for sale into multiple markets, while British Columbia trades against spot prices in multiple markets.

We formulated a linear programming (LP) model in AMPL to represent a simplified hydroelectric system trading electricity into multiple neighboring markets. The model captures the essential characteristics of both systems, including storage capacity, generation limits, and market prices. For British Columbia, we compare model outputs for one reference year, FY2025 (April 2024 to March 2025), to published financial reporting to validate the model's accuracy and reliability. For Uruguay, we compare the 2023 and 2024 model outputs to published market price data. The same LP model is used for both jurisdictions, with different constraints and different input data.

Figure 1: Two modeled systems
AESOMid-CCAISOBritish ColumbiaAlbertaUnited StatesWECC Path 1WECC Path 354.0TWh

British Columbia FY2025 (April 2024 to March 2025)

UruguayArgentinaBrazil14.2TWh

Uruguay 2024

  • Hydro
  • Thermal
  • Other
  • Intertie

Results

The model performs relatively well across both jurisdictions as a simplified representation of the hydroelectric systems.

British Columbia. Monthly net exports across Mid-C, CAISO, and Alberta correlate at 0.582, but modeled trade volumes exceed actual trades (−9.1 TWh predicted against a province-wide −7.8 TWh). The monthly hydro shape lands within 0.79 percentage points of StatCan's. Price is where it is plainly beaten: it sells into the US at $58.32/MWh against BC's realised $85.52, and buys at $23.35 against $33.87. Three markets cannot reach most of the counterparties BC actually trades with, and the capture price is where that shows up.

Uruguay. The model hourly price tracks ADME's sanctioned spot at r = 0.853, averaging $90.88/MWh against $87.61, and monthly net interchange correlates at 0.829. The water value tracks ADME's own published one at r = 0.938, but sits $28.80/MWh under it on average.

FY2025 (April 2024 - March 2025)One aggregate reservoir for the BC Hydro system, trading into Mid-C, CAISO and Alberta.

Figure 01 — Trading margin

The model trades more, in both directions

Trade volumes by market (red) against BC’s reported trade (gray). Exports are up and imports are down. The model only trades against the three markets shown.

Net position: model −9,083 GWh against −7,838 reported

GWH — EXPORTS UP, IMPORTS DOWN−15,000−10,000−5,00005,000Mid-C / Pacific NorthwestCAISO / CaliforniaAlberta(interprovincial)Rest of the US(no model market)Mid-C / Pacific NorthwestModel exports3,951 GWhModel imports12,152 GWhReported exports3,267 GWhReported imports9,026 GWhNet, model−8,200 GWhNet, reported−5,759 GWhCAISO / CaliforniaModel exports3,569 GWhModel imports1,108 GWhReported exports1,595 GWhReported imports2,469 GWhNet, model+2,460 GWhNet, reported−874 GWhAlbertaModel exports1,579 GWhModel imports4,922 GWhReported exports239 GWhReported imports2,394 GWhNet, model−3,343 GWhNet, reported−2,156 GWhRest of the USModel exports—Model imports—Reported exports1,371 GWhReported imports420 GWhNet, model—Net, reported+951 GWhGWH — EXPORTS UP, IMPORTS DOWN−15,000−10,000−5,00005,000Mid-C / Pacific NorthwestCAISO / CaliforniaAlberta(interprovincial)Rest of the US(no model market)Mid-C / Pacific NorthwestModel exports3,951 GWhModel imports12,152 GWhReported exports3,267 GWhReported imports9,026 GWhNet, model−8,200 GWhNet, reported−5,759 GWhCAISO / CaliforniaModel exports3,569 GWhModel imports1,108 GWhReported exports1,595 GWhReported imports2,469 GWhNet, model+2,460 GWhNet, reported−874 GWhAlbertaModel exports1,579 GWhModel imports4,922 GWhReported exports239 GWhReported imports2,394 GWhNet, model−3,343 GWhNet, reported−2,156 GWhRest of the USModel exports—Model imports—Reported exports1,371 GWhReported imports420 GWhNet, model—Net, reported+951 GWh
Model exportsModel importsReported exportsReported imports

Net position: model −9,083 GWh against −7,838 reported

NET EXPORTS, GWH−10,000−7,500−5,000−2,50002,500Mid-C / Pacific NorthwestCAISO / CaliforniaAlberta(interprovincial)Rest of the US(no model market)Mid-C / Pacific NorthwestModel exports3,951 GWhModel imports12,152 GWhReported exports3,267 GWhReported imports9,026 GWhNet, model−8,200 GWhNet, reported−5,759 GWhCAISO / CaliforniaModel exports3,569 GWhModel imports1,108 GWhReported exports1,595 GWhReported imports2,469 GWhNet, model+2,460 GWhNet, reported−874 GWhAlbertaModel exports1,579 GWhModel imports4,922 GWhReported exports239 GWhReported imports2,394 GWhNet, model−3,343 GWhNet, reported−2,156 GWhRest of the USModel exports—Model imports—Reported exports1,371 GWhReported imports420 GWhNet, model—Net, reported+951 GWhNET EXPORTS, GWH−10,000−7,500−5,000−2,50002,500Mid-C / Pacific NorthwestCAISO / CaliforniaAlberta(interprovincial)Rest of the US(no model market)Mid-C / Pacific NorthwestModel exports3,951 GWhModel imports12,152 GWhReported exports3,267 GWhReported imports9,026 GWhNet, model−8,200 GWhNet, reported−5,759 GWhCAISO / CaliforniaModel exports3,569 GWhModel imports1,108 GWhReported exports1,595 GWhReported imports2,469 GWhNet, model+2,460 GWhNet, reported−874 GWhAlbertaModel exports1,579 GWhModel imports4,922 GWhReported exports239 GWhReported imports2,394 GWhNet, model−3,343 GWhNet, reported−2,156 GWhRest of the USModel exports—Model imports—Reported exports1,371 GWhReported imports420 GWhNet, model—Net, reported+951 GWh
Model netReported net

Figure 02 — Reservoir storage

The model fills and drains when the reservoirs do

Measured levels are metres and the model is TWh of energy; nothing public converts one to the other, so each series is normalised over its own range and only the timing compares. Williston tracks at r = 0.98.

0%25%50%75%100%Apr2024MayJunJulAugSepOctNovDecJan2025FebMar0%25%50%75%100%Apr2024JunAugOctDecJan2025Feb
0102030Apr2024MayJunJulAugSepOctNovDecJan2025FebMarSmax 25 TWh, assumedSmin 3 TWh, assumed0102030Apr2024JunAugOctDecJan2025FebSmax 25 TWh, assumedSmin 3 TWh, assumed

Figure 03 — Water value

The water value holds flat; the price wanders

The value of stored water — the shadow price of the storage balance — is one number all year, $41.61/MWh, while the Mid-C price moves day to day around it. A run that ends where it started and never touches a reservoir bound has nothing to reprice.

The water value is one number all year, $41.61. The Mid-C price moves $93.80 across the same days.

RESERVOIR STORAGE, TWHWATER VALUE AGAINST THE MID-C PRICE, $/MWH0102030−250255075100Apr2024MayJunJulAugSepOctNovDecJan2025FebMarfulloperating floorRESERVOIR STORAGE, TWHWATER VALUE VS PRICE, $/MWH0102030−250255075100Apr2024JunAugOctDecJan2025Febfulloperating floor

2023 · rolling 7-day windowThe Rio Negro cascade as one reservoir, trading into Brazil and Argentina.

Figure 01 — Trading margin

The model sells into Argentina where ADME did not

Volumes by interconnection against ADME’s own metered interchange. The model exported 968 GWh to Argentina against a reported 211: Argentine prices were high in the drought and the LP sold into them, while ADME’s mandate is supply security and not margin.

Net position: model −450 GWh against −1,159 reported

GWH — EXPORTS UP, IMPORTS DOWN−1,500−1,000−50005001,000Brazil(Melo + Rivera)ArgentinaBrazilModel exports11 GWhModel imports1,427 GWhReported exports17 GWhReported imports1,367 GWhNet, model−1,416 GWhNet, reported−1,350 GWhArgentinaModel exports968 GWhModel imports2 GWhReported exports211 GWhReported imports19 GWhNet, model+966 GWhNet, reported+192 GWhGWH — EXPORTS UP, IMPORTS DOWN−1,500−1,000−50005001,000Brazil(Melo + Rivera)ArgentinaBrazilModel exports11 GWhModel imports1,427 GWhReported exports17 GWhReported imports1,367 GWhNet, model−1,416 GWhNet, reported−1,350 GWhArgentinaModel exports968 GWhModel imports2 GWhReported exports211 GWhReported imports19 GWhNet, model+966 GWhNet, reported+192 GWh
Model exportsModel importsReported exportsReported imports

Net position: model −450 GWh against −1,159 reported

NET EXPORTS, GWH−1,500−1,000−50005001,000Brazil(Melo + Rivera)ArgentinaBrazilModel exports11 GWhModel imports1,427 GWhReported exports17 GWhReported imports1,367 GWhNet, model−1,416 GWhNet, reported−1,350 GWhArgentinaModel exports968 GWhModel imports2 GWhReported exports211 GWhReported imports19 GWhNet, model+966 GWhNet, reported+192 GWhNET EXPORTS, GWH−1,500−1,000−50005001,000Brazil(Melo + Rivera)ArgentinaBrazilModel exports11 GWhModel imports1,427 GWhReported exports17 GWhReported imports1,367 GWhNet, model−1,416 GWhNet, reported−1,350 GWhArgentinaModel exports968 GWhModel imports2 GWhReported exports211 GWhReported imports19 GWhNet, model+966 GWhNet, reported+192 GWh
Model netReported net

Figure 02 — Reservoir storage

The rolling run tracks the reservoir, not just its shape

Unlike British Columbia, the measured counterpart here is in the model’s own units — Bonete’s level converted to cascade energy — so the levels are comparable and not only the timing. The run follows the drought down at r = 0.94.

0%25%50%75%100%Jan2023FebMarAprMayJunJulAugSepOctNovDec0%25%50%75%100%Jan2023MarMayJulSepNov
0.00.51.01.52.02.5Jan2023FebMarAprMayJunJulAugSepOctNovDecSmax 1.861 TWh, assumedSmin 0 TWh, assumed0.00.51.01.52.02.5Jan2023MarMayJulSepNovSmax 1.861 TWh, assumedSmin 0 TWh, assumed

Figure 03 — Water value

The water value moves, because the reservoir does

The surface reprices storage every week rather than holding one number all year, so the water value runs from $-0 to $222/MWh against ADME’s sanctioned spot. It is the same dual as British Columbia’s, in a year where storage was actually scarce.

The water value moves $222.01 across the year. The adme spot moves $250.00, about 1 times as far.

RESERVOIR STORAGE, TWHWATER VALUE AGAINST THE ADME SPOT, $/MWH0.01.02.03.0−1000100200300Jan2023FebMarAprMayJunJulAugSepOctNovDecfulloperating floorRESERVOIR STORAGE, TWHWATER VALUE VS PRICE, $/MWH0.01.02.03.0−1000100200300Jan2023MarMayJulSepNovfulloperating floor

Methodology

The LP model is a stylized representation of hydro systems that trade into neighboring markets. Results are illustrative rather than predictive. The model objective is to maximize annual trading margin over 8,760 hourly periods. This is achieved by scheduling hydro generation, other generation, imports and exports, and storage levels while respecting physical and operational constraints. In total, the model has 78,840 variables, and a full year solves in 1.8 to 4.5 seconds across the five full-year runs behind this case study and its companions.

Model formulation

The model formulation is:

maximize TradingMargin:

−−−
−
−−−
+
+

Revenue and trading costs

Trading revenue: Exports sold and imports bought at each market's hourly price, which can be negative.

pm,t

Price at each market in each hour $/MWh parameter · price

Xm,t

Exports sold to each market MW variable · X

Ym,t

Imports bought from each market MW variable · Y

Revenue and trading costs

Wheeling cost: The all-in cost of scheduling to or from a market, paid on flows both ways.

wm

Wheeling cost to or from each market $/MWh parameter · wheel

Xm,t

Exports sold to each market MW variable · X

Ym,t

Imports bought from each market MW variable · Y

Revenue and trading costs

Offer-curve discount: Each deeper tranche of exports sells at a wider discount to the price.

δm,k

Discount on each tranche of the offer curve $/MWh parameter · disc

Xkm,k,t

Exports at each tranche of the offer curve MW variable · Xk

Revenue and trading costs

Bid-curve premium: Each deeper tranche of imports costs a higher premium over the price.

βm,b

Premium on each tranche of the bid curve $/MWh parameter · bid_prem

Ykm,b,t

Imports at each tranche of the bid curve MW variable · Yk

Operating costs and penalties

Shortfall penalty: A penalty on each MWh the run ends below its storage target.

πshort

Penalty per MWh of storage shortfall $/MWh parameter · short_penalty

Short

Energy the run ends below its storage target MWh variable · Short

Operating costs and penalties

Thermal running cost: The running cost of each thermal unit's output.

cu

Running cost of each thermal unit $/MWh parameter · th_cost

Thu,t

Thermal generation, by unit MW variable · Th

Operating costs and penalties

Reserve penalty: A penalty on each MWh of the deepest draw below the reserve floor.

πreserve

Penalty per MWh of the deepest reserve draw $/MWh parameter · reserve_penalty

Below

The deepest draw below the reserve floor, across all hours MWh variable · Below

Operating costs and penalties

Spill tie-breaker: A token cost on water released without generating, so that storing it wins a tie with spilling it.

cspill

Token cost on water released without generating $/MWh parameter · spill_cost

Spillt

Water released without generating MWh/h variable · Spill

Terminal value

Terminal value, curve: The water left at the end, valued on a concave curve of final storage.

Tv

Value of the water left at the end $ variable · Tv

Terminal value

Terminal value, flat: Or valued at a flat rate per MWh. A run uses one terminal value or neither, never both; full-year runs use neither and hold the storage target instead.

v

Flat water value $/MWh parameter · wv

SN

Storage at the end of the last hour MWh variable · S

Revenue and trading costs

4 terms: What the schedule earns at market, less what moving it there costs.

Operating costs and penalties

4 terms: Fuel, and the soft limits a run may buy its way past.

Terminal value

2 terms: What the water left in storage is worth when the run stops.

Indices: m market, t hour from 1 to N, k and b tranches of the offer and bid curves, u thermal unit. A term is zero in any case that supplies no data for it; the constraints below show which cases do.
Learn more about the model variables, constraints, and assumptions

Model Variables

The model includes 78840 variables to represent the electric system and trading environment across two jurisdictions.

Every hour

Gt
Hydro generation MWFrom the must-run minimum to capacity
St
Storage at the end of the hour MWhBetween the reservoir floor and ceiling
Spillt
Water released without generating MWh/hUp to the spill limit, where a case sets one
Xm,t
Exports sold to each market MWUp to that market's export limit
Ym,t
Imports bought from each market MWUp to that market's import limit
Xkm,k,t
Exports at each tranche of the offer curve MWUp to the tranche's depth
Ykm,b,t
Imports at each tranche of the bid curve MWUp to the tranche's depth
Thu,t
Thermal generation, by unit MWUp to the unit's capacity
Curtailt
Must-run energy curtailed rather than generated MWUp to that hour's must-run surplus

Once per run

Short
Energy the run ends below its storage target MWhUp to the target itself
Below
The deepest draw below the reserve floor, across all hours MWhUp to the reserve itself
Tv
Value of the water left at the end $No more than the lowest cut at final storage, and zero when a run has no cuts

Constraints

Model constraints define the feasible solution space the model can solve for. Our model includes 12 constraints to represent the electric system and trading environment across two jurisdictions.

Constraints

All model runs: British Columbia and Uruguay

Storage balance

Water carried hour to hour: storage plus inflow, less generation and spill. Its shadow price is the value of stored energy — the number the model exists to produce.

In the model

subject to StorageBalance {t in T}:
    S[t] = (if t = 1 then S0 else S[t-1]) + inflow[t] - G[t] - Spill[t];
Nature
Physical
If pushed past
Hard — always holds
Shadow price
Value of stored energy

All model runs: British Columbia and Uruguay

Energy balance

Hydro and thermal generation, must-run supply net of curtailment, and imports meet load plus exports in every hour. Its shadow price is the system marginal price. In British Columbia only the hydro and trade terms are non-zero.

In the model

subject to EnergyBalance {t in T}:
    G[t] + sum {u in U} Th[u,t] + surplus[t] - Curtail[t]
      + sum {m in M} Y[m,t] = load[t] + sum {m in M} X[m,t];
Nature
Physical
If pushed past
Hard — always holds
Shadow price
System marginal price

All model runs: British Columbia and Uruguay

Shared path limits

Markets that ride the same physical intertie compete for it. In British Columbia 3 markets share 2 paths, so the California and Mid-C schedules are not independent.

In the model

subject to PathExport {p in P, t in T}:
    sum {m in M: path_of[m] = p} X[m,t] <= path_exp_cap[p];
subject to PathImport {p in P, t in T}:
    sum {m in M: path_of[m] = p} Y[m,t] <= path_imp_cap[p];
Nature
Physical
If pushed past
Hard — always holds

All model runs: British Columbia and Uruguay

Ramp limits

Output cannot move more than a set amount from one hour to the next — 2,500 MW in British Columbia — which is what stops the schedule chasing every price spike. A rolling run ramps its first hour from the last hour it actually committed, so windows join without a jump.

In the model

subject to RampUp {t in T: t > 1 or has_prev = 1}:
    G[t] - (if t = 1 then G_prev else G[t-1]) <= ramp_max;
subject to RampDown {t in T: t > 1 or has_prev = 1}:
    (if t = 1 then G_prev else G[t-1]) - G[t] <= ramp_max;
Nature
Operating
If pushed past
Hard — always holds

All model runs: British Columbia and Uruguay

End-of-horizon storage

The run must finish with at least a target volume in storage. Without it the model empties the reservoir into the last high-price hours and books the proceeds. Falling short is allowed at a penalty per MWh, so a dry year finishes low rather than making the problem infeasible.

In the model

var Short >= 0, <= S_end_min;
subject to EndStorage:
    S[N] + Short >= S_end_min;
Nature
Planning target
If pushed past
Soft — penalised per MWh short

Uruguay

Reserve floor

Storage is held above an operating reserve — Rincón del Bonete kept above a set level over its physical floor. It is a policy assumption, not a physical limit, and it can be breached: the deepest draw into it is penalised per MWh.

In the model

var Below >= 0, <= reserve;
subject to ReserveFloor {t in T}:
    S[t] + Below >= Smin + reserve;
Nature
Policy assumption
If pushed past
Soft — deepest draw penalised per MWh

Uruguay

Must-run and curtailment

Salto Grande, wind, solar and biomass generate whether or not they are wanted. When they exceed domestic demand the excess is exported or curtailed, and the model may curtail no more than that excess.

In the model

var Curtail {t in T} >= 0, <= surplus[t];
Nature
Physical
If pushed past
Hard — always holds

Uruguay

Thermal dispatch

Thermal plant comes in blocks, each with its own capacity and cost, so fuel is burned only when it is cheaper than the water or the import it replaces.

In the model

var Th {u in U, T} >= 0, <= th_cap[u];
Nature
Physical
If pushed past
Hard — always holds

Uruguay

Offer and bid curves

Exports are sold down an offer curve and imports bought up a bid curve: each further tranche earns less or costs more. It relaxes the price-taker assumption — selling more lowers what the next MWh fetches.

In the model

subject to OfferLink {m in M, t in T: card(K) > 0}:
    X[m,t] = sum {k in K} Xk[m,k,t];
subject to BidLink {m in M, t in T: card(KB) > 0}:
    Y[m,t] = sum {kb in KB} Yk[m,kb,t];
Nature
Market assumption
If pushed past
Hard — always holds

Uruguay

Transit limit

Imports may not exceed domestic load in any hour. It is a stated assumption — the interties serve Uruguay, not a corridor between Brazil and Argentina — and deliberately not fitted to observed flows. Lifted, the difference is what free wheeling between the two neighbours would be worth, which is not a hydro trading result.

In the model

subject to TransitLimit {t in T}:
    sum {m in M} Y[m,t] - load[t] <= transit_cap;
Nature
Stated assumption
If pushed past
Hard — always holds

Uruguay

Spill limit

Water released without generating is capped at the largest spill the cascade has actually passed, with headroom. Spill also carries a token cost — a tie-breaker, not an economic cost — so storing beats dumping when water is otherwise free.

In the model

var Spill {T} >= 0, <= spill_max;
Nature
Physical
If pushed past
Hard — always holds

Rolling-horizon runs

Terminal water value

Water left at the end of each window is valued on a concave curve of storage, built from tangent lines, so a short window neither hoards water nor dumps it to book a quick sale.

In the model

var Tv <= (if card(C) > 0 then Infinity else 0);
subject to CutCurve {c in C}:
    Tv <= cut_slope[c] * S[N] + cut_int[c];
Nature
Valuation
If pushed past
Not a limit — prices the water left

Assumptions

The LP model is a demonstration only, not a full representation of the system. It reduces dimensionality by aggregating all the hydro plants into a single reservoir, and it ignores environmental flow constraints, head effects, and river routing.

Key assumptions of the model include:

  • The trading of gas, environmental attributes, and other commodities are excluded.
  • Only the markets modelled for a system exist. Where it actually trades beyond them, that energy has nowhere to go, which pulls the modelled capture price below the realized one.
  • Must-take supply — independent power, wind, solar, biomass, and treaty exchanges — is netted off load rather than dispatched. The model absorbs it and cannot move it.
  • Domestic load is inelastic: served in every hour, and never shed.
  • Trade is limited only by the rating of each path. There are no scheduling rules, transmission products, counterparty or credit limits, and no distinction between day-ahead and real time, so buying and selling in the same hour costs only the wheeling charge.
  • Losses are carried entirely by that flat wheeling charge, and no reserve, ancillary-service or capacity obligation applies beyond the storage floor.
  • Every hour is alike: no unit commitment, no start costs, no outages or maintenance, and nothing below hourly resolution.
  • British Columbia's storage plants are aggregated into a single reservoir, and its walls — a ceiling of 25 TWh and a floor of 3 TWh — are illustrative rather than published capacities. Neither is reached: the reference year turns between 6.8 and 20.8 TWh, so the bounds decide nothing and the storage target does.
  • Intertie ratings, wheeling charges and the 3,000 MW minimum generation floor are likewise illustrative parameters rather than filed ratings or tariffs. The floor moves the answer more than any other assumed parameter, and it is the one with no source behind it.
  • Storage is fixed at both ends of a run, so the reservoir path follows from that target rather than predicting it.
  • Where inflow is not published it is backed out of the storage balance, which makes it net of evaporation and seepage, and flat within each day.

Data sources

The model uses published data as inputs and to verify model outputs, using synthetic data only where necessary. A full list of data sources can be found at the link below. Assumed parameters are labelled as assumptions and are never fitted to the series used to validate. Currencies are converted to USD for consistency.

British Columbia. Key data sources include: BC Hydro hourly load, total energy production, observed water levels, and electricity spot prices in Mid-C, CAISO, and AESO. The within-year inflow shape is synthetic, and its reservoir bounds, intertie ratings, wheeling charges, and 3,000 MW generation floor are illustrative parameters rather than measurements.

Uruguay. Key data sources include: ADME hourly generation, demand, interchange, water levels, and the marginal cost of operation in Brazil and Argentina. Inflow is back-calculated from observed levels, generation, and spill.

Expand the list of references and data sources

Hourly market data

  • [1]

    CAISO OASIS — Malin 500 kV node MALIN_5_N101, day-ahead

    The hourly California price. OASIS keeps only a rolling window, so the archive here cannot be re-fetched.

  • [2]

    CAISO OASIS — BPA EIM aggregation point ELAP_BPAT-APND, real-time

    The Mid-Columbia price, and the model's largest market.

  • [3]

    AESO public pool price API

    The hourly Alberta price, published in Canadian dollars.

  • [4]

    BC Hydro balancing authority hourly load report

    The hourly load shape, rescaled to BC Hydro's own integrated system.

Published accounts

  • [5]

    BC Hydro: Annual Report 2025/26

    Every annual energy figure the build uses, FY2022 to FY2026, and hydro generation and capacity plant by plant.

  • [6]

    BC Hydro: F2026–F2027 Revenue Requirements Application

    Appendix F Attachment 1, Schedule 4.0 gives system trade at transfer prices, a cross-check on the annual report. Appendix A gives Powerex trade income by year, as a comparator only.

  • [7]

    BC Hydro: Service Plan 2026/27 to 2028/29

    BC Hydro's own exchange-rate and Mid-Columbia forecast assumptions.

  • [8]

    BC Hydro: IPP Supply Lists

    Splits independent power into run-of-river and everything else.

Currency

  • [9]

    Bank of Canada Valet, series FXUSDCAD

    Converts the Alberta pool price to US dollars, day by day. Every price the model sees is in US dollars.

Monthly yardstick (scoring only)

  • [10]

    Statistics Canada tables 25-10-0015-01 and 25-10-0016-01

    Monthly generation by type and producer class, and monthly receipts, deliveries and availability: the hydro shape test, and the interprovincial and US flows.

  • [11]

    Canada Energy Regulator, monthly electricity exports and imports

    The only public monthly value of British Columbia's exports.

ADME, the system operator

  • [12]

    ADME datos abiertos

    Hourly generation, demand and interchange; Río Negro plant telemetry, which gives storage, generation and inflow; thermal output plant by plant; declared plant costs; the sanctioned spot price every validation scores against; ADME's own water value; and Salto Grande flows.

  • [13]

    ADME procedures — P004 on export offers, and Liquidación SPOT y Facturación

    Why a neighbour's price is treated as a ceiling rather than a market, and the basis for the reported price cap. Followed, not fetched.

Neighbouring markets

  • [14]

    ONS open data, CMO semi-horário, southern submarket — one file a year

    Brazil's marginal cost of operation, which is the ceiling on an export offer.

  • [15]

    CAMMESA, Costos Marginales Horarios Operados

    Argentina's hourly marginal cost, served one day to a request.

Currency

  • [16]

    Banco Central do Brasil, SGS series 1 — PTAX sell

    Brazilian reais to US dollars, at the daily rate rather than an annual average.

  • [17]

    BCRA, Comunicación A 3500 wholesale reference

    Argentine pesos to US dollars.

  • [18]

    Banco Central del Uruguay, interbank reference

    Uruguayan pesos to US dollars.

Model Improvements

  • Higher resolution of reservoir inflow and dispatch within the energy system

    The model includes no cascade, no head effect, no river routing, and no environmental flow constraints beyond a flat minimum. Real systems are a network of reservoirs with local conditions that bind at different times.

  • Gross-flow path limits

    Counter-flows are not netted and losses are not modelled, so the interties are treated more strictly than they behave.

More information

The code behind this case study — the model formulation in AMPL, the Python wrappers that build its inputs and iterate it, and the results of the runs reported here — is on GitHub.

Let's connect if you want to discuss how LP can be applied to your own optimization problems.