Interactive Brokers provider implementation for market-data-core
Project description
market-data-ibkr
Version: 1.0.0
Status: Production Ready
Interactive Brokers provider implementation for market-data-core. This package implements the MarketDataProvider protocol to deliver real-time and historical market data from IBKR Gateway/TWS.
๐ฏ Features
- โ Real-time quote streaming - Live bid/ask/last prices
- โ Real-time bar streaming - 5-second OHLCV bars
- โ Historical data - Request historical bars with automatic pacing
- โ Automatic reconnection - Exponential backoff on disconnection
- โ Rate limiting - TokenBucket algorithm prevents IBKR pacing violations
- โ Error mapping - Canonical error types from Core
- โ Contract caching - Minimize redundant IBKR API calls
- โ Async context manager - Clean resource management
- ๐ง Tick-by-tick trades - Coming soon
- ๐ง Options chain streaming - Coming soon
๐ฆ Installation
From Git (Recommended)
pip install git+https://github.com/YOUR_ORG/market-data-ibkr.git@v1.0.0
From Local Clone
git clone https://github.com/YOUR_ORG/market-data-ibkr.git
cd market-data-ibkr
pip install -e .
Development Installation
git clone https://github.com/YOUR_ORG/market-data-ibkr.git
cd market-data-ibkr
pip install -e ".[dev]"
๐ Quick Start
Basic Quote Streaming
import asyncio
from market_data_core import Instrument
from market_data_ibkr import IBKRProvider, IBKRSettings
async def main():
settings = IBKRSettings(
host="127.0.0.1",
port=4002, # Paper trading
client_id=17,
)
async with IBKRProvider(settings) as provider:
instruments = [Instrument(symbol="AAPL")]
async for quote in provider.stream_quotes(instruments):
print(f"{quote.symbol}: ${quote.last}")
asyncio.run(main())
Historical Data
from datetime import datetime, timedelta
async def fetch_history():
settings = IBKRSettings(host="127.0.0.1", port=4002)
async with IBKRProvider(settings) as provider:
instrument = Instrument(symbol="AAPL")
end = datetime.now()
start = end - timedelta(days=7)
async for bar in provider.request_historical_bars(
instrument=instrument,
start=start,
end=end,
resolution="1d"
):
print(f"{bar.ts}: O={bar.open} H={bar.high} L={bar.low} C={bar.close}")
asyncio.run(fetch_history())
โ๏ธ Configuration
IBKRSettings
All connection and behavior settings are configured via IBKRSettings:
from market_data_ibkr import IBKRSettings
settings = IBKRSettings(
# Connection
host="127.0.0.1", # IBKR Gateway/TWS host
port=4002, # 4002=Paper, 4001=Live, 7497=TWS
client_id=17, # Unique client ID (0-9999)
read_timeout_sec=30.0, # Socket timeout
# Market data
market_data_type=1, # 1=Live, 2=Frozen, 3=Delayed, 4=Delayed frozen
snapshot_mode=False, # True for snapshots instead of streaming
# Reconnection
reconnect_enabled=True, # Auto-reconnect on disconnect
reconnect_backoff_ms=250, # Initial backoff
reconnect_backoff_max_ms=5000, # Max backoff
max_reconnect_attempts=10, # 0 = infinite
# Historical data pacing
hist_pacing_window_sec=600, # 10-min cooldown window
hist_max_bars_per_request=2000,
# Options (future)
options_semaphore_size=5,
options_base_delay=0.1,
)
Environment Variables
You can use a .env file:
IBKR_HOST=127.0.0.1
IBKR_PORT=4002
IBKR_CLIENT_ID=17
Then load with python-dotenv:
from dotenv import load_dotenv
import os
load_dotenv()
settings = IBKRSettings(
host=os.getenv("IBKR_HOST", "127.0.0.1"),
port=int(os.getenv("IBKR_PORT", 4002)),
client_id=int(os.getenv("IBKR_CLIENT_ID", 17)),
)
๐๏ธ Architecture
Protocol Conformance
This package implements the MarketDataProvider protocol from market-data-core:
- โ
stream_quotes(instruments)โAsyncIterable[Quote] - โ
stream_bars(resolution, instruments)โAsyncIterable[Bar] - โ
request_historical_bars(...)โAsyncIterable[Bar] - ๐ง
stream_trades(instruments)โAsyncIterable[Trade] - ๐ง
stream_options(instrument, ...)โAsyncIterable[OptionSnapshot]
Module Structure
src/market_data_ibkr/
โโโ __init__.py # Public API
โโโ settings.py # IBKRSettings (Pydantic)
โโโ session.py # IBKRSessionManager (connection lifecycle)
โโโ errors.py # IBKR โ Core error mapping
โโโ pacing.py # TokenBucket + PacingManager
โโโ mapping.py # DTO conversions (TickerโQuote, BarDataโBar)
โโโ provider.py # IBKRProvider (main implementation)
Error Handling
All IBKR errors are mapped to Core canonical exception types:
| IBKR Code | Core Exception | Description |
|---|---|---|
| 420 | PacingViolation |
Rate limit exceeded |
| 162 | (varies) | Ambiguous umbrella code |
| 200 | InvalidInstrument |
Security not found |
| 354 | PermissionsMissing |
No market data permissions |
| 504 | ConnectionFailed |
Not connected |
| 1100 | ConnectionFailed |
TWS connection lost |
| 2110 | FarmTransient |
Server connectivity issue |
Rate Limiting
IBKR enforces strict rate limits:
- Historical data: 60 requests per 10 minutes
- Pacing violations: 10-minute cooldown
This provider handles rate limiting with:
- TokenBucket: Smooth rate limiting (6 req/min)
- PacingManager: Tracks cooldown per scope (symbol)
- Automatic backoff: Exponential delays on errors
๐งช Testing
Run the test suite:
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# With coverage
pytest tests/ --cov=market_data_ibkr --cov-report=html
Test Structure
tests/
โโโ conftest.py # Fixtures (mock_ib, ibkr_settings)
โโโ test_settings.py # Settings validation
โโโ test_session.py # Connection management
โโโ test_errors.py # Error code mapping
โโโ test_pacing.py # Rate limiting
โโโ test_mapping.py # DTO conversions
โโโ test_provider.py # Provider implementation
๐ Examples
See the examples/ directory:
basic_streaming.py: Stream real-time quoteshistorical_data.py: Fetch historical bars with pacing
Run examples:
python examples/basic_streaming.py
python examples/historical_data.py
๐ง Requirements
System Requirements
- Python: 3.11+
- IBKR Gateway or TWS: Running and connected
- IBKR Account: Paper or live with market data subscriptions
IBKR Setup
- Download IBKR Gateway or TWS from Interactive Brokers
- Configure API settings:
- Enable API connections
- Set socket port (4001=Live, 4002=Paper, 7497=TWS)
- Add trusted IPs (127.0.0.1 for localhost)
- Start Gateway/TWS and login
- Verify connection: Check Gateway status shows "Listening"
Market Data Subscriptions
Ensure your account has subscriptions for:
- US Securities Snapshot and Futures Value Bundle (for US stocks)
- Any other asset classes you plan to trade
Without proper subscriptions, you'll get PermissionsMissing errors (code 354).
๐ Troubleshooting
"Connection refused" (ConnectionFailed)
- โ Check IBKR Gateway/TWS is running
- โ Verify correct port (4002 for paper, 4001 for live)
- โ Check firewall allows connections to 127.0.0.1
"No market data permissions" (PermissionsMissing)
- โ Verify market data subscriptions in Account Management
- โ
Try
market_data_type=3(delayed data) if live data not subscribed - โ Check symbol is valid and trading on specified exchange
"Pacing violation" (PacingViolation)
- โ Slow down requests (built-in rate limiter helps but may need tuning)
- โ Wait for cooldown (10 minutes for historical data)
- โ
Use
PacingManager.clear_cooldown(scope)to manually reset (use cautiously)
Historical data returns empty
- โ Check date range is valid (not future dates)
- โ
Verify market hours (use
useRTH=Truein settings) - โ Ensure instrument has data for requested period
๐๏ธ Migration from Legacy Code
If upgrading from the old src/ibkr_client.py architecture:
Old Code (Legacy)
from src.market_data_collector import MarketDataCollector
collector = MarketDataCollector()
await collector.connect()
data = await collector.collect_historical_data(["AAPL"], "1 M", "1 day")
await collector.disconnect()
New Code (v1.0.0)
from market_data_ibkr import IBKRProvider, IBKRSettings
from market_data_core import Instrument
from datetime import datetime, timedelta
settings = IBKRSettings(host="127.0.0.1", port=4002)
async with IBKRProvider(settings) as provider:
instrument = Instrument(symbol="AAPL")
end = datetime.now()
start = end - timedelta(days=30)
async for bar in provider.request_historical_bars(
instrument, start, end, resolution="1d"
):
print(bar)
Key Changes
- Protocol conformance: All methods return Core DTOs
- Async context manager:
async withfor automatic cleanup - Settings-based config: No more raw env vars in code
- Error handling: Canonical exceptions instead of generic errors
- Rate limiting: Built-in pacing management
Legacy Code Location
Old code has been moved to legacy/ for reference:
legacy/
โโโ config.py
โโโ main.py
โโโ requirements.txt
โโโ __init__.py
โโโ data_store.py
โโโ ibkr_client.py
โโโ market_data_collector.py
โ ๏ธ Note: data_store.py (SQLite storage) is not part of the Core protocol. Storage is handled downstream by consumers of the provider.
๐ณ Docker Deployment
Running as a Service
This provider can run as a containerized HTTP service for integration with the market-data platform infrastructure.
Build the Image
docker build -t market-data-ibkr:latest .
Run Standalone
docker run -d \
--name ibkr \
-p 8084:8084 \
-e IBKR_HOST=host.docker.internal \
-e IBKR_GATEWAY_PORT=4002 \
-e IBKR_CLIENT_ID=17 \
market-data-ibkr:latest
Note: Use host.docker.internal to connect to IBKR Gateway running on your host machine.
Run with Docker Compose
This service is designed to integrate with the market_data_infra compose stack:
# In market_data_infra/docker-compose.yml
ibkr:
build: ../market_data_ibkr
container_name: ibkr
environment:
IBKR_ACCOUNT: ${IBKR_ACCOUNT}
IBKR_GATEWAY_PORT: ${IBKR_GATEWAY_PORT}
CORE_URL: ${CORE_URL}
ports: ["8084:8084"]
depends_on:
core:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8084/health || exit 1"]
interval: 10s
timeout: 3s
retries: 10
networks: [mdnet]
profiles: ["pipeline"]
Start the service:
# From market_data_infra directory
docker compose --profile pipeline up -d ibkr
HTTP API Endpoints
Once running, the service exposes:
Health Check
curl http://localhost:8084/health
Response:
{
"status": "healthy",
"version": "1.0.0",
"connected": true
}
Prometheus Metrics
curl http://localhost:8084/metrics
Stream Quotes (SSE)
curl -X POST http://localhost:8084/api/v1/stream/quotes \
-H "Content-Type: application/json" \
-d '{"symbols": ["AAPL", "MSFT"]}'
Historical Bars
curl -X POST http://localhost:8084/api/v1/historical/bars \
-H "Content-Type: application/json" \
-d '{
"symbol": "AAPL",
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-31T00:00:00Z",
"resolution": "1d"
}'
Environment Variables
| Variable | Default | Description |
|---|---|---|
IBKR_HOST |
127.0.0.1 |
IBKR Gateway/TWS host |
IBKR_GATEWAY_PORT |
4002 |
IBKR Gateway port |
IBKR_CLIENT_ID |
17 |
Client ID for connection |
PORT |
8084 |
HTTP service port |
Using with IBKR Gateway
When running in Docker, you need to ensure the container can reach your IBKR Gateway:
Option 1: Run IBKR Gateway on host, use host.docker.internal
docker run -e IBKR_HOST=host.docker.internal ...
Option 2: Run IBKR Gateway in same Docker network
# Not recommended - IBKR Gateway has complex requirements
Option 3: Expose Gateway port and connect by host IP
docker run -e IBKR_HOST=192.168.1.100 ...
Health Checks
The Docker image includes a built-in health check that runs every 10 seconds:
# Check container health
docker inspect ibkr --format='{{.State.Health.Status}}'
Healthy containers will show: healthy
๐ Roadmap
v1.0.0 (Current)
- โ Quote streaming
- โ Bar streaming (5s real-time)
- โ Historical bars with pacing
- โ Auto-reconnection
- โ Error mapping
- โ Contract caching
v1.1.0 (Planned)
- ๐ง Tick-by-tick trade streaming
- ๐ง Options chain streaming
- ๐ง Futures support
- ๐ง Forex support
v2.0.0 (Future)
- ๐ฎ Multi-threaded contract resolution
- ๐ฎ Advanced pacing strategies
- ๐ฎ WebSocket alternative (if IBKR adds support)
๐ค Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Add tests for new functionality
- Ensure all tests pass (
pytest tests/) - Run linter (
ruff check src/) - Submit a pull request
๐ License
MIT License - see LICENSE file for details.
๐ Links
- market-data-core: https://github.com/mjdevaccount/market-data-core
- ib_insync Documentation: https://ib-insync.readthedocs.io/
- IBKR API Documentation: https://interactivebrokers.github.io/tws-api/
- Issues: https://github.com/YOUR_ORG/market-data-ibkr/issues
๐ฌ Support
For questions or issues:
- Check Troubleshooting section
- Search existing issues
- Open a new issue with:
- Python version
- IBKR Gateway/TWS version
- Minimal reproduction code
- Full error traceback
Happy Trading! ๐
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file market_data_ibkr-1.1.2.tar.gz.
File metadata
- Download URL: market_data_ibkr-1.1.2.tar.gz
- Upload date:
- Size: 28.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
191057856117bcf92e180c1db30c1a59f2afe0e039854437361b330a2e95bb6c
|
|
| MD5 |
01b1f77e7b57af881f22d0756c0b99ab
|
|
| BLAKE2b-256 |
fa58a92fc7e5baea8a8f1424654fbec1584cdf158c4ecd4a4145d115263f0bfa
|
File details
Details for the file market_data_ibkr-1.1.2-py3-none-any.whl.
File metadata
- Download URL: market_data_ibkr-1.1.2-py3-none-any.whl
- Upload date:
- Size: 23.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
498b8a8be631afd7a0bbea99a94378f1778c981368dbb9f7ec0adc8c29c3f25d
|
|
| MD5 |
fab7949be69e783ab8e159edc9e748fc
|
|
| BLAKE2b-256 |
743f8f4ef53563490f792aca93c2e5085bf4aff55007ba38091a4de463d2182a
|