IBKR Advanced Trading

Overview

Interactive Brokers supports far more than US stocks. This chapter covers trading options, futures, and forex through Puffin’s ContractSpec system, plus using IBKRDataProvider for multi-asset historical and real-time data.

Options, futures, and forex involve significant risk and require appropriate account permissions and margin. Ensure your IB account is approved for each product before trading.

Architecture

graph TB
    classDef dark fill:#2d5016,stroke:#1a3a1a,color:#e8e0d4
    classDef accent fill:#1a3a5c,stroke:#0d2137,color:#e8e0d4
    classDef broker fill:#6b2d5b,stroke:#4a1a4a,color:#e8e0d4
    classDef gateway fill:#8b4513,stroke:#5a2d0a,color:#e8e0d4

    GW[IB Gateway / TWS]:::gateway
    BR[IBKRBroker<br/>client_id=1]:::broker
    DP[IBKRDataProvider<br/>client_id=10]:::accent
    CS[ContractSpec]:::dark
    ST[Your Strategy]:::dark

    ST --> BR
    ST --> DP
    BR --> GW
    DP --> GW
    CS --> BR
    CS -.-> DP

Each component uses a separate client_id so the broker and data provider can connect simultaneously without conflicts.

ContractSpec

The ContractSpec dataclass defines what you’re trading beyond simple US stocks:

from puffin.broker import ContractSpec

# US stock (default — same as not using a spec)
stock = ContractSpec(asset_type="STK", exchange="SMART", currency="USD")

# Non-US stock (London Stock Exchange)
uk_stock = ContractSpec(asset_type="STK", exchange="LSE", currency="GBP")

# Option
call_option = ContractSpec(
    asset_type="OPT",
    expiry="20260320",
    strike=150.0,
    right="C",        # "C" for call, "P" for put
    exchange="SMART",
    currency="USD",
)

# Futures
es_future = ContractSpec(
    asset_type="FUT",
    expiry="202603",
    exchange="CME",
    currency="USD",
    multiplier="50",
)

# Forex
forex = ContractSpec(asset_type="CASH", pair_currency="JPY")

Trading with ContractSpec

Use submit_order_with_spec() for non-stock orders:

from puffin.broker import IBKRBroker, ContractSpec, Order, OrderSide, OrderType

broker = IBKRBroker(port=4002, paper=True)

# Buy a call option
order = Order(symbol="AAPL", side=OrderSide.BUY, qty=1, type=OrderType.LIMIT, limit_price=5.50)
spec = ContractSpec(asset_type="OPT", expiry="20260320", strike=150.0, right="C")
order_id = broker.submit_order_with_spec(order, spec)

# Buy E-mini S&P 500 futures
order = Order(symbol="ES", side=OrderSide.BUY, qty=1, type=OrderType.LIMIT, limit_price=5200.0)
spec = ContractSpec(asset_type="FUT", expiry="202603", exchange="CME", multiplier="50")
order_id = broker.submit_order_with_spec(order, spec)

# Buy EUR/USD forex
order = Order(symbol="EUR", side=OrderSide.BUY, qty=100000, type=OrderType.MARKET)
spec = ContractSpec(asset_type="CASH", pair_currency="USD")
order_id = broker.submit_order_with_spec(order, spec)

Regular submit_order() still works exactly as before for US stocks — no changes needed to existing code.

IBKRDataProvider

The dedicated data provider supports historical and real-time data for all asset types:

Historical Data

from puffin.data import IBKRDataProvider

provider = IBKRDataProvider(port=4002, client_id=10)

# Stock data
df = provider.fetch_historical("AAPL", start="2025-01-01", end="2026-01-01", interval="1d")

# Futures data
df = provider.fetch_historical("ES", start="2025-06-01", interval="1h", asset_type="FUT")

# Forex data (uses MIDPOINT automatically)
df = provider.fetch_historical("EURUSD", start="2025-01-01", interval="1d", asset_type="CASH")

Supported intervals: 1m, 5m, 15m, 30m, 1h, 1d, 1w.

Real-Time Streaming

def on_bar(symbol, price, volume, timestamp):
    print(f"{symbol}: {price} @ {timestamp}")

# Stream 5-second bars
thread = provider.stream_realtime(["AAPL", "MSFT"], callback=on_bar)

# Forex streaming
thread = provider.stream_realtime(["EURUSD"], callback=on_bar, asset_type="CASH")

Supported Assets

provider.get_supported_assets()
# ['equity', 'etf', 'futures', 'options', 'forex']

Risk Considerations

Margin Requirements

Options and futures require margin. Monitor your account:

account = broker.get_account()
print(f"Margin used: ${account.margin_used:,.2f}")
print(f"Maintenance margin: ${account.maintenance_margin:,.2f}")
print(f"Available funds: ${account.cash:,.2f}")

Global Market Hours

IB supports markets worldwide. Forex trades nearly 24 hours on weekdays. Futures have extended hours. Your safety controllers should account for these schedules:

from puffin.broker import TradingHoursValidator

# For US stocks, the default validator works
validator = TradingHoursValidator()

# For forex/futures, you may need to adjust or disable hours checking
# since these markets operate outside US equity hours

Position Sizing for Leveraged Products

Futures and forex are highly leveraged. A single E-mini S&P contract controls ~$260,000 notional value. Use PositionSizingValidator to limit exposure:

from puffin.broker import PositionSizingValidator

validator = PositionSizingValidator(max_position_pct=0.02)  # 2% per position