@stoqey/ibkr
v2.8.4
Published
NodeJS Interactive Brokers wrapper & utilities using @stoqey/ib
Maintainers
Readme
Overview
A modern, TypeScript-based Node.js client for Interactive Brokers (IBKR) that provides a simplified interface to the IBKR API. This package is a wrapper around @stoqey/ib, which implements the official IBKR API. It offers a more developer-friendly way to interact with Interactive Brokers' trading platform, abstracting away the complexity of the underlying API.
Key Features
| | Feature | | :---: | -------------------------------------------------------- | | ✅ | Accounts and account update events | | ✅ | Portfolios, positions, and position update events | | ✅ | Orders, open-order updates, and completed trade events | | ✅ | Historical bars and historical ticks | | ✅ | Realtime bars and tick-by-tick price updates | | ✅ | Contract lookup and search for stocks/forex/options/etc. | | ✅ | Market-data-only mode for scanners and feeders | | ✅ | Contract allowlists for orders, positions, and data | | ⬜️ | Mosaic Market scanner | | ⬜️ | News |
1. Install
npm i @stoqey/ibkr2. Usage
Create a .env in the root dir of your project, set IBKR_HOST and IBKR_PORT, IBKR_CLIENT_ID(Optional, it'll use 0 by default), and DEBUG for logs, like this
IBKR_HOST=localhost
IBKR_PORT=7497
IBKR_CLIENT_ID=123
DEBUG=ibkr:*Optional connection settings:
IBKR_RECONNECT_INTERVAL=5000
IBKR_WATCHDOG_INTERVAL=1Initialize
import ibkr from '@stoqey/ibkr';
await ibkr();
// your codeYou can also pass @stoqey/ib IBApiNext creation options directly:
import ibkr from '@stoqey/ibkr';
await ibkr({
host: "127.0.0.1",
port: 7497,
reconnectInterval: 5000,
connectionWatchdogInterval: 1,
});Events
IBKREvents.Instance is the shared event bus. Managers keep their cached state up to date, and these events let your app react when that state changes:
| Event | Payload | When it emits |
| --- | --- | --- |
| IBKR_CONNECTED | none | Socket reconnects or finishes connecting |
| IBKR_ACCOUNT_UPDATED | { updatedAt } | Account summary cache changes |
| IBKR_POSITIONS_UPDATED | { updatedAt } | Position cache changes |
| IBKR_OPEN_ORDERS_UPDATED | { updatedAt } | Open-order cache changes |
| IBKR_COMPLETED_TRADES_UPDATED | { updatedAt } | Filled trade cache changes |
| IBKR_SAVE_TRADE | Trade | A filled order is converted to a trade |
| IBKR_BAR | MarketData | Realtime bar or tick-aggregated bar is cached |
import { IBKREvents, IBKREVENTS } from '@stoqey/ibkr';
import type { MarketData, Trade } from '@stoqey/ibkr';
const events = IBKREvents.Instance;
events.on(IBKREVENTS.IBKR_BAR, (bar: MarketData) => {
console.log(bar.instrument?.symbol, bar.close);
});
events.on(IBKREVENTS.IBKR_SAVE_TRADE, (trade: Trade) => {
console.log(trade.instrument?.symbol, trade.action, trade.quantity);
});Accounts Summary e.t.c
import { AccountSummary, IBKREvents, IBKREVENTS } from "@stoqey/ibkr";
const accountInstance = AccountSummary.Instance;
// account summaries is automatically updated for you
const accountSummaries = accountInstance.accountSummary;
const accountId = accountSummaries.accountId;
const totalCashValue = accountSummaries.TotalCashValue.value;
IBKREvents.Instance.on(IBKREVENTS.IBKR_ACCOUNT_UPDATED, () => {
console.log(accountInstance.accountSummary.NetLiquidation.value);
});Portfolios
import { Portfolios, IBKREvents, IBKREVENTS } from "@stoqey/ibkr";
// Get current portfolios
const portfolios = Portfolios.Instance;
// positions returns the latest cached snapshot
const accountPortfolios = portfolios.positions;
console.log(accountPortfolios);
IBKREvents.Instance.on(IBKREVENTS.IBKR_POSITIONS_UPDATED, () => {
const updatedPortfolios = portfolios.positions;
console.log(updatedPortfolios);
});Market Data
Historical bars
import { MarketDataManager } from '@stoqey/ibkr';
import { BarSizeSetting, WhatToShow } from '@stoqey/ib';
// 1. Get market data manager
const mkdManager = MarketDataManager.Instance;
// 2. Resolve an IBKR contract
const contract = await mkdManager.getContract({
symbol: "AAPL",
secType: "STK",
exchange: "SMART",
currency: "USD",
});
// 3. Get historical bars
const data = await mkdManager.getHistoricalData(
contract,
undefined,
"1 D",
BarSizeSetting.MINUTES_FIVE,
WhatToShow.TRADES,
true
);
Realtime bar updates
import { MarketDataManager, IBKREvents, IBKREVENTS } from '@stoqey/ibkr';
import type { MarketData } from '@stoqey/ibkr';
import { BarSizeSetting, WhatToShow } from '@stoqey/ib';
// 1. Get IBKR events
const ibkrEvents = IBKREvents.Instance;
// 2. Get market data manager
const mkdManager = MarketDataManager.Instance;
// 3. Request historical data updates
await mkdManager.getHistoricalDataUpdates(
contract,
BarSizeSetting.SECONDS_FIVE,
WhatToShow.TRADES
);
// 4. Subscribe for realtime bars
ibkrEvents.on(IBKREVENTS.IBKR_BAR, (bar: MarketData) => {
// use the realtime bar here
});
// 5. Get cached market data for a date range
const cachedData = await mkdManager.historicalData(contract, start, end);
// 6. Get the latest cached quote, or the quote at or before a timestamp
const latestQuote = await mkdManager.getQuote(contract);
const pointInTimeQuote = await mkdManager.getQuote(contract, new Date("2026-01-15T15:30:00Z"));
// Unsubscribe from historical data updates
mkdManager.removeHistoricalDataUpdates(contract);Tick-by-tick updates
getTickByTickDataUpdates subscribes to IBKR all-last ticks, updates portfolio market prices, aggregates ticks into one-second bars, caches those bars, and emits them through IBKR_BAR.
import { MarketDataManager, IBKREvents, IBKREVENTS } from '@stoqey/ibkr';
import type { MarketData } from '@stoqey/ibkr';
const ibkrEvents = IBKREvents.Instance;
const mkdManager = MarketDataManager.Instance;
ibkrEvents.on(IBKREVENTS.IBKR_BAR, (bar: MarketData) => {
console.log(bar.date, bar.close, bar.volume);
});
await mkdManager.getTickByTickDataUpdates(contract);
// Later, unsubscribe
mkdManager.removeTickByTickDataUpdates(contract);For historical tick data:
const ticks = await mkdManager.getHistoricalTicksLast(
contract,
new Date("2026-01-15T14:30:00Z"),
new Date("2026-01-15T15:30:00Z"),
1000,
false
);Market-data-only mode
Set MD_ONLY=true or IBKR_MD_ONLY=true before initialization when a process only needs contract lookup and market data:
IBKR_MD_ONLY=trueIn market-data-only mode, the package still connects to IBKR and initializes MarketDataManager. Contract lookup, contract details, historical data, realtime bars, historical ticks, and tick-by-tick market data remain available.
It skips account summary updates, account/portfolio subscriptions, open-order subscriptions, and order/trade event state. Use this for scanners, feeders, and symbol-search clients. Do not use it for execution clients that place orders or need live portfolio/order state.
Contract filtering
Set IBKR_CONTRACTS to a comma-separated allowlist when multiple apps share the same broker session but should only see or trade selected contracts:
IBKR_CONTRACTS=NQ-FUT,AAPL-STK,GC-FUTThe global filter applies to orders, positions, and market data. Filters are case-insensitive and can match:
- Symbol, such as
AAPL - Symbol/security type, such as
NQ-FUT - Symbol/security type/expiry, such as
NQ-FUT-202606orNQ-FUT-20260622 - Symbol/security type/exchange, such as
AAPL-STK-SMART - The package symbol key returned by
getSymbolKey
If one area needs a different allowlist, use a scoped override:
IBKR_CONTRACTS_ORDERS=NQ-FUT
IBKR_CONTRACTS_POSITIONS=NQ-FUT,GC-FUT
IBKR_CONTRACTS_MARKETDATA=*IBKR_CONTRACTS_ORDER, IBKR_CONTRACTS_POSITION, and IBKR_CONTRACTS_MD are also accepted aliases. * disables filtering for that scope. Account summary is account-level data from IBKR, so it is intentionally not contract-filtered; use separate accounts, allocation groups, or app-side risk budgets when each app needs isolated buying power.
Contracts
import { MarketDataManager } from '@stoqey/ibkr';
// 1. Get market data manager
const mkdManager = MarketDataManager.Instance;
const contract = {
symbol: "PLTR",
secType: "STK"
};
const contractDetails = await mkdManager.getContract(contract);
// or e.g options
const contractDetails = await mkdManager.getContract({
currency: 'USD',
exchange: 'SMART',
multiplier: 100,
right: 'C',
secType: 'OPT',
strike: 300,
symbol: 'AAPL'
});
// e.g forex
const contractDetails = await mkdManager.getContract({
"symbol":"GBP",
"secType":"CASH",
"currency":"USD",
});Use searchContracts when you need all matching contract details instead of only the first match:
const contracts = await mkdManager.searchContracts({
symbol: "ES",
secType: "FUT",
});Orders
import { MarketDataManager, Orders, IBKREvents, IBKREVENTS } from '@stoqey/ibkr';
import type { Trade } from '@stoqey/ibkr';
import { OrderAction, OrderType } from '@stoqey/ib';
// 1. Get IBKR events
const ibkrEvents = IBKREvents.Instance;
// 2. Get orders manager
const ordersManager = Orders.Instance;
// 3. Place order
const mkdManager = MarketDataManager.Instance;
const contract = await mkdManager.getContract({
symbol: "AAPL",
secType: "STK" /* STK, OPT, FUT, etc. */,
exchange: "SMART" /* SMART, NYSE, NASDAQ, etc. */,
currency: "USD" /* USD, EUR, GBP, etc. */
});
const price = 200;
const quantity = 1;
const myOrder = {
action: OrderAction.BUY,
totalQuantity: quantity,
orderType: price ? OrderType.LMT : OrderType.MKT,
...(price && { lmtPrice: price }),
transmit: true, // true to submit order immediately, false to save as draft
outsideRth: false, // true to allow execution outside regular trading hours, false otherwise
tif: "DAY", // DAY (day order), GTC (good till canceled), IOC (immediate or cancel), etc.
};
const placed = await ordersManager.placeOrder(contract, myOrder);
// 4. Modify order
const modifyOrder = await ordersManager.modifyOrder(id, contract, myOrder);
// get orders, this is automatically updated
const orders = ordersManager.orders;
// get filled orders(trades), this is automatically updated
const trades = ordersManager.trades;
// subscribe for trades, when orders are filled in real time
ibkrEvents.on(IBKREVENTS.IBKR_SAVE_TRADE, (trade: Trade) => {
// use trade here
});
ibkrEvents.on(IBKREVENTS.IBKR_OPEN_ORDERS_UPDATED, () => {
console.log(ordersManager.orders);
});
ibkrEvents.on(IBKREVENTS.IBKR_COMPLETED_TRADES_UPDATED, () => {
console.log(ordersManager.trades);
});
// other methods e.t.c....
await ordersManager.cancelOrder(orderId);
await ordersManager.cancelAllOrders({});Quickstart Sample App: See this API in action with our companion Sample Application.
Also, see any .test.ts file for examples
3. Debug
We use debug library for logging.
Run with DEBUG=ibkr:* to see all logs, or DEBUG=ibkr:info for less verbose logs.
See change log for updates
Community
Join our Discord community to get help, share ideas, and connect with other developers:
- Get help with implementation
- Share your projects
- Connect with other developers
- Stay updated on new releases
- Contribute to discussions
