Python API Guide

Overview

This guide covers using ISO-DART programmatically from Python scripts and applications.

Installation

# Option 1: Use as a library (recommended)
import sys
sys.path.append('/path/to/ISO-DART')

from lib.iso.caiso import CAISOClient, Market
from lib.iso.miso import MISOClient, MISOConfig
# ... etc

# Option 2: Install as package (future)
# pip install isodart

Basic Usage Pattern

All ISO clients follow a similar pattern:

from datetime import date

# 1. Import the client
from lib.iso.caiso import CAISOClient, Market

# 2. Create client instance
client = CAISOClient()

# 3. Download data
success = client.get_lmp(
    market=Market.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# 4. Clean up
client.cleanup()

CAISO Client

Basic LMP Download

from datetime import date
from lib.iso.caiso import CAISOClient, Market

# Initialize client
client = CAISOClient()

# Download Day-Ahead LMP
client.get_lmp(
    market=Market.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# Download Real-Time LMP
client.get_lmp(
    market=Market.RTM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 7)
)

client.cleanup()

Available Markets

from lib.iso.caiso import Market

Market.DAM      # Day-Ahead Market
Market.HASP     # Hour-Ahead Scheduling Process
Market.RTM      # Real-Time Market
Market.RTPD     # Real-Time Pre-Dispatch
Market.RUC      # Residual Unit Commitment
Market.TWO_DA   # Two Day-Ahead
Market.SEVEN_DA # Seven Day-Ahead

Load Forecasts

# Day-Ahead forecast
client.get_load_forecast(
    market=Market.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# 7-Day forecast
client.get_load_forecast(
    market=Market.SEVEN_DA,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

Renewable Generation

# Wind and solar summary
client.get_wind_solar_summary(
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

Ancillary Services

# AS prices
client.get_ancillary_services_prices(
    market=Market.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# AS requirements
client.get_ancillary_services_requirements(
    market=Market.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31),
    anc_type='ALL',  # or 'RU', 'RD', 'SR', 'NR'
    anc_region='ALL'
)

Custom Configuration

from pathlib import Path
from lib.iso.caiso import CAISOClient, CAISOConfig

# Custom config
config = CAISOConfig(
    data_dir=Path('my_data/CAISO'),
    max_retries=5,
    timeout=60,
    retry_delay=10
)

client = CAISOClient(config=config)

MISO Client

Setup with API Keys

from lib.iso.miso import MISOClient, MISOConfig

# Load from config file
config = MISOConfig.from_ini_file()
client = MISOClient(config)

# Or specify directly
config = MISOConfig(
    pricing_api_key='your-pricing-key',
    lgi_api_key='your-lgi-key'
)
client = MISOClient(config)

LMP Data

from datetime import date

# Day-Ahead ExAnte LMP
data = client.get_lmp(
    lmp_type='da_exante',
    start_date=date(2024, 1, 1),
    duration=30,
    node='ALTW.WELLS1'  # Optional: specific node
)

# Save to CSV
if data:
    client.save_to_csv(data, 'miso_lmp.csv')

Available LMP Types

'da_exante'   # Day-Ahead ExAnte
'da_expost'   # Day-Ahead ExPost
'rt_exante'   # Real-Time ExAnte
'rt_expost'   # Real-Time ExPost

Load and Generation

# Actual load
load_data = client.get_demand(
    demand_type='rt_actual',
    start_date=date(2024, 1, 1),
    duration=30,
    time_resolution='daily'
)

# Fuel mix
fuel_data = client.get_fuel_mix(
    start_date=date(2024, 1, 1),
    duration=30
)

# Generation by fuel type
gen_data = client.get_generation(
    gen_type='rt_fuel_type',
    start_date=date(2024, 1, 1),
    duration=30
)

Working with MISO Data

# Download and process
data = client.get_lmp('da_exante', date(2024, 1, 1), 7)

if data:
    # Data is a dict: {date: [records]}
    print(f"Downloaded data for {len(data)} dates")

    # Save to CSV
    client.save_to_csv(data, 'output.csv')

    # Or process directly
    import pandas as pd
    all_records = []
    for date_key, records in data.items():
        for record in records:
            record['query_date'] = date_key
            all_records.append(record)

    df = pd.DataFrame(all_records)
    print(df.head())

NYISO Client

Basic Usage

from lib.iso.nyiso import NYISOClient, NYISOMarket

client = NYISOClient()

# LBMP data
client.get_lbmp(
    market=NYISOMarket.DAM,
    level='zonal',  # or 'generator'
    start_date=date(2024, 1, 1),
    duration=30
)

# Load data
client.get_load_data(
    load_type='actual',
    start_date=date(2024, 1, 1),
    duration=30
)

# Fuel mix
client.get_fuel_mix(
    start_date=date(2024, 1, 1),
    duration=30
)

client.cleanup()

SPP Client

LMP Data

from lib.iso.spp import SPPClient, SPPMarket

client = SPPClient()

# LMP by settlement location
client.get_lmp(
    market=SPPMarket.DAM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31),
    by_location=True  # False for by bus
)

# Market clearing prices
client.get_mcp(
    market=SPPMarket.RTBM,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

client.cleanup()

Load and Resource Forecasts

# Short-term load forecast
client.get_load_forecast(
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31),
    forecast_type='stlf'
)

# Medium-term resource (wind + solar) forecast
client.get_resource_forecast(
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31),
    forecast_type='mtrf'
)

BPA Client

Historical Data

from lib.iso.bpa import BPAClient

client = BPAClient()

# Wind generation and total load
client.get_wind_gen_total_load(
    year=2024,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# Operating reserves
client.get_reserves_deployed(
    year=2024,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

# Outages
client.get_outages(
    year=2024,
    start_date=date(2024, 1, 1),
    end_date=date(2024, 1, 31)
)

client.cleanup()

PJM Client

Setup

from lib.iso.pjm import PJMClient, PJMConfig

# Load from config
config = PJMConfig.from_ini_file()
client = PJMClient(config)

# Or specify directly
config = PJMConfig(api_key='your-api-key')
client = PJMClient(config)

LMP Data

# Day-ahead hourly LMP
client.get_lmp(
    lmp_type='da_hourly',
    start_date=date(2024, 1, 1),
    duration=7,
    pnode_id=51288  # Optional: specific node
)

# Real-time 5-minute LMP
client.get_lmp(
    lmp_type='rt_5min',
    start_date=date(2024, 1, 1),
    duration=1  # Use shorter duration for 5-min data
)

client.cleanup()

ISO-NE Client

Basic Usage

from lib.iso.isone import ISONEClient

client = ISONEClient()

# Day-ahead hourly LMP
paths = client.get_hourly_lmp(
    start_date=date(2024, 1, 1),
    end_date_exclusive=date(2024, 2, 1),
    market='da',
    report='final'
)

# 5-minute regulation prices
paths = client.get_5min_regulation_prices(
    start_date=date(2024, 1, 1),
    end_date_exclusive=date(2024, 2, 1)
)

Weather Client

Download Weather Data

from lib.weather.client import WeatherClient

client = WeatherClient()

# Download weather data (interactive station selection)
client.download_weather_data(
    state='CA',
    start_date=date(2024, 1, 1),
    duration=30,
    interactive=True
)

# Download solar data
client.download_solar_data(year=2024)

Advanced Patterns

Multi-ISO Download

from datetime import date
from lib.iso.caiso import CAISOClient, Market as CAISOMarket
from lib.iso.miso import MISOClient, MISOConfig
from lib.iso.nyiso import NYISOClient, NYISOMarket

start = date(2024, 1, 1)
end = date(2024, 1, 31)

# CAISO
caiso = CAISOClient()
caiso.get_lmp(CAISOMarket.DAM, start, end)
caiso.cleanup()

# MISO
miso_config = MISOConfig.from_ini_file()
miso = MISOClient(miso_config)
miso.get_lmp('da_exante', start, 30)

# NYISO
nyiso = NYISOClient()
nyiso.get_lbmp(NYISOMarket.DAM, 'zonal', start, 30)
nyiso.cleanup()

print("Downloaded data from all three ISOs")

Error Handling

from datetime import date
from lib.iso.caiso import CAISOClient, Market
import logging

# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

client = CAISOClient()

try:
    success = client.get_lmp(
        market=Market.DAM,
        start_date=date(2024, 1, 1),
        end_date=date(2024, 1, 31)
    )

    if success:
        logger.info("Download successful")
    else:
        logger.error("Download failed")

except Exception as e:
    logger.error(f"Error: {e}", exc_info=True)

finally:
    client.cleanup()

Async/Parallel Downloads

from concurrent.futures import ThreadPoolExecutor
from datetime import date
from lib.iso.caiso import CAISOClient, Market

def download_market(market, start, end):
    """Download data for a specific market."""
    client = CAISOClient()
    try:
        result = client.get_lmp(market, start, end)
        return market, result
    finally:
        client.cleanup()

# Download multiple markets in parallel
markets = [Market.DAM, Market.HASP, Market.RTM]
start = date(2024, 1, 1)
end = date(2024, 1, 31)

with ThreadPoolExecutor(max_workers=3) as executor:
    futures = [
        executor.submit(download_market, m, start, end)
        for m in markets
    ]
    results = [f.result() for f in futures]

for market, success in results:
    print(f"{market.value}: {'✓' if success else '✗'}")

Data Processing Pipeline

import pandas as pd
from datetime import date
from pathlib import Path
from lib.iso.caiso import CAISOClient, Market

def download_and_process(start_date, end_date):
    """Download data and perform basic processing."""

    # Download
    client = CAISOClient()
    success = client.get_lmp(Market.DAM, start_date, end_date)
    client.cleanup()

    if not success:
        return None

    # Load the most recent file
    data_dir = Path('data/CAISO')
    files = sorted(data_dir.glob('*PRC_LMP*.csv'))
    if not files:
        return None

    # Process
    df = pd.read_csv(files[-1])

    # Add datetime column
    df['datetime'] = pd.to_datetime(df['OPR_DATE'])

    # Calculate statistics
    stats = {
        'mean_price': df['VALUE'].mean(),
        'max_price': df['VALUE'].max(),
        'min_price': df['VALUE'].min(),
        'date_range': f"{df['OPR_DATE'].min()} to {df['OPR_DATE'].max()}"
    }

    return df, stats

# Use it
df, stats = download_and_process(date(2024, 1, 1), date(2024, 1, 7))
if df is not None:
    print(f"Mean price: ${stats['mean_price']:.2f}/MWh")

Custom Retry Logic

import time
from datetime import date
from lib.iso.caiso import CAISOClient, Market

def download_with_retry(client, market, start, end, max_retries=5):
    """Download with custom retry logic."""

    for attempt in range(max_retries):
        try:
            success = client.get_lmp(market, start, end)
            if success:
                return True

            print(f"Attempt {attempt + 1} failed, retrying...")
            time.sleep(30 * (attempt + 1))  # Exponential backoff

        except Exception as e:
            print(f"Error on attempt {attempt + 1}: {e}")
            if attempt < max_retries - 1:
                time.sleep(30 * (attempt + 1))

    return False

# Use it
client = CAISOClient()
success = download_with_retry(
    client, Market.DAM,
    date(2024, 1, 1), date(2024, 1, 31)
)
client.cleanup()

Best Practices

1. Always Clean Up

# Use try-finally
client = CAISOClient()
try:
    client.get_lmp(Market.DAM, start, end)
finally:
    client.cleanup()

# Or use context manager pattern (if implemented)
# with CAISOClient() as client:
#     client.get_lmp(Market.DAM, start, end)

2. Check Return Values

success = client.get_lmp(Market.DAM, start, end)
if not success:
    print("Download failed - check logs")
    # Handle failure

3. Use Appropriate Date Ranges

from datetime import date, timedelta

# Don't download future dates
today = date.today()
safe_date = today - timedelta(days=2)

# Don't use excessively large ranges at once
# Break into chunks for better reliability

4. Configure Logging

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('isodart.log'),
        logging.StreamHandler()
    ]
)

Type Hints

ISO-DART v2.0 includes type hints for better IDE support:

from datetime import date
from lib.iso.caiso import CAISOClient, Market

# IDE will provide autocomplete and type checking
client: CAISOClient = CAISOClient()
market: Market = Market.DAM
start: date = date(2024, 1, 1)

success: bool = client.get_lmp(market, start, start)

Next Steps