stoqey/ib Node.js Client Library

repository·master·Indexed 43 days ago

https://github.com/stoqey/ib

A TypeScript API client library for Node.js that ports the Interactive Brokers (IB) TWS/Gateway Java API. It provides two interfaces: IBApi, which replicates the official TWS API using an EventEmitter, and IBApiNext (Preview), a reactive API built on RxJS 7 using Promises and Observables. The library supports market data, portfolio management, and trading automation for Interactive Brokers.

Tokens
8K
Snippets
20
Records
38
Agent score
56%

What's inside stoqey/ib

  1. How the configuration system works

    master

    The configuration system compiles a single config object by layering multiple sources in a specific order of precedence. This allows you to define common defaults and override them for specific environments or local development.

    Precedence Order (Highest to Lowest):

    1. process.env environment variables (only those listed in envsToInclude in configuration.ts)
    2. Environment-specific JSON files (e.g., staging.json)
    3. local.json (used for local overrides, typically gitignored)
    4. default.json (contains common configuration and null keys for schema definition)
  2. Understand the difference between IBApi and IBApiNext

    master

    The package provides two distinct API interfaces:

    1. IBApi: Replicates the official TWS API as closely as possible. It uses a request/event design where you call functions and register event callbacks via an EventEmitter. This is ideal for migrating existing Java/C++ code.

    2. IBApiNext (Preview): A newer, usability-focused API built on RxJS 7. It moves away from the request/event model:

      • One-shot functions: Return a Promise (e.g., getCurrentTime, getContractDetails).
      • Endless stream subscriptions: Return an Observable (e.g., getAccountSummary, getMarketData). Note that the complete callback for these Observables will never be invoked; do not attempt to convert them to Promises.

    Note: IBApiNext is in preview and its interface may change.

  3. Manage local and secret configurations

    master

    Non-secret configurations

    Use default.json for common settings and environment-specific JSON files for environment-specific non-secret settings.

    Secret configurations

    Do not store secrets in JSON files. Use environment variables for all secret configurations. The configuration system will automatically include these in the final config object if they are registered in configuration.ts via the envsToInclude array.

    Local development overrides

    You can use local.json to store local-only configurations (both secret and non-secret). This file is ignored by git. Alternatively, you can use a .env file for local development.

  4. Set up local testing with IB Gateway Docker

    master

    To test locally, use the provided IB Gateway Docker container.

    WARNING: Always test on a papertrading account as tests may involve buying or selling financial instruments.

    1. Copy sample.env to .env and fill in your account info.
    2. Install dependencies: yarn.
    3. Compile TypeScript: yarn build.
    4. Start the container: docker-compose up (use -d for background mode).
    5. If using docker-compose, you may need to change IB_PORT from 4002 to 4004 in your .env.
    6. To stop the container: docker-compose down.

    To run existing Jest tests:

    • All tests: yarn test
    • Specific test file: jest src/test/unit/api/api.test.ts
  5. Configure environment-specific settings

    master
    To define settings for a specific environment, create a JSON file named exactly after that environment (e.g., staging.json or production.json). These files are layered on top of default.json and local.json during the configuration compilation process.
  6. Configure Time In Force (TIF) for orders

    master

    The tif property determines how long an order remains active. Valid values include:

    • DAY: Valid for the current trading day only.
    • GTC: Good until canceled. Automatically canceled if corporate actions occur, if you don't log in for 90 days, or at the end of the calendar quarter following the current quarter.
    • IOC: Immediate or Cancel. Any portion not filled immediately is canceled.
    • FOK: Fill-or-Kill. The entire order must execute immediately or the whole order is canceled.
    • GTD: Good until Date. Requires specifying goodTillDate.
    • OPG: Use for Market-on-Open (MOO) or Limit-on-Open (LOO) orders.
    • DTC: Day until Canceled.
  7. Run the IB API and TWS via Docker Compose

    master

    The project provides a docker-compose.yml configuration to orchestrate the Interactive Brokers (IB) Gateway/TWS and the ib-api service.

    Services

    • tws: Uses the industrialninja/ib_gateway:latest image. It maps a host port to the IB port (defaulting to 4002 if IB_PORT is not set in the environment). It requires a .env file for configuration.
    • ib-api: Built from the local directory using ./api.Dockerfile. It links to the tws service and sets IB_HOST=tws to allow the API to communicate with the gateway.

    Configuration Requirements

    • Environment Variables: A .env file must be present in the root directory to populate service configurations.
    • Volumes: The ib-api service mounts the current directory to /usr/src/app for development, including a specific volume for node_modules to prevent host-machine overrides from breaking the container's dependencies.
    version: "3.1"
    services:
      tws:
        image: industrialninja/ib_gateway:latest
        env_file: .env
        ports:
          - 4004:${IB_PORT:-4002}
        environment:
          - TZ=America/NewYork
    
      ib-api:
        container_name: ib-api
        build:
          context: .
          dockerfile: ./api.Dockerfile
        links:
          - tws
        env_file: .env
        environment:
          - IB_HOST=tws
        volumes:
          - .:/usr/src/app
          - /usr/src/app/node_modules
        depends_on:
          - tws
  8. Migrate from 1.1.x to 1.2.x (Breaking Change)

    master

    In versions 1.2.1 and later, values that are not available no longer return Number.MAX_VALUE (to match the Java API). Instead, they return undefined.

    If your code checks for Number.MAX_VALUE, you must update it to check for undefined.

    Example Change:

    Old (1.1.x):

    ib.on(EventName.pnlSingle, (reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value) => {
      // unrealizedPnL and realizedPnL might be Number.MAX_VALUE
    });

    New (1.2.x+):

    ib.on(EventName.pnlSingle, (reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value) => {
      // unrealizedPnL and realizedPnL might be undefined
    });
  9. Send an order using IBApi

    master

    To place an order, first obtain a valid order ID using reqIds() and listen for the nextValidId event. Then, construct a Contract and an Order object and pass them to placeOrder().

    ib.once(EventName.nextValidId, (orderId: number) => {
      const contract: Contract = {
        symbol: "AMZN",
        exchange: "SMART",
        currency: "USD",
        secType: SecType.STK,
      };
    
      const order: Order = {
        orderType: OrderType.LMT,
        action: OrderAction.BUY,
        lmtPrice: 1,
        orderId,
        totalQuantity: 1,
        account: "YOUR_ACCOUNT_ID",
      };
    
      ib.placeOrder(orderId, contract, order);
    });
    
    ib.connect();
    ib.reqIds();
  10. Use IBApi to print portfolio positions

    master

    To use the standard IBApi, instantiate the class, register event handlers using .on() or .once(), and call the necessary API methods.

    import { IBApi, EventName, ErrorCode, Contract } from "@stoqey/ib";
    
    // create IBApi object
    const ib = new IBApi({
      // clientId: 0,
      // host: '127.0.0.1',
      port: 7497,
    });
    
    // register event handler
    let positionsCount = 0;
    
    ib.on(EventName.error, (err: Error, code: ErrorCode, reqId: number) => {
      console.error(`${err.message} - code: ${code} - reqId: ${reqId}`);
    })
      .on(
        EventName.position,
        (account: string, contract: Contract, pos: number, avgCost?: number) => {
          console.log(`${account}: ${pos} x ${contract.symbol} @ ${avgCost}`);
          positionsCount++;
        },
      )
      .once(EventName.positionEnd, () => {
        console.log(`Total: ${positionsCount} positions.`);
        ib.disconnect();
      });
    
    // call API functions
    ib.connect();
    ib.reqPositions();
    import { IBApi, EventName, ErrorCode, Contract } from "@stoqey/ib";
    
    const ib = new IBApi({
      port: 7497,
    });
    
    let positionsCount = 0;
    
    ib.on(EventName.error, (err: Error, code: ErrorCode, reqId: number) => {
      console.error(`${err.message} - code: ${code} - reqId: ${reqId}`);
    })
      .on(
        EventName.position,
        (account: string, contract: Contract, pos: number, avgCost?: number) => {
          console.log(`${account}: ${pos} x ${contract.symbol} @ ${avgCost}`);
          positionsCount++;
        },
      )
      .once(EventName.positionEnd, () => {
        console.log(`Total: ${positionsCount} positions.`);
        ib.disconnect();
      });
    
    ib.connect();
    ib.reqPositions();
  11. Configure IB socket ports

    master

    When connecting to Interactive Brokers, use the following ports based on your account type and platform:

    PlatformPort
    IB Gateway live account4001
    IB Gateway paper account4002
    TWS Live Account7496
    TWS papertrading account7497