In this post we simulate tomorrow's day-ahead and real-time prices as a distribution for how the day could unfold. We optimized for risk adjusted returns across those scenarios to create a 1,000 MWh book of virtual bids for January 26, a scarcity day, and settled with $928k P&L. Running the same routine with a deterministic forecast of each market earned $264k. Everything below is 26 January, 2026; next week's post will run the same process for an entire month.
If you want to the trade simulator for yourself head over to our Virtual Trader, and make your own simulations in our OPF Studio ; send an email to info@distill.energy if you're an ERCOT market participant and we can set up a demo and trial.
An end-to-end flow from fundamentals to trades
As we've discussed in The Future is a Distribution and our Primer on Optimal Power Flow, Distill lets you simulate the power market according to what could happen, with the understanding that the future holds uncertainty. Here, we elaborate further by distinguishing between the day-ahead and the real-time auctions.
The day-ahead auction is a clearing problem: participants submit offer and bid curves, the market operator picks the cheapest feasible combination, and the resulting prices are as much about how people bid as about the physics. Real-time is closer to pure physics: whatever was scheduled meets the grid as it actually is, and price is set by what it costs to serve the next megawatt where it is needed. Feed each market its own inputs, simulate the power flow, and the two answers differ just like they do when ERCOT solves the models.
However, the future is uncertain: load might show up differently than forecast, units might trip, and wind might arrive early. The trading output is better when each market is solve many times over across a spread of plausible conditions, and every solve is a complete network simulation rather than a perturbation of an earlier answer. Then, what you feed into the trading module is a distribution of prices at every node and hour, and, more usefully, a distribution of the gap between the two markets.
That distribution is what the Virtual Trader module works from. It picks the nodes where the DART gap moves most in the simulations, decides which side of each to take, and sizes the position. The sizing also needs the distribution, because a wide spread of outcomes and a narrow one can share the same average but have very different exposure.The trading algorithm accepts three parameters that can help customize how the shape of the distribution impacts trades: K for how many nodes to look at, α for how much of the average return to trade off for protection against a tail event, and λ for how strongly to prefer many small positions over a few large ones. What comes out is a set of bids ready to submit: node, hour, side, price, megawatts.
How it works
Call OPF Studio for day-ahead and real-time simulations, and bring your own forecasts to augment them. We pull that through a robust optimization routine that finds the portfolio with the best risk-adjusted returns based on parameters you set. The more simulations you bring that explore the space of tomorrow’s possibility, the better your portfolio will end up.
Two models, one per market. The day-ahead model simulates tomorrow's auction; the real-time model simulates the physical grid actually running. This produces a distribution of how the day could go instead of a single guess.
Each hour, the optimizer chooses K nodes. It looks at the gap between the two forecasts measured across all of the scenarios to identify which nodes have the highest volatility for the day.
Across those nodes it places offers (sell day-ahead, buy back real-time) and bids (the reverse), choosing volumes and bid prices to maximize
expected profit − α × CVaR − λ × Σ volume²CVaR is the average loss over the worst 20% of scenarios; α prices protection against it. The last term is a penalty on the megawatts held at any one node-hour, making size progressively expensive, so λ decides how widely the book spreads beneath the hard 30 MW limit.
The book obeys ERCOT's rules — 0.1 MW increments, bids inside [−$250, $5,000], a 1,000 MWh daily allocation, 30 MW at any one node-hour — and settles against ERCOT's published day-ahead and real-time prices. The forecasts never saw them.
One guess or a distribution?
The only differences between the deterministic and probabilistic outcomes are the nodal prices. Both portfolios use the same optimizer and the same rules. For deterministic forecasts, the risk parameter α has no effect.
| K nodes/hour | Deterministicforecasts | Probabilisticforecasts | Probabilisticadvantage |
|---|---|---|---|
| 1 | −$5,422 | $679k | $685k |
| 3 | $119k | $982k | $863k |
| 5 | $264k | $928k | $664k |
| 10 | $406k | $941k | $535k |
| 20 | $790k | $1.00M | $210k |
At the default K=5, the probabilistic book settles $928k against $264k for the deterministic book.
A grid of user-defined parameters
There are five parameters to set
- The total size of the portfolio, here set to 1,000MWh
- The maximum volume per node-hour, defaulted to 30MW.
- The maximum number of nodes the book will trade each hour, K.
- Control over the average return the optimizer will trade away for protection against the bad tail, called α.
- The willingness to spread the book instead of putting large volumes on one node, call λ.
With these, here’s the settled P&L for all 100 combinations:
| K \ α | α = 0.0 | α = 0.5 | α = 1.0 | α = 2.0 | α = 5.0 |
|---|---|---|---|---|---|
| K = 1 | $604k | $604k | $1.13M | $1.13M | $1.18M |
| K = 3 | $868k | $868k | $930k | $926k | $926k |
| K = 5 | $831k | $922k | $926k | $937k | $948k |
| K = 10 | $693k | $714k | $776k | $977k | $1.24M |
| K = 20 | $1.03M | $1.01M | $1.00M | $1.03M | $1.01M |
Breadth pays: more nodes each hour puts more of the allocation to work. Risk aversion pays too, at nearly every setting, because α is guarding against real shifts in DA caught by the simulations. λ buys diversification by moving the median portfolio from 34 node-hours to 85. Best cell K=10, α=5.0, λ=0.0 at $1.24M
The day's forecasts against actuals
These figures show that our day-ahead simulations were more accurate than the real-time, but the uncertainty in the real-time was geographically correct. On scarcity days in particular, the stack is so sensitive that it is impossible to get a forecast right, but by modeling a distribution you don’t have to. Importantly, Distill’s nodal model got the geographic spread very close, which made a big difference in creating a diverse portfolio.
Day-ahead
Real-time
Forecast − settled
Uncertainty
Performance
The headline is the difference between probabilistic and deterministic outcomes. As seen above, the forecasts weren’t perfect, but by accounting for uncertainty we were able to put on a portfolio that cleared volume where it mattered in the morning ramp, and left most of the later day alone. Knowing when to trade, and how much, becomes a function of how certain you are that there is edge; instead of gut feel, you get clarity with numbers to back it.
Probabilistic forecast
Hour ending, market local time.
The book, in full
Note that even though the day was a short, the portfolio still put on (and made money on!) bids where it could across the grid.
| HE | Node | Side | Bid | MW | DA settled | RT settled | P&L |
|---|---|---|---|---|---|---|---|
| 1 | FOXTROT_ALL | OFF, not filled | $607.19 | 26.8 | $217.79 | $163.87 | $0 |
| 1 | FREC_2_CCU | BID, filled | $1,420.74 | 7.0 | $1,347.19 | $330.73 | −$7,115 |
| 1 | HOLCOMB_RN1 | OFF, not filled | $792.03 | 4.8 | $728.95 | $447.25 | $0 |
| 1 | OUTP_SLR_RN | OFF, not filled | $688.16 | 14.7 | $567.37 | $265.93 | $0 |
| 1 | PALACIOS_RN | BID, filled | $1,551.46 | 24.1 | $1,203.28 | $1,286.08 | $1,995 |
| 2 | DC_L | OFF, filled | $422.40 | 18.4 | $494.11 | $168.08 | $5,999 |
| 2 | FREC_2_CCU | BID, filled | $1,602.68 | 27.4 | $1,024.25 | $377.27 | −$17.7k |
| 2 | OUTP_SLR_RN | OFF, filled | $436.59 | 12.6 | $498.01 | $227.41 | $3,410 |
| 2 | PALACIOS_RN | BID, filled | $1,530.53 | 29.9 | $961.74 | $1,748.53 | $23.5k |
| 3 | FREC_2_CCU | BID, filled | $1,417.17 | 26.9 | $1,209.63 | $387.11 | −$22.1k |
| 3 | OUTP_SLR_RN | OFF, filled | $587.17 | 15.5 | $687.66 | $56.42 | $9,784 |
| 3 | PALACIOS_RN | BID, filled | $1,359.78 | 29.9 | $1,198.44 | $1,880.77 | $20.4k |
| 3 | STP_STP_G1 | OFF, filled | $588.46 | 23.7 | $703.89 | $191.28 | $12.1k |
| 4 | FOXTROT_ALL | OFF, not filled | $476.84 | 26.5 | $139.42 | $215.12 | $0 |
| 4 | FREC_2_CCU | BID, filled | $1,474.27 | 12.3 | $1,207.29 | $365.32 | −$10.4k |
| 4 | OUTP_SLR_RN | OFF, not filled | $563.05 | 15.3 | $528.87 | $79.34 | $0 |
| 4 | PALACIOS_RN | BID, filled | $1,425.97 | 29.9 | $1,243.26 | $1,863.41 | $18.5k |
| 5 | CITYVICT_ALL | OFF, not filled | $758.40 | 29.9 | $695.01 | $281.55 | $0 |
| 5 | FREC_2_CCU | BID, filled | $1,543.04 | 4.4 | $1,345.84 | $542.75 | −$3,534 |
| 5 | OUTP_SLR_RN | OFF, not filled | $927.78 | 25.6 | $667.19 | $109.15 | $0 |
| 5 | PALACIOS_RN | BID, not filled | $1,933.95 | 29.9 | $3,682.42 | $1,741.85 | $0 |
| 6 | DC_L | OFF, not filled | $1,286.57 | 29.9 | $1,242.67 | −$1.55 | $0 |
| 6 | HOLCOMB_RN1 | OFF, filled | $1,384.74 | 29.4 | $1,398.88 | $507.03 | $26.2k |
| 6 | OUTP_SLR_RN | OFF, not filled | $1,288.39 | 29.9 | $1,231.75 | $70.85 | $0 |
| 6 | PALACIOS_RN | BID, not filled | $2,276.33 | 29.9 | $6,706.73 | $1,664.28 | $0 |
| 7 | BOARDCRK_ALL | OFF, filled | $1,445.96 | 29.9 | $1,605.88 | $297.49 | $39.1k |
| 7 | CITYVICT_ALL | OFF, filled | $277.78 | 6.0 | $956.94 | $229.29 | $4,366 |
| 7 | FREC_2_CCU | OFF, filled | $1,600.13 | 19.6 | $1,613.36 | $374.68 | $24.3k |
| 7 | OUTP_SLR_RN | OFF, not filled | $1,024.57 | 29.9 | $742.10 | $76.69 | $0 |
| 7 | PALACIOS_RN | BID, not filled | $1,755.33 | 29.9 | $22,618.19 | $1,847.47 | $0 |
| 8 | CITYVICT_ALL | OFF, filled | $218.88 | 6.9 | $1,062.64 | $161.80 | $6,216 |
| 8 | DECKER_GT | OFF, filled | $1,761.25 | 29.9 | $2,102.16 | $566.74 | $45.9k |
| 8 | FREC_2_CCU | OFF, filled | $1,568.21 | 29.9 | $1,735.50 | $180.19 | $46.5k |
| 8 | OUTP_SLR_RN | OFF, not filled | $1,079.22 | 29.9 | $903.89 | $67.03 | $0 |
| 9 | CFLAT_ES_RN | OFF, filled | $810.12 | 25.6 | $977.95 | $204.24 | $19.8k |
| 9 | CITYVICT_ALL | OFF, filled | $401.62 | 20.5 | $1,415.54 | $110.01 | $26.8k |
| 9 | NRTN_SLR_RN | OFF, filled | $1,232.95 | 29.9 | $1,681.46 | $75.30 | $48k |
| 9 | PALACIOS_RN | OFF, filled | $1,110.37 | 29.9 | $18,015.25 | $269.85 | $531k |
| 9 | SANDHSYD1_2 | OFF, filled | $1,378.91 | 29.9 | $1,699.36 | $223.30 | $44.1k |
| 10 | BUDA_RN | OFF, filled | $539.75 | 10.2 | $754.97 | $109.90 | $6,580 |
| 10 | ERSL_RN | OFF, filled | $236.06 | 0.2 | $423.29 | $46.15 | $75 |
| 10 | MDANP_CT3_4 | OFF, filled | $316.60 | 0.1 | $466.75 | $123.51 | $34 |
| 11 | CFLAT_ES_RN | BID, filled | $144.36 | 2.4 | $133.26 | $10.43 | −$295 |
| 12 | CFLAT_ES_RN | BID, not filled | $116.53 | 4.1 | $120.77 | $1.40 | $0 |
| 13 | CFLAT_ES_RN | BID, not filled | $110.98 | 4.8 | $119.86 | $4.77 | $0 |
| 14 | CFLAT_ES_RN | BID, not filled | $79.60 | 3.6 | $104.51 | $0.11 | $0 |
| 15 | CFLAT_ES_RN | BID, not filled | $52.46 | 2.1 | $79.68 | −$0.66 | $0 |
| 16 | CFLAT_ES_RN | BID, not filled | $61.27 | 1.2 | $88.99 | −$1.71 | $0 |
| 19 | JUNCTION_RN | OFF, filled | $651.91 | 9.5 | $746.27 | $177.27 | $5,406 |
| 19 | SANDHSYD1_2 | OFF, not filled | $496.02 | 2.2 | $481.93 | $169.91 | $0 |
| 20 | SANDHSYD1_2 | OFF, filled | $475.80 | 1.5 | $480.75 | $154.72 | $489 |
| 21 | 7RNCHSLR_ALL | OFF, filled | $395.65 | 1.7 | $401.56 | $167.55 | $398 |
| 21 | HART_WND_RN | OFF, filled | $269.70 | 4.5 | $318.68 | −$45.40 | $1,638 |
| 21 | SANDHSYD1_2 | OFF, not filled | $543.25 | 6.3 | $531.13 | $163.14 | $0 |
| 22 | BOARDCRK_ALL | OFF, filled | $343.87 | 0.2 | $441.91 | $157.51 | $57 |
| 22 | HART_WND_RN | OFF, filled | $302.86 | 6.1 | $388.87 | −$35.36 | $2,588 |
| 22 | JUNCTION_RN | OFF, filled | $520.34 | 7.6 | $681.54 | $179.90 | $3,812 |
| 22 | SANDHSYD1_2 | OFF, filled | $512.63 | 6.0 | $591.87 | $170.28 | $2,530 |
| 23 | FAGUSSLR_RN | OFF, filled | $273.19 | 7.4 | $464.65 | $75.53 | $2,879 |
| 23 | RUSSEKST_RN | OFF, filled | $371.25 | 4.1 | $523.42 | $128.49 | $1,619 |
| 23 | SANDHSYD1_2 | OFF, filled | $384.08 | 4.2 | $558.94 | $119.14 | $1,847 |
| 23 | X443ESRN | OFF, filled | $330.49 | 3.1 | $517.07 | $122.71 | $1,223 |
| 24 | BUZI_SLR_RN | OFF, filled | $216.95 | 0.8 | $268.06 | $101.11 | $134 |
| 63 rows | 996.2 | $928k | |||||
Uncertainty to decisions
We show here how account for uncertainty can make a huge difference, even when the the forecast is good! Don’t forget you can test out our Virtual Trader (no paywall!) and run your own simulations in our OPF Studio. For the whole system end-to-end send an email to info@distill.energy if you're an ERCOT market participant and we can set up a demo and trial.