Carbon markets have evolved sophisticated financial instruments that enable efficient price discovery, risk management, and liquidity provision. This chapter explores the trading products available on WIA-CARBON_TRADING and the mechanisms that enable effective carbon price formation.
The spot market forms the foundation of carbon trading, enabling immediate delivery of carbon credits and allowances. Spot prices reflect current supply and demand conditions and serve as the reference point for derivative pricing.
// Spot Contract Definition
interface SpotContract {
contractId: string;
underlying: CarbonCreditType;
tradingUnit: number; // Standard lot size (e.g., 1000 tonnes)
tickSize: number; // Minimum price increment
settlementType: 'physical' | 'cash';
settlementCycle: 'T+0' | 'T+1' | 'T+2';
tradingHours: TradingSession[];
deliveryRegistry: string;
}
// Example EU Allowance Spot Contract
const euaSpot: SpotContract = {
contractId: "EUA-SPOT",
underlying: {
type: 'allowance',
scheme: 'EU-ETS',
vintage: 'current',
serialRange: null // Any valid EUA
},
tradingUnit: 1000, // 1000 EUAs per lot
tickSize: 0.01, // EUR 0.01 per tonne
settlementType: 'physical',
settlementCycle: 'T+2',
tradingHours: [
{
session: 'continuous',
start: '07:00',
end: '17:00',
timezone: 'CET'
}
],
deliveryRegistry: 'EU-REGISTRY'
};
// Spot Market Data Structure
interface SpotMarketData {
contractId: string;
timestamp: Date;
bid: number;
bidSize: number;
ask: number;
askSize: number;
last: number;
volume: number;
openInterest: number;
high: number;
low: number;
vwap: number; // Volume-weighted average price
change: number;
changePercent: number;
}
The order book aggregates buy and sell orders at different price levels, providing visibility into market depth and liquidity. Understanding order book dynamics is crucial for effective trading execution.
// Order Book Analysis
class OrderBookAnalyzer {
analyzeDepth(orderBook: OrderBook): MarketDepthAnalysis {
const bidLevels = this.aggregateLevels(orderBook.bids);
const askLevels = this.aggregateLevels(orderBook.asks);
return {
bidDepth: bidLevels,
askDepth: askLevels,
spread: askLevels[0]?.price - bidLevels[0]?.price,
spreadPercent: (askLevels[0]?.price - bidLevels[0]?.price) / bidLevels[0]?.price * 100,
imbalance: this.calculateImbalance(bidLevels, askLevels),
liquidityScore: this.calculateLiquidityScore(bidLevels, askLevels)
};
}
calculateImbalance(bids: PriceLevel[], asks: PriceLevel[]): number {
const bidVolume = bids.slice(0, 5).reduce((sum, l) => sum + l.quantity, 0);
const askVolume = asks.slice(0, 5).reduce((sum, l) => sum + l.quantity, 0);
return (bidVolume - askVolume) / (bidVolume + askVolume);
}
estimateSlippage(side: 'buy' | 'sell', quantity: number, book: OrderBook): SlippageEstimate {
const levels = side === 'buy' ? book.asks : book.bids;
let remaining = quantity;
let totalCost = 0;
let executionLevels: ExecutionLevel[] = [];
for (const level of levels) {
const fillQty = Math.min(remaining, level.quantity);
totalCost += fillQty * level.price;
remaining -= fillQty;
executionLevels.push({
price: level.price,
quantity: fillQty
});
if (remaining === 0) break;
}
const avgPrice = totalCost / (quantity - remaining);
const bestPrice = levels[0].price;
return {
averagePrice: avgPrice,
slippage: avgPrice - bestPrice,
slippagePercent: (avgPrice - bestPrice) / bestPrice * 100,
filledQuantity: quantity - remaining,
unfilledQuantity: remaining,
executionLevels
};
}
}
Carbon futures enable participants to lock in prices for future delivery, providing crucial hedging capabilities for compliance entities and speculative opportunities for traders. Futures prices incorporate expectations about future supply, demand, and policy developments.
| Parameter | EUA Futures | CCA Futures | Nature Credit Futures |
|---|---|---|---|
| Contract Size | 1,000 tonnes | 1,000 tonnes | 1,000 tonnes |
| Tick Size | EUR 0.01 | USD 0.01 | USD 0.01 |
| Delivery Months | Mar, Jun, Sep, Dec | All months | Mar, Jun, Sep, Dec |
| Settlement | Physical | Physical | Physical |
| Position Limits | 250,000 contracts | 100,000 contracts | 50,000 contracts |
// Futures Contract Implementation
interface FuturesContract {
contractId: string;
underlying: CarbonCreditType;
contractSize: number;
tickSize: number;
tickValue: number;
deliveryMonth: Date;
firstTradingDay: Date;
lastTradingDay: Date;
firstNoticeDay: Date;
lastDeliveryDay: Date;
settlementMethod: 'physical' | 'cash';
marginRequirements: {
initial: number; // Percentage
maintenance: number; // Percentage
};
positionLimits: {
spotMonth: number;
allMonths: number;
};
}
// Futures Pricing Model
class FuturesPricer {
calculateTheoreticalPrice(
spotPrice: number,
riskFreeRate: number,
storageAndCarryCost: number,
timeToExpiry: number, // Years
convenienceYield: number
): number {
// Cost of carry model
// F = S * e^((r + c - y) * T)
const netCarry = riskFreeRate + storageAndCarryCost - convenienceYield;
return spotPrice * Math.exp(netCarry * timeToExpiry);
}
calculateBasis(futuresPrice: number, spotPrice: number): number {
return futuresPrice - spotPrice;
}
calculateImpliedRepo(
spotPrice: number,
futuresPrice: number,
timeToExpiry: number
): number {
// Implied financing rate
return Math.log(futuresPrice / spotPrice) / timeToExpiry;
}
buildForwardCurve(
spotPrice: number,
futuresChain: FuturesQuote[]
): ForwardCurve {
const points = futuresChain.map(f => ({
maturity: f.deliveryMonth,
price: f.price,
impliedRate: this.calculateImpliedRepo(
spotPrice,
f.price,
this.yearFraction(new Date(), f.deliveryMonth)
)
}));
return { spotPrice, forwardPoints: points };
}
}
Carbon options provide the right, but not the obligation, to buy (call) or sell (put) carbon credits at a specified price. Options enable sophisticated risk management strategies and allow participants to express views on price volatility.
// Carbon Option Contract
interface CarbonOption {
optionId: string;
underlying: string; // Futures contract or spot
optionType: 'call' | 'put';
exerciseStyle: 'european' | 'american';
strikePrice: number;
expirationDate: Date;
contractSize: number;
premiumQuotation: 'per_tonne' | 'total';
settlementMethod: 'physical' | 'cash';
}
// Option Pricing using Black-Scholes
class CarbonOptionPricer {
private normalCDF(x: number): number {
const a1 = 0.254829592;
const a2 = -0.284496736;
const a3 = 1.421413741;
const a4 = -1.453152027;
const a5 = 1.061405429;
const p = 0.3275911;
const sign = x < 0 ? -1 : 1;
x = Math.abs(x) / Math.sqrt(2);
const t = 1.0 / (1.0 + p * x);
const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
return 0.5 * (1.0 + sign * y);
}
priceOption(
spotPrice: number,
strikePrice: number,
timeToExpiry: number,
riskFreeRate: number,
volatility: number,
optionType: 'call' | 'put'
): OptionPricing {
const d1 = (Math.log(spotPrice / strikePrice) +
(riskFreeRate + volatility * volatility / 2) * timeToExpiry) /
(volatility * Math.sqrt(timeToExpiry));
const d2 = d1 - volatility * Math.sqrt(timeToExpiry);
let price: number;
let delta: number;
if (optionType === 'call') {
price = spotPrice * this.normalCDF(d1) -
strikePrice * Math.exp(-riskFreeRate * timeToExpiry) * this.normalCDF(d2);
delta = this.normalCDF(d1);
} else {
price = strikePrice * Math.exp(-riskFreeRate * timeToExpiry) * this.normalCDF(-d2) -
spotPrice * this.normalCDF(-d1);
delta = this.normalCDF(d1) - 1;
}
// Calculate Greeks
const gamma = Math.exp(-d1 * d1 / 2) /
(spotPrice * volatility * Math.sqrt(2 * Math.PI * timeToExpiry));
const vega = spotPrice * Math.sqrt(timeToExpiry) *
Math.exp(-d1 * d1 / 2) / Math.sqrt(2 * Math.PI);
const theta = this.calculateTheta(spotPrice, strikePrice, timeToExpiry,
riskFreeRate, volatility, optionType, d1, d2);
return { price, delta, gamma, vega, theta };
}
}
Effective price discovery is essential for market efficiency. WIA-CARBON_TRADING employs multiple mechanisms to ensure accurate and transparent price formation.
During regular trading hours, prices are discovered through continuous order matching. The best bid and ask prices from the order book determine the current market spread, while executed trades establish transaction prices.
Periodic auctions aggregate orders and execute at a single clearing price, providing concentrated liquidity events. Auctions are particularly important for compliance market allowance distribution.
// Auction Price Discovery
class AuctionEngine {
private orders: AuctionOrder[] = [];
determineAuctionPrice(): AuctionResult {
// Separate buy and sell orders
const buyOrders = this.orders.filter(o => o.side === 'buy')
.sort((a, b) => b.price - a.price);
const sellOrders = this.orders.filter(o => o.side === 'sell')
.sort((a, b) => a.price - b.price);
// Build demand and supply curves
const demandCurve = this.buildCumulativeCurve(buyOrders, 'descending');
const supplyCurve = this.buildCumulativeCurve(sellOrders, 'ascending');
// Find equilibrium price (maximum volume)
let maxVolume = 0;
let clearingPrice = 0;
const allPrices = [...new Set([
...buyOrders.map(o => o.price),
...sellOrders.map(o => o.price)
])].sort((a, b) => a - b);
for (const price of allPrices) {
const demandAtPrice = this.getQuantityAtPrice(demandCurve, price, 'demand');
const supplyAtPrice = this.getQuantityAtPrice(supplyCurve, price, 'supply');
const volumeAtPrice = Math.min(demandAtPrice, supplyAtPrice);
if (volumeAtPrice > maxVolume) {
maxVolume = volumeAtPrice;
clearingPrice = price;
}
}
// Match orders at clearing price
const matches = this.matchAtPrice(clearingPrice, buyOrders, sellOrders);
return {
clearingPrice,
totalVolume: maxVolume,
matches,
coverRatio: this.calculateCoverRatio(demandCurve, supplyCurve, clearingPrice)
};
}
}
The variety of trading instruments on WIA-CARBON_TRADING enables participants to implement sophisticated carbon management strategies. The next chapter examines the registry systems and MRV processes that ensure the integrity of all traded carbon assets.