Skip to content

Latest commit

 

History

History
871 lines (682 loc) · 18.4 KB

File metadata and controls

871 lines (682 loc) · 18.4 KB

📚 IBKR API Guide

Complete API documentation for the Interactive Brokers Trading API wrapper.


📋 Table of Contents


Overview

The IBKR API provides a RESTful interface to Interactive Brokers trading platform. All endpoints are asynchronous and return JSON responses.

Base URL: http://localhost:8000 (default)

Interactive Documentation:

  • Swagger UI: http://localhost:8000/docs
  • ReDoc: http://localhost:8000/redoc

Base URL & Authentication

Currently, the API runs locally without authentication. Ensure:

  • IB Gateway/TWS is running
  • API is enabled on port 4002 (Paper Trading) or 4001 (Live Trading)
  • Trusted IP 127.0.0.1 is configured

GET Endpoints

GET /account

Get account summary including balance and available cash.

Request:

GET /account

Response:

{
  "balance": 201879.04,
  "cash": 200000.0
}

Response Fields:

  • balance (float): Net liquidation value / total account equity
  • cash (float): Available funds for trading

Example:

curl http://localhost:8000/account

GET /positions

Get all open positions in the account.

Request:

GET /positions

Response:

{
  "positions": [
    {
      "symbol": "AAPL",
      "qty": 10,
      "avg_cost": 230.50,
      "market_value": 2305.00
    },
    {
      "symbol": "MSFT",
      "qty": -5,
      "avg_cost": 350.20,
      "market_value": -1751.00
    }
  ]
}

Response Fields:

  • positions (array): List of position objects
    • symbol (string): Stock symbol
    • qty (float): Position quantity (positive = long, negative = short)
    • avg_cost (float): Average cost per share
    • market_value (float): Total position value (qty × avg_cost)

Example:

curl http://localhost:8000/positions

GET /orders

Get all pending orders (orders that are not yet filled or cancelled).

Request:

GET /orders

Response:

{
  "orders": [
    {
      "orderId": 12345,
      "permId": 1788680597,
      "symbol": "AAPL",
      "action": "BUY",
      "quantity": 10,
      "type": "LMT",
      "trigger": 230.00,
      "status": "SUBMITTED"
    },
    {
      "orderId": 12346,
      "permId": 1788680598,
      "symbol": "TSLA",
      "action": "SELL",
      "quantity": 5,
      "type": "STP",
      "trigger": 250.00,
      "status": "PENDINGSUBMIT"
    }
  ]
}

Response Fields:

  • orders (array): List of pending order objects
    • orderId (int): Temporary order ID (changes on restart)
    • permId (int): Permanent order ID (use this for cancellation)
    • symbol (string): Stock symbol
    • action (string): "BUY" or "SELL"
    • quantity (float): Number of shares
    • type (string): Order type ("LMT", "MKT", "STP", etc.)
    • trigger (float|string): Limit price, stop price, or "—" for market orders
    • status (string): Order status ("PENDINGSUBMIT", "PRESUBMITTED", "SUBMITTED", "APIPENDING")

Order Statuses:

  • PENDINGSUBMIT: Order is being submitted
  • PRESUBMITTED: Order validated, waiting to be sent
  • SUBMITTED: Order sent to exchange
  • APIPENDING: Order pending API confirmation

Example:

curl http://localhost:8000/orders

GET /executions

Get execution history (filled orders) from multiple sources.

Request:

GET /executions
GET /executions?symbol=AAPL

Query Parameters:

  • symbol (string, optional): Filter executions by symbol (case-insensitive)

Response:

{
  "executions": [
    {
      "symbol": "AAPL",
      "side": "BUY",
      "qty": 10,
      "price": 230.50,
      "time": "20240115 14:30:25",
      "orderRef": "my_trade_001",
      "source": "reqExecutions"
    },
    {
      "symbol": "MSFT",
      "side": "SELL",
      "qty": 5,
      "price": 350.20,
      "orderId": 12345,
      "orderRef": "strategy_2",
      "source": "trades()"
    }
  ]
}

Response Fields:

  • executions (array): List of execution objects
    • symbol (string): Stock symbol
    • side (string): "BUY" or "SELL"
    • qty (float): Number of shares executed
    • price (float): Execution price
    • time (string, optional): Execution timestamp (format: "YYYYMMDD HH:MM:SS")
    • orderId (int, optional): Order ID
    • orderRef (string, optional): Order reference string
    • source (string): Data source ("reqExecutions", "trades()", "reqCompletedOrders", "positions()")

Note: Execution history resets when IB Gateway restarts. Consider saving executions to your own database.

Example:

# All executions
curl http://localhost:8000/executions

# Filtered by symbol
curl "http://localhost:8000/executions?symbol=AAPL"

POST Endpoints

POST /order/limit

Place a limit order (buy/sell at a specific price or better).

Request:

POST /order/limit
Content-Type: application/json

Request Body:

{
  "symbol": "AAPL",
  "action": "BUY",
  "quantity": 10,
  "limit_price": 230.00,
  "order_ref": "my_trade_001"
}

Request Fields:

  • symbol (string, required): Stock symbol (e.g., "AAPL")
  • action (string, required): "BUY" or "SELL"
  • quantity (float, required): Number of shares
  • limit_price (float, required): Limit price
  • order_ref (string, optional): Custom reference string for tracking

Response:

{
  "status": "✅ Limit order sent",
  "permId": 1788680597
}

Response Fields:

  • status (string): Success message
  • permId (int): Permanent order ID (use this to cancel the order)

Example:

curl -X POST http://localhost:8000/order/limit \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "limit_price": 230.00,
    "order_ref": "my_trade_001"
  }'

Error Responses:

  • 400 Bad Request: Invalid request parameters
  • 500 Internal Server Error: Order placement failed (check IB Gateway connection)

POST /order/market

Place a market order (buy/sell at current market price).

Request:

POST /order/market
Content-Type: application/json

Request Body:

{
  "symbol": "AAPL",
  "action": "BUY",
  "quantity": 10,
  "order_ref": "market_trade_001"
}

Request Fields:

  • symbol (string, required): Stock symbol
  • action (string, required): "BUY" or "SELL"
  • quantity (float, required): Number of shares
  • order_ref (string, optional): Custom reference string

Response:

{
  "status": "✅ Market order sent",
  "permId": 1788680598
}

Example:

curl -X POST http://localhost:8000/order/market \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "order_ref": "market_trade_001"
  }'

Note: Market orders execute immediately at the current market price. Use with caution as prices can vary.


POST /order/stop

Place a stop order (stop-loss order that triggers when price reaches stop price).

Request:

POST /order/stop
Content-Type: application/json

Request Body:

{
  "symbol": "AAPL",
  "action": "SELL",
  "quantity": 10,
  "stop_price": 225.00,
  "order_ref": "stop_loss_001"
}

Request Fields:

  • symbol (string, required): Stock symbol
  • action (string, required): "BUY" or "SELL"
  • quantity (float, required): Number of shares
  • stop_price (float, required): Stop price (triggers when price reaches this level)
  • order_ref (string, optional): Custom reference string

Response:

{
  "status": "✅ Stop order sent",
  "permId": 1788680599
}

Example:

curl -X POST http://localhost:8000/order/stop \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "AAPL",
    "action": "SELL",
    "quantity": 10,
    "stop_price": 225.00,
    "order_ref": "stop_loss_001"
  }'

Stop Order Behavior:

  • Stop-Loss (SELL): Triggers when price falls to or below stop price
  • Stop-Buy (BUY): Triggers when price rises to or above stop price

POST /order/bracket

Place a bracket order (entry order with automatic stop-loss and take-profit).

Request:

POST /order/bracket
Content-Type: application/json

Request Body:

{
  "symbol": "AAPL",
  "action": "BUY",
  "quantity": 10,
  "entry_price": 230.00,
  "stop_loss": 225.00,
  "take_profit": 240.00,
  "order_ref": "protected_trade_001"
}

Request Fields:

  • symbol (string, required): Stock symbol
  • action (string, required): "BUY" or "SELL"
  • quantity (float, required): Number of shares
  • entry_price (float, required): Entry limit price
  • stop_loss (float, required): Stop-loss price
  • take_profit (float, required): Take-profit price
  • order_ref (string, optional): Custom reference string

Response:

{
  "status": "✅ Bracket order sent",
  "permIds": [1788680600, 1788680601, 1788680602]
}

Response Fields:

  • status (string): Success message
  • permIds (array): List of 3 permanent order IDs:
    1. Parent order (entry)
    2. Stop-loss order
    3. Take-profit order

Example:

curl -X POST http://localhost:8000/order/bracket \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "entry_price": 230.00,
    "stop_loss": 225.00,
    "take_profit": 240.00,
    "order_ref": "protected_trade_001"
  }'

Bracket Order Behavior:

  • Entry order is placed first
  • When entry fills, stop-loss and take-profit orders are automatically activated
  • Only one of the exit orders will execute (whichever price is hit first)
  • The other exit order is automatically cancelled

POST /order/cancel

Cancel an order by its permanent ID.

Request:

POST /order/cancel
Content-Type: application/json

Request Body:

{
  "perm_id": 1788680597
}

Request Fields:

  • perm_id (int, required): Permanent order ID (from order placement response)

Response:

{
  "status": "✅ Order 1788680597 cancelled"
}

Example:

curl -X POST http://localhost:8000/order/cancel \
  -H "Content-Type: application/json" \
  -d '{"perm_id": 1788680597}'

Error Responses:

  • 404 Not Found: Order not found or already filled/cancelled
  • 500 Internal Server Error: Cancellation failed

Note: You can only cancel orders that are pending. Filled or already cancelled orders cannot be cancelled.


Response Formats

Success Response

All successful requests return HTTP 200 OK with JSON body:

{
  "status": "✅ Success message",
  "data": { ... }
}

Error Response

Errors return appropriate HTTP status codes with JSON body:

{
  "detail": "Error message description"
}

Common Status Codes:

  • 200 OK: Request successful
  • 400 Bad Request: Invalid request parameters
  • 404 Not Found: Resource not found
  • 500 Internal Server Error: Server error (check IB Gateway connection)

Error Handling

Connection Errors

If IB Gateway is not running or not accessible:

{
  "detail": "Failed to connect to IB Gateway"
}

Solution: Ensure IB Gateway/TWS is running and API is enabled.

Order Placement Errors

If order placement fails:

{
  "detail": "Failed to place limit order: Could not qualify contract for symbol: INVALID"
}

Common Causes:

  • Invalid symbol
  • Insufficient funds
  • Market closed
  • Contract not found

Order Cancellation Errors

If cancellation fails:

{
  "detail": "Order not found or already filled"
}

Common Causes:

  • Order already filled
  • Order already cancelled
  • Invalid permId

Code Examples

Python

import requests

BASE_URL = "http://localhost:8000"

# Get account summary
response = requests.get(f"{BASE_URL}/account")
account = response.json()
print(f"Balance: ${account['balance']:,.2f}")
print(f"Cash: ${account['cash']:,.2f}")

# Place limit order
order_data = {
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "limit_price": 230.00,
    "order_ref": "python_trade_001"
}
response = requests.post(f"{BASE_URL}/order/limit", json=order_data)
order_result = response.json()
print(f"Order placed: {order_result['permId']}")

# Get pending orders
response = requests.get(f"{BASE_URL}/orders")
orders = response.json()
print(f"Pending orders: {len(orders['orders'])}")

# Cancel order
cancel_data = {"perm_id": order_result['permId']}
response = requests.post(f"{BASE_URL}/order/cancel", json=cancel_data)
print(response.json()['status'])

JavaScript / Node.js

const axios = require('axios');

const BASE_URL = 'http://localhost:8000';

async function main() {
    // Get account summary
    const account = await axios.get(`${BASE_URL}/account`);
    console.log(`Balance: $${account.data.balance.toLocaleString()}`);
    console.log(`Cash: $${account.data.cash.toLocaleString()}`);

    // Place limit order
    const orderData = {
        symbol: 'AAPL',
        action: 'BUY',
        quantity: 10,
        limit_price: 230.00,
        order_ref: 'js_trade_001'
    };
    const orderResult = await axios.post(`${BASE_URL}/order/limit`, orderData);
    console.log(`Order placed: ${orderResult.data.permId}`);

    // Get pending orders
    const orders = await axios.get(`${BASE_URL}/orders`);
    console.log(`Pending orders: ${orders.data.orders.length}`);

    // Cancel order
    const cancelResult = await axios.post(`${BASE_URL}/order/cancel`, {
        perm_id: orderResult.data.permId
    });
    console.log(cancelResult.data.status);
}

main().catch(console.error);

cURL

# Get account
curl http://localhost:8000/account

# Place limit order
curl -X POST http://localhost:8000/order/limit \
  -H "Content-Type: application/json" \
  -d '{
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "limit_price": 230.00
  }'

# Get orders
curl http://localhost:8000/orders

# Cancel order
curl -X POST http://localhost:8000/order/cancel \
  -H "Content-Type: application/json" \
  -d '{"perm_id": 1788680597}'

Best Practices

1. Use Order References

Always include order_ref to track your orders:

import time

order_ref = f"strategy_1_{int(time.time())}"
order_data = {
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "limit_price": 230.00,
    "order_ref": order_ref
}

2. Check Account Before Trading

Verify sufficient funds before placing orders:

account = requests.get(f"{BASE_URL}/account").json()
required_cash = quantity * limit_price

if account['cash'] >= required_cash:
    # Place order
    pass
else:
    print("Insufficient funds!")

3. Use Bracket Orders for Risk Management

Protect your trades with automatic stop-loss and take-profit:

bracket_data = {
    "symbol": "AAPL",
    "action": "BUY",
    "quantity": 10,
    "entry_price": 230.00,
    "stop_loss": 225.00,   # -2.2% risk
    "take_profit": 240.00  # +4.3% reward
}

4. Save Executions to Database

Execution history resets when IB Gateway restarts. Save executions:

executions = requests.get(f"{BASE_URL}/executions").json()
for exec in executions['executions']:
    database.save(exec)  # Your database logic

5. Handle Errors Gracefully

Always handle potential errors:

try:
    response = requests.post(f"{BASE_URL}/order/limit", json=order_data)
    response.raise_for_status()
    result = response.json()
    print(f"Order placed: {result['permId']}")
except requests.exceptions.HTTPError as e:
    print(f"Error: {e.response.json()['detail']}")
except Exception as e:
    print(f"Unexpected error: {e}")

6. Monitor Order Status

Check order status before cancelling:

orders = requests.get(f"{BASE_URL}/orders").json()
pending_perm_ids = [o['permId'] for o in orders['orders']]

if perm_id in pending_perm_ids:
    # Safe to cancel
    requests.post(f"{BASE_URL}/order/cancel", json={"perm_id": perm_id})

7. Use Paper Trading First

Always test with Paper Trading (port 4002) before using Live Trading (port 4001).


Order Types Summary

Order Type Endpoint Use Case
Limit /order/limit Buy/sell at specific price or better
Market /order/market Immediate execution at market price
Stop /order/stop Stop-loss protection
Bracket /order/bracket Entry + stop-loss + take-profit

Rate Limits

Currently, there are no explicit rate limits. However:

  • Orders are processed sequentially (thread-safe queue)
  • Each request opens/closes IB connection
  • Avoid rapid-fire requests (add delays if needed)

Troubleshooting

Cannot Connect to IB Gateway

Symptoms: 500 Internal Server Error or connection timeout

Solutions:

  1. Verify IB Gateway/TWS is running
  2. Check API is enabled (Settings → API → Settings)
  3. Verify port: 4002 (Paper) or 4001 (Live)
  4. Add 127.0.0.1 to trusted IPs
  5. Test connection: telnet 127.0.0.1 4002

Orders Not Filling

Common Causes:

  • Price too far from market
  • Market closed (9:30 AM - 4:00 PM ET)
  • Insufficient funds
  • Stock halted/delisted

Solution: Check order status via /orders endpoint

Executions Not Showing

Explanation: Execution history resets when IB Gateway restarts

Solution: Save executions to your own database


Additional Resources


Support

For issues or questions:

  1. Check the troubleshooting section
  2. Review IB Gateway setup in IB_GATEWAY.md
  3. Test with Paper Trading first
  4. Check IB Gateway logs for detailed errors

⚠️ Disclaimer: This API is for educational purposes only. Trading involves risk of loss. Always test with Paper Trading first.