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]
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}")
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)}")
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)