Transmission & Interconnections
This page documents the transmission and DC tie interconnection data products available through the ERCOT API.
DC Tie Flows
Report: NP6-626-CD
Method: get_dc_tie_flows()
Update Frequency: Hourly
Retention: 7-8 days via API
Actual hourly flows for ERCOT’s four DC interconnections with neighboring grids.
ERCOT’s DC Ties
ERCOT has four non-synchronous DC interconnections:
DC_N - North tie to SPP (Southwest Power Pool)
DC_E - East tie to Mexico (CFE)
DC_L - Laredo tie to Mexico (CFE)
DC_R - Railroad tie to Mexico (CFE)
Flow Convention:
Negative values = Imports into ERCOT
Positive values = Exports from ERCOT
Basic Usage
from datetime import datetime
from lib.iso.ercot import ERCOTClient, ERCOTConfig
config = ERCOTConfig.from_ini_file()
client = ERCOTClient(config)
# Get DC tie flows for a specific day
start_dt = datetime(2025, 8, 15, 0, 0, 0)
end_dt = datetime(2025, 8, 15, 23, 59, 59)
dc_flows = client.get_dc_tie_flows(
post_datetime_from=start_dt,
post_datetime_to=end_dt
)
# Analyze flows by tie
import pandas as pd
df = pd.DataFrame(dc_flows['data'])
print("\nDC Tie Flow Summary:")
by_tie = df.groupby('dcTieName')['powerFlow'].agg(['mean', 'min', 'max', 'sum'])
print(by_tie)
# Calculate net position
net_flow = df['powerFlow'].sum() / len(df)
if net_flow < 0:
print(f"\nERCOT was a NET IMPORTER: {abs(net_flow):,.1f} MW avg")
elif net_flow > 0:
print(f"\nERCOT was a NET EXPORTER: {net_flow:,.1f} MW avg")
else:
print("\nERCOT was BALANCED")
client.cleanup()
Data Fields:
postDatetime/operatingTime- Timestamp of measurementdcTieName- DC tie identifier (DC_N, DC_E, DC_L, DC_R)powerFlow- Power flow in MW (negative = import, positive = export)operatingDate- Operating dateoperatingHour- Operating hour
Advanced Analysis
# Analyze import/export patterns by time of day
df['hour'] = pd.to_datetime(df['operatingTime']).dt.hour
hourly_pattern = df.groupby('hour')['powerFlow'].mean()
print("\nAverage Flow by Hour:")
print(hourly_pattern.round(1))
# Find peak import/export hours
peak_import_hour = hourly_pattern.idxmin()
peak_export_hour = hourly_pattern.idxmax()
print(f"\nPeak Import Hour: {peak_import_hour}:00")
print(f" Avg Flow: {hourly_pattern[peak_import_hour]:,.1f} MW")
print(f"\nPeak Export Hour: {peak_export_hour}:00")
print(f" Avg Flow: {hourly_pattern[peak_export_hour]:,.1f} MW")
# Analyze by tie and direction
import_hours = df[df['powerFlow'] < 0].groupby('dcTieName')['powerFlow'].agg(['count', 'mean'])
export_hours = df[df['powerFlow'] > 0].groupby('dcTieName')['powerFlow'].agg(['count', 'mean'])
print("\nImports by Tie:")
print(import_hours)
print("\nExports by Tie:")
print(export_hours)
Use Cases:
Import/export pattern analysis
Grid interconnection studies
Cross-border energy flow tracking
Net interchange calculations
Regional market integration analysis
Dashboard: https://www.ercot.com/gridmktinfo/dashboards/dctieflows
Important Notes:
Real-time dashboard updates every 5 minutes
API data may have timing differences from dashboard
Only 7-8 days of data available via API
For historical data beyond 8 days, use EIA-930 API
—
SCED Binding Transmission Constraints
Report: NP6-86-CD
Method: get_sced_binding_transmission_constraints()
Update Frequency: Hourly (when constraints occur)
Retention: 7 days via API
Shadow prices and details for binding or violated transmission constraints in SCED, including when DC ties or interfaces hit their limits.
Understanding Shadow Prices
Shadow prices represent the marginal cost ($/MW) of relieving a transmission constraint. High shadow prices indicate:
Significant congestion on the constrained element
Large price separation across the constraint
High cost to deliver additional power through the constraint
A shadow price of $15/MW means that relieving the constraint by 1 MW would reduce total system costs by $15.
Basic Usage
from datetime import datetime
# Get binding constraints for a specific day
start_dt = datetime(2025, 8, 15, 0, 0, 0)
end_dt = datetime(2025, 8, 15, 23, 59, 59)
constraints = client.get_sced_binding_transmission_constraints(
sced_timestamp_from=start_dt,
sced_timestamp_to=end_dt
)
# Find most expensive constraints
df = pd.DataFrame(constraints['data'])
if not df.empty:
top_10 = df.nlargest(10, 'shadowPrice')[
['contingencyName', 'overloadedElementName', 'shadowPrice',
'elementFlow', 'elementLimit']
]
print("\nTop 10 Most Expensive Constraints:")
print(top_10)
print(f"\nTotal Constraint-Hours: {len(df)}")
print(f"Average Shadow Price: ${df['shadowPrice'].mean():,.2f}/MW")
print(f"Max Shadow Price: ${df['shadowPrice'].max():,.2f}/MW")
else:
print("No binding constraints during this period")
Data Fields:
scedTimestamp- SCED timestampcontingencyName- Contingency identifiercontingencyType- Type of contingencyoverloadedElementName- Name of constrained elementfromStation/toStation- Element endpointsvoltageLevel- Voltage levelshadowPrice- Shadow price in $/MWmaxShadowPrice- Maximum penalty priceelementLimit- Element capacity limit in MWelementFlow- Actual flow in MWconstraintType- Type of constraint
DC Tie Constraint Analysis
# Check if DC ties were constrained
dc_tie_constraints = df[
df['overloadedElementName'].str.contains('DC|TIE', case=False, na=False)
]
if not dc_tie_constraints.empty:
print(f"\n⚠️ Found {len(dc_tie_constraints)} DC tie constraint intervals")
print("\nDC Tie Constraints:")
for _, row in dc_tie_constraints.iterrows():
element = row['overloadedElementName']
shadow_price = row['shadowPrice']
flow = row['elementFlow']
limit = row['elementLimit']
overload_pct = ((flow - limit) / limit * 100) if limit > 0 else 0
print(f"\n {element}")
print(f" Shadow Price: ${shadow_price:,.2f}/MW")
print(f" Flow: {flow:,.1f} MW / Limit: {limit:,.1f} MW")
print(f" Overload: {overload_pct:.1f}%")
else:
print("\n✓ No DC tie constraints detected")
Congestion Pattern Analysis
# Analyze constraint frequency by element
constraint_freq = df['overloadedElementName'].value_counts().head(10)
print("\nMost Frequently Constrained Elements:")
print(constraint_freq)
# Calculate total congestion cost (approximate)
# Shadow price * (actual flow - limit) estimates the cost per interval
df['overload_MW'] = (df['elementFlow'] - df['elementLimit']).clip(lower=0)
df['congestion_cost'] = df['shadowPrice'] * df['overload_MW']
total_cost = df['congestion_cost'].sum()
print(f"\nEstimated Total Congestion Cost: ${total_cost:,.0f}")
# Analyze by time of day
df['hour'] = pd.to_datetime(df['scedTimestamp']).dt.hour
hourly_constraints = df.groupby('hour').size()
print("\nConstraint Count by Hour:")
print(hourly_constraints)
Use Cases:
Transmission congestion analysis
Identifying bottlenecks
DC tie limit monitoring
Interface constraint tracking
Congestion cost calculations
Transmission planning insights
—
Historical Data Beyond 7 Days
For DC tie flow data beyond the 7-8 day API window, use the EIA-930 API:
# EIA-930 provides hourly ERCOT interchange from July 2015-present
# Free public API (no authentication required)
# Dashboard: https://www.eia.gov/electricity/gridmonitor/
# Note: EIA-930 may aggregate ties differently than ERCOT's
# individual DC_N, DC_E, DC_L, DC_R breakdown
Consult your project’s EIA client for accessing historical interchange data.
—
CLI Usage
All transmission data products can be accessed via the command-line interface:
# DC tie flows (last 7 days available)
python isodart.py ercot transmission --trans-type dc_ties --start 2025-08-15 --duration 7
# Binding transmission constraints
python isodart.py ercot transmission --trans-type binding_constraints --start 2025-08-15 --duration 1
—
Example Scripts
See examples/ercot_transmission_analysis.py for a comprehensive example demonstrating:
DC tie flow pattern analysis
Net import/export calculations
Binding constraint identification
Congestion analysis
# Run all analyses
python examples/ercot_transmission_analysis.py --date 2025-08-15
# Run specific analysis
python examples/ercot_transmission_analysis.py --date 2025-08-15 --analysis ties
python examples/ercot_transmission_analysis.py --date 2025-08-15 --analysis constraints
—