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 $/MWh

  • ordcAdder - 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 delivery

  • hourEnding - Hour ending (1-24)

  • settlementPoint - Settlement point name

  • settlementPointType - Type (Hub, Load Zone, Resource Node)

  • price - Settlement point price in $/MWh

Common Settlement Points

Hubs:

  • HB_HOUSTON - Houston hub

  • HB_NORTH - North hub

  • HB_SOUTH - South hub

  • HB_WEST - West hub

  • HB_BUSAVG - Bus average

Load Zones:

  • LZ_HOUSTON - Houston load zone

  • LZ_NORTH - North load zone

  • LZ_SOUTH - South load zone

  • LZ_WEST - West load zone

  • LZ_SOUTH_HOUSTON - South Houston

  • LZ_AEN - AEN load zone

  • LZ_CPS - CPS load zone

  • LZ_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

—