System Operations
This page documents the system operations and market data products available through the ERCOT API.
Actual System Lambda
Report: NP6-905-CD
Method: get_actual_system_lambda()
Update Frequency: Every 5 minutes (SCED)
System lambda represents the marginal cost of serving the next MW of load in the ERCOT system.
Understanding System Lambda
System lambda is the system-wide energy price component that reflects:
The marginal cost of the next MW of generation
Operating reserve scarcity conditions
The Operating Reserve Demand Curve (ORDC) adder
High lambda values indicate:
Tight supply conditions
Scarcity pricing in effect
Potential need for demand response
High Operating Reserve Demand Curve (ORDC) adders
Typical ranges:
Normal operations: $20-50/MWh
Tight conditions: $100-500/MWh
Scarcity pricing: >$1,000/MWh
Emergency conditions: >$5,000/MWh (approaching cap of $9,000/MWh)
Basic Usage
from datetime import datetime
from lib.iso.ercot import ERCOTClient, ERCOTConfig
config = ERCOTConfig.from_ini_file()
client = ERCOTClient(config)
# Get system lambda for a specific day
start_dt = datetime(2025, 8, 15, 0, 0, 0)
end_dt = datetime(2025, 8, 15, 23, 59, 59)
lambda_data = client.get_actual_system_lambda(
sced_timestamp_from=start_dt,
sced_timestamp_to=end_dt
)
# Analyze lambda values
import pandas as pd
df = pd.DataFrame(lambda_data['data'])
print("\nSystem Lambda Statistics:")
print(f" Peak: ${df['systemLambda'].max():>10,.2f}/MWh")
print(f" Average: ${df['systemLambda'].mean():>10,.2f}/MWh")
print(f" Minimum: ${df['systemLambda'].min():>10,.2f}/MWh")
client.cleanup()
Data Fields:
scedTimestamp- SCED timestamp (5-minute intervals)systemLambda- System lambda in $/MWhordcAdder- Operating Reserve Demand Curve adder in $/MWh (if available)
Scarcity Pricing Analysis
# Identify scarcity periods
high_scarcity = df[df['systemLambda'] > 1000]
extreme_scarcity = df[df['systemLambda'] > 5000]
total_intervals = len(df)
print(f"\nScarcity Periods:")
print(f" High (>$1000/MWh): {len(high_scarcity):>4} intervals ({len(high_scarcity)/total_intervals*100:.1f}%)")
print(f" Extreme (>$5000/MWh): {len(extreme_scarcity):>4} intervals ({len(extreme_scarcity)/total_intervals*100:.1f}%)")
if not high_scarcity.empty:
print("\nHigh Scarcity Events:")
for _, row in high_scarcity.head(10).iterrows():
timestamp = row['scedTimestamp']
lambda_val = row['systemLambda']
print(f" {timestamp}: ${lambda_val:,.2f}/MWh")
Time-of-Day Patterns
# Analyze lambda by time of day
df['timestamp'] = pd.to_datetime(df['scedTimestamp'])
df['hour'] = df['timestamp'].dt.hour
hourly_avg = df.groupby('hour')['systemLambda'].agg(['mean', 'min', 'max'])
print("\nAverage System Lambda by Hour:")
print(hourly_avg.round(2))
# Find peak price hours
peak_hour = hourly_avg['mean'].idxmax()
off_peak_hour = hourly_avg['mean'].idxmin()
print(f"\nPeak Hour: {peak_hour}:00 (${hourly_avg.loc[peak_hour, 'mean']:.2f}/MWh avg)")
print(f"Off-Peak Hour: {off_peak_hour}:00 (${hourly_avg.loc[off_peak_hour, 'mean']:.2f}/MWh avg)")
Use Cases:
Real-time market monitoring
Scarcity pricing analysis
Energy trading decisions
Grid reliability assessment
Operating reserve evaluation
Demand response trigger identification
—
60-Day DAM Settlement Point Prices
Report: NP4-188-CD
Method: get_dam_60day_settlement_point_price()
Update Frequency: Daily (after DAM clearing)
Retention: Rolling 60-day window
Historical Day-Ahead Market settlement point prices with a 60-day rolling window.
Basic Usage
from datetime import date
# Get DAM settlement point prices for a specific hub
spp_60d = client.get_dam_60day_settlement_point_price(
delivery_date_from=date(2025, 7, 1),
delivery_date_to=date(2025, 8, 31),
settlement_point="HB_HOUSTON"
)
# Calculate statistics
df = pd.DataFrame(spp_60d['data'])
print(f"\nHB_HOUSTON DAM Price Statistics:")
print(f" Average: ${df['price'].mean():,.2f}/MWh")
print(f" Median: ${df['price'].median():,.2f}/MWh")
print(f" Peak: ${df['price'].max():,.2f}/MWh")
print(f" Minimum: ${df['price'].min():,.2f}/MWh")
print(f" Std Dev: ${df['price'].std():,.2f}/MWh")
Data Fields:
deliveryDate- Date of deliveryhourEnding- Hour ending (1-24)settlementPoint- Settlement point namesettlementPointType- Type (Hub, Load Zone, Resource Node)price- Settlement point price in $/MWh
Common Settlement Points
Hubs:
HB_HOUSTON- Houston hubHB_NORTH- North hubHB_SOUTH- South hubHB_WEST- West hubHB_BUSAVG- Bus average
Load Zones:
LZ_HOUSTON- Houston load zoneLZ_NORTH- North load zoneLZ_SOUTH- South load zoneLZ_WEST- West load zoneLZ_SOUTH_HOUSTON- South HoustonLZ_AEN- AEN load zoneLZ_CPS- CPS load zoneLZ_LCRA- LCRA load zone
Price Trend Analysis
# Compare prices across multiple hubs
hubs = ["HB_HOUSTON", "HB_NORTH", "HB_SOUTH", "HB_WEST"]
hub_prices = {}
for hub in hubs:
data = client.get_dam_60day_settlement_point_price(
delivery_date_from=date(2025, 8, 1),
delivery_date_to=date(2025, 8, 31),
settlement_point=hub
)
df = pd.DataFrame(data['data'])
hub_prices[hub] = df['price'].mean()
print("\nAverage DAM Prices by Hub (August 2025):")
for hub, avg_price in sorted(hub_prices.items(), key=lambda x: x[1], reverse=True):
print(f" {hub:<15} ${avg_price:>7,.2f}/MWh")
Peak vs Off-Peak Analysis
# Define peak hours (HE 7-22 on weekdays)
df['hour'] = df['hourEnding']
df['date'] = pd.to_datetime(df['deliveryDate'])
df['dayofweek'] = df['date'].dt.dayofweek # Monday=0, Sunday=6
# Identify peak hours
df['is_peak'] = (
(df['dayofweek'] < 5) & # Weekday
(df['hour'] >= 7) & # Hour 7 or later
(df['hour'] <= 22) # Hour 22 or earlier
)
peak_price = df[df['is_peak']]['price'].mean()
off_peak_price = df[~df['is_peak']]['price'].mean()
print(f"\nPeak Hours (Weekdays HE 7-22): ${peak_price:,.2f}/MWh")
print(f"Off-Peak Hours: ${off_peak_price:,.2f}/MWh")
print(f"Peak Premium: ${peak_price - off_peak_price:,.2f}/MWh ({(peak_price/off_peak_price - 1)*100:.1f}%)")
Volatility Analysis
# Calculate daily volatility
daily_stats = df.groupby('deliveryDate')['price'].agg(['mean', 'std', 'min', 'max'])
daily_stats['range'] = daily_stats['max'] - daily_stats['min']
print("\nDaily Price Volatility:")
print(f" Average Daily Range: ${daily_stats['range'].mean():,.2f}/MWh")
print(f" Max Daily Range: ${daily_stats['range'].max():,.2f}/MWh")
print(f" Average Std Dev: ${daily_stats['std'].mean():,.2f}/MWh")
# Find most volatile days
most_volatile = daily_stats.nlargest(5, 'range')
print("\nMost Volatile Days:")
print(most_volatile[['mean', 'min', 'max', 'range']].round(2))
Use Cases:
Historical price analysis
Price forecasting
Market trend identification
Financial settlement validation
Load serving entity (LSE) planning
Hedging strategy development
—
CLI Usage
All system operations data products can be accessed via the command-line interface:
# System lambda (scarcity pricing)
python isodart.py ercot system-operations --ops-type lambda --start 2025-08-15 --duration 1
# Load vs forecast
python isodart.py ercot system-operations --ops-type load_vs_forecast --start 2025-08-01 --duration 7
# 60-day DAM prices for a specific settlement point
python isodart.py ercot system-operations --ops-type dam_60d_prices --start 2025-07-01 --duration 60 --settlement-point HB_HOUSTON
—
Example Scripts
See examples/ercot_generation_analysis.py for scarcity pricing analysis examples:
# Run scarcity analysis
python examples/ercot_generation_analysis.py --date 2025-08-15 --analysis scarcity
—