Across 28 days in February the virtuals optimizer earned $364k trading against distributions of DA and RT. Using a point forecast of the mean, everything else identical, it earned $39.8k. Nine tenths of the profit comes from accounting for uncertainty, not from the forecast being right.
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.
Why we simulate
In a world where collateral is infinite, risk is irrelevant. If we can make $10M in one year without regard to drawdowns, then we should always take the trade, unless there is an alternative by which we can expect to make more than $10M. Uncertainty (i.e., risk) is relevant when drawdowns and path-dependence are important. Our $10M year may never materialize if we lose $5M in the first week, and in fact we may actually prefer an $8M year if it comes with more manageable drawdowns.
Every firm has different tolerance and preferences, and optimizing towards those preferences requires understanding what's possible from the market; in particular, it means running simulations of the future instead of relying on dubious deterministic forecasts.
Using Distill's API, we perturb inputs such as CC turbine bid curves, financial market offers, battery bids for the DA solve; and load, renewable supply, and self-dispatch prices in the RT. These fundamentals are pushed through our powerflow simulator to come up with sample prices. We run 100 such perturbations for each day.
Cumulative P&L at the base configuration
The two runs separate almost immediately and never re-converge. The deterministic line is not losing money — it is simply flat, capturing a small fraction of the same opportunity set.
Daily P&L
The stochastic run wins on 22 of 28 days. Its edge is concentrated: February 8 alone contributes $72.9k, a day on which the deterministic baseline loses $2.4k.
Where a day's profit accumulates
The trader identifies where there is variability and uncertainty in the nodes so that it doesn't bias towards bids or offers. These three days have completely different bidding profiles and made their money in different ways.
The month's strongest day, $72.9k. Bids earn all of it in two windows, overnight and evening; offers barely leave zero.
$17.1k, of which offers earn $16.5k.
$29.5k split almost exactly in half — offers $14.7k, bids $14.8k. Both sides spend the day near zero and land in the last hour.
One knob at a time
Each knob is varied one at a time from the base configuration:
- K=5 nodes selected per hour
- CVaR weight α=1.0, volume penalty λ=0
- CVaR tail 0.95
- 1,000 MWh a day
- 30 MW cap per node-hour.
Every configuration is solved against the same simulated prices for a given day, so differences between rows are due solely to differences in the parameter. Each is solved twice: once against the DA and RT distributions, once against a point forecast of their per-node-hour mean.
All four panels share a vertical scale, and in this instance they show the following: two of our knobs impact the result and two do not.
Panels share a common vertical scale from $0 to $600k. Parameter values are evenly spaced by rank, not by magnitude.
In February, penalizing volume hurts performance
Increasing the volume penalty from 0 to 100 takes realized P&L from $364k to $24.5k — a fifteen-fold destruction, and by far the largest effect any parameter has.
K rises monotonically
Widening selection from K=1 to K=50 takes the result from $184k to $570k, with no maximum inside the grid. In February it paid to trade across more nodes.
Both CVaR knobs have low impact
The CVaR1 weight moves the stochastic result from $380k to $355k across its full range, and the tail probability from $371k to $351k. Both are within the day-to-day noise of a 28-day sample.
Garbage in, garbage out
Everything above depends on the distributions describing the day being traded. To show how much, the month was re-solved with the forecasts shuffled: each day still settles against the prices ERCOT printed, but is handed the DA distribution from another day and the RT distribution from another day again. No day sees either of its own forecasts. Same optimizer, same configuration, same allocation; the only thing changed is whether the distributions belong to the day.
The same machinery that earns $364k on matched distributions loses $20.8k on shuffled ones.
The portfolio is worthless if the distributions are mis-specified. Shuffled, the optimizer wins on 16 of 28 days, and its worst day is −$30.3k against −$7.4k when the forecasts are right. Its prices also stop finding the market: the clearing rate falls from 61.3% to 34.7%, because it is bidding around a price level drawn from the wrong day.
Given garbage, the optimizer does not hedge or abstain. Instead, it finds wider spreads in the noise and bids harder into them. It is very important to be confident in the distributions provided to the optimizer, nothing downstream of a bad distribution will tell you it's bad until your trades clear.
Footnotes
1. CVaR is the average of your worst outcomes, rather than the worst single one. The tail setting says which outcomes count as the worst: at 0.95, CVaR is the average result across the worst 5% of cases. The weight says how much that average matters next to ordinary profit — turn it up and the optimizer avoids positions that usually pay but occasionally lose badly, accepting lower typical profit to do it. ↩