DEV Community

Propfirmkey
Propfirmkey

Posted on

Understanding Futures Contract Specifications for Algorithmic Trading

If you're building trading algorithms for futures markets, getting contract specifications wrong will cost you money. Let's build a comprehensive contract specification library in Python.

Why Specs Matter

A single E-mini S&P 500 (ES) tick is $12.50. A Micro (MES) tick is $1.25. Hard-coding the wrong value means your position sizer calculates 10x too large or too small.

Building a Contract Spec Library

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import json

class Exchange(Enum):
    CME = "CME"
    CBOT = "CBOT"
    NYMEX = "NYMEX"
    COMEX = "COMEX"

class AssetClass(Enum):
    EQUITY_INDEX = "equity_index"
    ENERGY = "energy"
    METALS = "metals"
    AGRICULTURE = "agriculture"
    INTEREST_RATE = "interest_rate"
    CURRENCY = "currency"

@dataclass
class ContractSpec:
    symbol: str
    name: str
    exchange: Exchange
    asset_class: AssetClass
    tick_size: float
    tick_value: float
    point_value: float
    contract_size: float
    margin_initial: float
    margin_maintenance: float
    trading_hours: str
    months: list[str]
    micro_symbol: Optional[str] = None

    @property
    def ticks_per_point(self) -> float:
        return 1.0 / self.tick_size

    @property
    def dollar_per_point(self) -> float:
        return self.tick_value * self.ticks_per_point

    def pnl(self, entry: float, exit: float, quantity: int = 1) -> float:
        points = exit - entry
        return points * self.dollar_per_point * quantity

    def ticks_to_dollars(self, ticks: int) -> float:
        return ticks * self.tick_value

    def dollars_to_ticks(self, dollars: float) -> int:
        return int(dollars / self.tick_value)

# Comprehensive contract database
CONTRACTS = {
    "ES": ContractSpec(
        symbol="ES", name="E-mini S&P 500", exchange=Exchange.CME,
        asset_class=AssetClass.EQUITY_INDEX,
        tick_size=0.25, tick_value=12.50, point_value=50.0,
        contract_size=50, margin_initial=15_400, margin_maintenance=14_000,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=["H","M","U","Z"],
        micro_symbol="MES"
    ),
    "NQ": ContractSpec(
        symbol="NQ", name="E-mini Nasdaq-100", exchange=Exchange.CME,
        asset_class=AssetClass.EQUITY_INDEX,
        tick_size=0.25, tick_value=5.00, point_value=20.0,
        contract_size=20, margin_initial=18_700, margin_maintenance=17_000,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=["H","M","U","Z"],
        micro_symbol="MNQ"
    ),
    "CL": ContractSpec(
        symbol="CL", name="Crude Oil", exchange=Exchange.NYMEX,
        asset_class=AssetClass.ENERGY,
        tick_size=0.01, tick_value=10.00, point_value=1000.0,
        contract_size=1000, margin_initial=6_600, margin_maintenance=6_000,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=list("FGHJKMNQUVXZ"),
        micro_symbol="MCL"
    ),
    "GC": ContractSpec(
        symbol="GC", name="Gold", exchange=Exchange.COMEX,
        asset_class=AssetClass.METALS,
        tick_size=0.10, tick_value=10.00, point_value=100.0,
        contract_size=100, margin_initial=11_000, margin_maintenance=10_000,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=list("GJMQVZ"),
        micro_symbol="MGC"
    ),
    "YM": ContractSpec(
        symbol="YM", name="E-mini Dow", exchange=Exchange.CBOT,
        asset_class=AssetClass.EQUITY_INDEX,
        tick_size=1.0, tick_value=5.00, point_value=5.0,
        contract_size=5, margin_initial=10_200, margin_maintenance=9_300,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=["H","M","U","Z"],
        micro_symbol="MYM"
    ),
    "RTY": ContractSpec(
        symbol="RTY", name="E-mini Russell 2000", exchange=Exchange.CME,
        asset_class=AssetClass.EQUITY_INDEX,
        tick_size=0.10, tick_value=5.00, point_value=50.0,
        contract_size=50, margin_initial=7_150, margin_maintenance=6_500,
        trading_hours="Sun-Fri 17:00-16:00 CT", months=["H","M","U","Z"],
        micro_symbol="M2K"
    ),
}

def get_contract(symbol: str) -> ContractSpec:
    sym = symbol.upper()
    if sym not in CONTRACTS:
        raise ValueError(f"Unknown contract: {sym}. Available: {list(CONTRACTS.keys())}")
    return CONTRACTS[sym]
Enter fullscreen mode Exit fullscreen mode

Practical Example: Multi-Contract P&L Calculator

def calculate_trade(symbol: str, entry: float, exit: float, qty: int):
    spec = get_contract(symbol)
    pnl = spec.pnl(entry, exit, qty)
    ticks = (exit - entry) / spec.tick_size

    print(f"Trade: {qty}x {spec.name} ({symbol})")
    print(f"  Entry: {entry} -> Exit: {exit}")
    print(f"  Ticks: {ticks:+.0f}")
    print(f"  P&L: ${pnl:+,.2f}")
    print(f"  Margin used: ${spec.margin_initial * qty:,.0f}")
    print(f"  ROI on margin: {pnl / (spec.margin_initial * qty) * 100:+.1f}%")
    return pnl

# Example trades
trades = [
    ("ES", 5250.00, 5258.50, 2),   # 34 ticks profit
    ("NQ", 18500.00, 18475.25, 1),  # 99 ticks loss
    ("CL", 72.50, 73.15, 3),        # 65 ticks profit
]

total = 0
for t in trades:
    total += calculate_trade(*t)
    print()

print(f"Total session P&L: ${total:+,.2f}")
Enter fullscreen mode Exit fullscreen mode

Contract Rollover Dates

from datetime import date

MONTH_CODES = {"F":1,"G":2,"H":3,"J":4,"K":5,"M":6,
               "N":7,"Q":8,"U":9,"V":10,"X":11,"Z":12}

def next_expiry(symbol: str, from_date: date = None) -> str:
    from_date = from_date or date.today()
    spec = get_contract(symbol)

    for month_code in spec.months * 2:  # loop twice for year wrap
        month = MONTH_CODES[month_code]
        year = from_date.year if month >= from_date.month else from_date.year + 1
        # Third Friday approximation
        expiry = date(year, month, 15)
        while expiry.weekday() != 4:
            expiry = expiry.replace(day=expiry.day + 1)

        if expiry > from_date:
            return f"{symbol}{month_code}{year % 100:02d}"

    return "Unknown"

for sym in ["ES", "NQ", "CL", "GC"]:
    print(f"{sym}: Next contract = {next_expiry(sym)}")
Enter fullscreen mode Exit fullscreen mode

Summary

Getting contract specs right is foundational for any futures trading system. This library gives you a clean, extensible way to handle specs across instruments.

For a broader comparison of which futures instruments are available across different prop firms, check out PropFirmKey's futures prop firm comparison β€” they cover firms like Alpha Futures with details on available instruments and contract specs.

Top comments (0)