Back to Tutorials

PPA Settlement

Calculate capture prices and settlements

Overview

Power Purchase Agreements (PPAs) are long-term contracts between renewable generators and offtakers. Settlement typically occurs monthly, comparing market reference prices against the agreed strike price.

Key Concepts

Capture Price

Volume-weighted average price achieved by a technology. Wind typically captures 85-95% of baseload due to cannibalization.

Shape Factor

Capture Price ÷ Baseload Price. Values below 1.0 indicate the technology generates when prices are lower.

Reference Price

The market price used for settlement. Can be baseload average, capture price, or a specific index.

Settlement

(Reference Price - Strike Price) × Volume. Positive means offtaker pays generator the difference.

Calculating Capture Price

The capture price is the volume-weighted average price achieved during periods of generation. For wind, this is typically lower than baseload due to price cannibalization when wind output is high.

typescript
import { EnergyOracle } from '@energyoracle/sdk';

const oracle = new EnergyOracle({ apiKey: 'your-key' });

// Calculate capture price for wind generation
const capture = await oracle.uk.analytics.capturePrice({
  technology: 'wind',
  year: 2024,
  month: 12,
});

console.log(`Capture Price: £${capture.capturePrice}/MWh`);
console.log(`Baseload Price: £${capture.baseloadPrice}/MWh`);
console.log(`Shape Factor: ${capture.shapeFactor}`);

// Shape Factor = Capture Price / Baseload Price
// < 1.0 means wind captures below average price (cannibalization)
// > 1.0 means wind captures above average price

Formula: Capture Price = Σ(Price × Generation) ÷ Σ(Generation)

Settlement Calculation

Use our SDK to calculate monthly settlements with a single API call.

typescript
// Monthly PPA settlement calculation
const settlement = await oracle.uk.settlement.calculate({
  volumeMwh: 10000,           // 10 GWh monthly generation
  contractPrice: 55.00,       // Strike price £55/MWh
  fromDate: '2024-12-01',
  toDate: '2024-12-31',
  technology: 'wind',         // Optional: use technology-specific capture
});

// Response:
// {
//   period: { from: '2024-12-01', to: '2024-12-31' },
//   volumeMwh: 10000,
//   contractPrice: 55.00,
//   referencePrice: 48.50,    // Monthly average or capture price
//   settlementAmount: -65000, // Negative = generator pays offtaker
//   details: {
//     capturePrice: 48.50,
//     shapeFactor: 0.91,
//     baseloadPrice: 53.30
//   }
// }

Custom Settlement with Python

For complex settlement logic, use raw price data with Pandas.

python
from energyoracle import EnergyOracle
import pandas as pd

oracle = EnergyOracle(api_key="your-key")

# Get raw price data for custom calculations
prices = oracle.uk.prices.range("2024-12-01", "2024-12-31")
df = prices.to_dataframe()

# Calculate your own settlement index
# Example: Volume-weighted average for specific hours
peak_hours = df[(df['period'] >= 16) & (df['period'] <= 40)]  # 8am-8pm
peak_avg = peak_hours['price'].mean()

# Apply contract formula
volume_mwh = 10000
strike_price = 55.00
settlement = (peak_avg - strike_price) * volume_mwh

print(f"Peak Average: £{peak_avg:.2f}/MWh")
print(f"Settlement: £{settlement:,.0f}")

Reference Price Indices

Different PPAs use different reference indices. Our API supports all common types.

typescript
// Available reference indices
const indices = {
  // Simple averages
  baseload: 'Average of all settlement periods',
  peak: 'Average of periods 16-40 (8am-8pm weekdays)',
  offpeak: 'Average of all other periods',

  // Technology capture prices
  windCapture: 'Volume-weighted by wind generation',
  solarCapture: 'Volume-weighted by solar generation',

  // System prices
  systemSellPrice: 'SSP - for short positions',
  systemBuyPrice: 'SBP - for long positions',
};

// Get specific index
const index = await oracle.uk.analytics.referenceIndex({
  type: 'windCapture',
  year: 2024,
  month: 12,
});

PPA Contract Types

Implementation patterns for common PPA structures.

typescript
// Different PPA contract types

// 1. Fixed Price PPA
const fixedPPA = {
  type: 'fixed',
  strikePrice: 55.00,
  volume: 10000,
  settlement: async (oracle, period) => {
    const ref = await oracle.uk.prices.monthlyAverage(period.year, period.month);
    return (ref.avgPrice - 55.00) * 10000;
  }
};

// 2. Baseload Shape PPA (most common)
const baseloadPPA = {
  type: 'baseload',
  strikePrice: 55.00,
  volume: 10000,
  settlement: async (oracle, period) => {
    const ref = await oracle.uk.prices.monthlyAverage(period.year, period.month);
    return (ref.avgPrice - 55.00) * 10000;
  }
};

// 3. As-Generated PPA (technology-specific capture)
const asGeneratedPPA = {
  type: 'as-generated',
  technology: 'wind',
  strikePrice: 50.00,
  volume: 10000,
  settlement: async (oracle, period) => {
    const capture = await oracle.uk.analytics.capturePrice({
      technology: 'wind',
      year: period.year,
      month: period.month
    });
    return (capture.capturePrice - 50.00) * 10000;
  }
};

// 4. Sleeved PPA (route-to-market)
const sleevedPPA = {
  type: 'sleeved',
  strikePrice: 48.00, // Lower due to imbalance risk
  shapeDiscount: 0.05, // 5% discount for shape
  imbalanceCost: 2.50, // £2.50/MWh imbalance allowance
};

On-Chain Settlement

Use our Solidity contracts for trustless, automated settlement.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@energyoracle/contracts/IEnergyOracle.sol";

contract PPASettlement {
    IEnergyOracle public oracle;

    // Strike price in GBP/MWh (18 decimals)
    uint256 public strikePrice = 55e18;

    function calculateSettlement(
        uint16 year,
        uint8 month,
        uint256 volumeMwh
    ) external view returns (int256) {
        // Get reference price from oracle
        uint256 referencePrice = oracle.getMonthlyAverage(year, month);

        // Settlement = (Reference - Strike) × Volume
        int256 priceDiff = int256(referencePrice) - int256(strikePrice);
        int256 settlement = priceDiff * int256(volumeMwh) / 1e18;

        return settlement;
    }
}

Best Practices

1. Use Final Settlement Data

Elexon publishes initial prices (II) which are later revised. For contractual settlement, wait for SF (Settlement Final) data, typically available 14 working days after the settlement day.

2. Document Your Reference Price

Store the exact timestamp and data source used for each settlement calculation. Our API includes metadata for audit trails.

3. Handle Clock Changes

UK has 46 settlement periods on short days and 50 on long days. Our API handles this automatically, but verify your volume allocation logic.

Next Steps