Code Monkey home page Code Monkey logo

ibkr's Introduction

IBKR: Interactive Brokers

NPM

Run IBKR in style

This is an event-based ibkr client for node

Feature
โœ… Accounts
โœ… Portfolios
โœ… Orders
โœ… Historical Data
โœ… Realtime price updates
โœ… Contracts (stocks/forex/options/index .e.t.c)
โœ… Mosaic Market scanner
โฌœ๏ธ News

1. Install

npm i @stoqey/ibkr

2. Usage

Initialize

import ibkr, { AccountSummary, IBKREVENTS, IbkrEvents, PortFolioUpdate, getContractDetails } from '@stoqey/ibkr';

const ibkrEvents = IbkrEvents.Instance;


// 0. Using env process.env.IB_PORT and process.env.IB_HOST
await ibkr();

// 1. Async 
await ibkr({ port: IB_PORT, host: IB_HOST });

// 2. Callback
ibkr({ port: IB_PORT, host: IB_HOST }).then(started => {
  
    if(!started){
          // Error IBKR has not started
          console.log('error cannot start ibkr');
        //   Not to proceed if not connected with interactive brokers
          return process.exit(1);
    }

    // Your code here

})

Accounts, Summary e.t.c

const accountId = AccountSummary.Instance.accountSummary.AccountId;
const totalCashValue = AccountSummary.Instance.accountSummary.TotalCashValue;

Portfolios

// Get current portfolios
const portfolios = Portfolios.Instance;
const accountPortfolios = await portfolios.getPortfolios();

// Subscribe to portfolio updates
ibkrEvents.on(IBKREVENTS.PORTFOLIOS, (porfolios: PortFolioUpdate[]) => {
      // use porfolios  updates here
})

Historical Data + Realtime price updates

  • Market data
import { HistoricalData } from '@stoqey/ibkr';

// 1. Init
const historyApi = HistoricalData.Instance;

const args = {
  symbol,
  // contract: ib.contract.stock("AAPL"),
  endDateTime = '',
  durationStr = '1 D',
  barSizeSetting = '1 min',
  whatToShow = 'ASK'
};

// 2. Get market data async promise
const data = await historyApi.reqHistoricalData(args);

// OR 

// 3.1 Request for market data using events
historyApi.getHistoricalData(args);
ibkrEvents.emit(IBKREVENTS.GET_MARKET_DATA, args); // the same

// 3.2. Subscribe to market data results
ibkrEvents.on(IBKREVENTS.ON_MARKET_DATA, ({ symbol, marketData }) => {
    //  Use the data here
})
  • Real-time price updates
import { PriceUpdates } from '@stoqey/ibkr';

PriceUpdates.Instance; // init

// subscribe for price updates
ibkrEvents.on(IBKREVENTS.ON_PRICE_UPDATES, (priceUpdates) => {
     // use the price updates here
 });

//  Request price updates
ibkrEvents.emit(IBKREVENTS.SUBSCRIBE_PRICE_UPDATES, { symbol: 'AAPL' });
// Unsubscribe from price updates
ibkrEvents.emit(IBKREVENTS.UNSUBSCRIBE_PRICE_UPDATES, symbol);

Contracts

 
const contractDetails = await getContractDetails(ib.contract.stock("AAPL"));

//  or e.g options
const contractDetails = await getContractDetails({
    currency: 'USD',
    exchange: 'SMART',
    multiplier: 100,
    right: 'C',
    secType: 'OPT',
    strike: 300,
    symbol: 'AAPL'
});

// e.g forex
const contractDetails = await getContractDetails({
    "symbol":"GBP",
    "secType":"CASH",
    "currency":"USD",
     // "localSymbol":"GBP.USD",
});


// or with just a symbol, defaults to stocks
 const contractDetails = await getContractDetails('AAPL');

Orders

import { Orders, OrderStock } from '@stoqey/ibkr';

const orderTrade = Orders.Instance;

const myStockOrder: OrderStock = { ... }

const placedOrder = await orderTrade.placeOrder(myStockOrder);
          

OrderStock

const stockOrderBuyOut: OrderStock = {
    symbol: symbol,
    action: "SELL",
    type: "limit",
    parameters: ["1", "9999"], // 'SELL', 1, 9999,
}

type

  • limit ('SELL', 1, 9999) like in example above
  • market (action, quantity, transmitOrder, goodAfterTime, goodTillDate)
  • marketClose (action, quantity, price, transmitOrder)
  • stop (action, quantity, price, transmitOrder, parentId, tif)
  • stopLimit (action, quantity, limitPrice, stopPrice, transmitOrder, parentId, tif)
  • trailingStop (action, quantity, auxPrice, tif, transmitOrder, parentId)

Order events

  • Order filled
ibkrEvents.on(IBKREVENTS.ORDER_FILLED, (data) => {

});
  • Order status
ibkrEvents.on(IBKREVENTS.ORDER_STATUS, (data) => {

});
  • Open Orders updates
ibkrEvents.on(IBKREVENTS.OPEN_ORDERS, (data) => {

});

Mosaic Scanner

import { MosaicScanner } from '@stoqey/ibkr';
const mosaicScanner = new MosaicScanner();

const scannerData = await mosaicScanner.scanMarket({
      instrument: 'STK',
      locationCode: 'STK.US.MAJOR',
      numberOfRows: 10,
      scanCode: 'TOP_PERC_GAIN',
      stockTypeFilter: 'ALL'
})

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.

Stoqey Inc

ibkr's People

Contributors

anri-asaturov avatar ceddybi avatar ellis avatar gh-action-bump-version avatar tsopic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

ibkr's Issues

Searching securities

Hi there, first off I'd like to say amazing work on that wrapper so far. Being new to IBKR and their API I was wondering if there was any way to search securities via their API, and if there is does that wrapper implement it ?

What's a good way to get price data (high, low, open, close, etc)?

I want to get the high, low, open, close, etc prices for my portfolio. I didn't see a good way to do this with @stoqey/ibkr, so I wrote the following self-contained prototype with @stoqey/ib to figure out how thinks work on a lower level. It grabs the price data once for AAPL and prints it to the screen. I'd like to do something similar with ibkr, but the current implementation of IBKREVENTS.SUBSCRIBE_PRICE_UPDATES only seems to emit events for a single element of the price. Can you give me a tip for how to use ibrk and tie into it's low-level interface when necessary?

import IB from "@stoqey/ib";

type Exchange =
	| "SMART"
	/** Forex cash exchange */
	| "IDEALPRO"
	/** Briefing Trader News */
	| "BRF";

type PrimaryExchange = "IDEALPRO" | "NASDAQ" | "NYSE";

type SecType = "CASH" | "FUT" | "NEWS" | "OPT" | "STK";

interface MktData {
	/** The last available closing price for the previous day. For US Equities, we use corporate action processing to get the closing price, so the close price is adjusted to reflect forward and reverse splits and cash and stock dividends. (9) */
	readonly closePrice?: number;
	/** Delayed bid price. (66) */
	readonly delayedBid?: number;
	/** Delayed ask price. (67) */
	readonly delayedAsk?: number;
	/** Delayed last traded price. (68) */
	readonly delayedLast?: number;
	/** Delayed highest price of the day. (72) */
	readonly delayedHighPrice?: number;
	/** Delayed lowest price of the day. (73) */
	readonly delayedLowPrice?: number;
	/** Delayed traded volume of the day. (74) */
	readonly delayedVolume?: number;
	/** The prior day's closing price. (75) */
	readonly delayedClose?: number;
}

type ResultHandlerCallbackFunction = (requestId: number, args: readonly any[]) => void;

interface ResultHandlerCallbackMap {
	[event: string]: {
		[requestId: string]: ResultHandlerCallbackFunction;
	};
}

let globalRequestIdNext = 10000;

const resultHandlerCallbacks: ResultHandlerCallbackMap = {};

async function run(): Promise<void> {
	const ib = new IB({
		// clientId: 0,
		// host: '127.0.0.1',
		// port: 7496
	})
		.on("connected", function () {
			console.log("CONNECTED");
		})
		.on("disconnected", function () {
			console.log("DISCONNECTED");
		})
		.on("received", function (tokens: any) {
			console.info("%s %s", "<<< RECV <<<", JSON.stringify(tokens));
		})
		.on("sent", function (tokens: any) {
			console.info("%s %s", ">>> SENT >>>", JSON.stringify(tokens));
		})
		.on("server", function (version: any, connectionTime: any) {
			console.log(`Server Version: ${version}`);
			console.log(`Server Connection Time: ${connectionTime}`);
		})
		.on("error", function (err: any) {
			console.error(`@@@ ERROR: ${err.message} @@@`);
		})
		.on("result", function (event: string, args: readonly any[]) {
			console.log(`======= ${event} =======`);
			args.forEach(function (arg: any, i: number) {
				console.log("%s %s", `[${i + 1}]`, JSON.stringify(arg));
			});

			if (typeof args[0] === "number") {
				const requestId = args[0];
				const [, ...rest] = args;
				const callback = resultHandlerCallbacks[event]?.[requestId.toString()];
				if (callback) {
					callback(requestId, rest);
				}
			}
		});

	ib.connect();
	ib.reqMarketDataType(4); // marketDataType (1=live, 2=frozen, 3=delayed, 4=delayed/frozen)

	const result = await getMktData(ib, {
		exchange: "SMART",
		primaryExch: "NASDAQ",
		secType: "STK",
		symbol: "AAPL",
		currency: "USD",
	});
	console.log("result:", result);
}

/**
 * Requests market data (price, bid, ask)
 */
function getMktData(
	ib: IB,
	args: {
		readonly exchange: Exchange;
		readonly primaryExch: PrimaryExchange;
		readonly secType: SecType;
		readonly symbol: string;
		readonly currency?: string;
	}
): Promise<MktData> {
	const requestId = globalRequestIdNext++;
	return new Promise((res) => {
		// see https://interactivebrokers.github.io/tws-api/tick_types.html
		const tickPriceData: { [tickType: string]: number } = {};
		const expecting = new Set<number>(
			args.secType === "STK"
				? [66, 67, 68, 72, 73, 74, 75, 88]
				: args.secType === "CASH"
				? [9]
				: [-1]
		);

		let isDone = false;
		const done = async () => {
			if (!isDone) {
				isDone = true;
				unsetResultHandlerCallback("tickPrice", requestId);
				unsetResultHandlerCallback("tickSize", requestId);
				unsetResultHandlerCallback("tickString", requestId);
				ib.cancelMktData(requestId);
				res({
					closePrice: tickPriceData["9"],
					delayedBid: tickPriceData["66"],
					delayedAsk: tickPriceData["67"],
					delayedLast: tickPriceData["68"],
					delayedHighPrice: tickPriceData["72"],
					delayedLowPrice: tickPriceData["73"],
					delayedVolume: tickPriceData["74"],
					delayedClose: tickPriceData["75"],
				});
			}
		};

		const addNumber = async (tickType: number, value: number) => {
			tickPriceData[tickType.toString()] = value;
			expecting.delete(tickType);
			if (expecting.size === 0) {
				await done();
			}
		};

		const addString = async (tickType: number, value: string) => {
			// tickPriceData[tickType.toString()] = value;
			expecting.delete(tickType);
			if (expecting.size === 0) {
				await done();
			}
		};

		async function callback_tickPrice(
			requestId: number,
			[tickType, price, attrib]: [number, number, boolean]
		): Promise<void> {
			console.log("tickPrice:", { requestId, tickType, price, attrib });
			await addNumber(tickType, price);
		}
		async function callback_tickSize(
			requestId: number,
			[tickType, size]: [number, number]
		): Promise<void> {
			console.log("tickSize:", { requestId, tickType, size });
			await addNumber(tickType, size);
		}
		async function callback_tickString(
			requestId: number,
			[tickType, value]: [number, string]
		): Promise<void> {
			console.log("tickString:", { requestId, tickType, value });
			await addString(tickType, value);
			// console.log("DONE: ", requestId, tickPriceData);
		}

		setResultHandlerCallback("tickPrice", requestId, callback_tickPrice);
		setResultHandlerCallback("tickSize", requestId, callback_tickSize);
		setResultHandlerCallback("tickString", requestId, callback_tickString);

		ib.reqMktData(
			requestId,
			{
				currency: args.currency,
				exchange: args.exchange,
				primaryExch: args.primaryExch,
				secType: args.secType,
				symbol: args.symbol,
			},
			"",
			false,
			false
		); // requestId, contract, genericTickList, snapshot, snapshot2

		// Force the end in 10 seconds
		setTimeout(done, 10 * 1000);
	});
}

function setResultHandlerCallback(
	event: string,
	requestId: number,
	callback: ResultHandlerCallbackFunction
): void {
	if (!(event in resultHandlerCallbacks)) {
		resultHandlerCallbacks[event] = {};
	}
	resultHandlerCallbacks[event][requestId] = callback;
}

function unsetResultHandlerCallback(event: string, requestId: number): void {
	if (resultHandlerCallbacks[event]?.[requestId]) {
		delete resultHandlerCallbacks[event][requestId];
	}
}

run();

Concurrent orders

  • Place multiple orders for same symbol
  • Set filter duplicate flag
  • Cancel order

OrderState commission prices are incorrect scientific notation numbers

Hello! Thanks for building such a great and thorough library. I'm seeing this bug when executing any order on my paper trading account:

const ib = new IBApi({port: PORT})
ib.connect(clientId)
ib.on(EventName.openOrder, (orderId, contract, order, orderState) => {
  console.log(orderState)
})


=> {
  status: 'PreSubmitted',
  initMarginBefore: 1.7976931348623157e+308,
  maintMarginBefore: 1.7976931348623157e+308,
  equityWithLoanBefore: 1.7976931348623157e+308,
  initMarginChange: 1.7976931348623157e+308,
  maintMarginChange: 1.7976931348623157e+308,
  equityWithLoanChange: 1.7976931348623157e+308,
  initMarginAfter: 1.7976931348623157e+308,
  maintMarginAfter: 1.7976931348623157e+308,
  equityWithLoanAfter: 1.7976931348623157e+308,
  commission: 1.7976931348623157e+308,
  minCommission: 1.7976931348623157e+308,
  maxCommission: 1.7976931348623157e+308,
  commissionCurrency: '',
  warningText: ''
}

If I was being charged fees totalling more than the GDP of every nation in the world, I'd be a bit annoyed ๐Ÿ˜‰ I'm not sure what the issue is.

My real account is a standard individual's account with the Pro tier. Orders executed both in the API and manually produce actual fees of USD$1.00 (in the real account; not sure how to see fees in Trader Workstation to verify what the paper trading account's fees are.)

Cannot initialize project - ibkr() is not a function and node:11784

The code snippet given in the README.MD is giving several different errors. Tried with a fresh NodeJS TS project.

I spent quite some time tinkering aroud, first it said cannot use import statement outside a module. Here's the error:

(node:11784) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
E:\work\robinhood\exp\exp1ts\dist\app.js:18
import ibkr, { IbkrEvents } from '@stoqey/ibkr';
^^^^^^

SyntaxError: Cannot use import statement outside a module

Later when you change the type to module, it says ibkr() is not a function! Here's the error:

await ibkr();
      ^

TypeError: ibkr is not a function

Even if we decide to change the import to regular require() statement, tsc starts to complain about using TLA/top-level-awaits, because the file is not a module. The error given:

> tsc && node dist/app.js

src/app.ts:32:1 - error TS1375: 'await' expressions are only allowed at the top level of a file when that file is a module, but this file has no imports or exports. Consider adding an empty 'export {}' to make this file a module.

32 await ibkr();

After some tinkering around, I managed to make it work with the following code, which is not very pretty:

const ibkr = require('@stoqey/ibkr');
const { AccountSummary, IBKREVENTS, IbkrEvents, PortFolioUpdate, getContractDetails } = ibkr;

const ibkrEvents = IbkrEvents.Instance;
const IB_HOST = "localhost";
const IB_PORT = 7496;

ibkr.default({ port: IB_PORT, host: IB_HOST })
  .then((v) => {
    const accountId = AccountSummary.Instance.accountSummary.AccountId;
    const totalCashValue = AccountSummary.Instance.accountSummary.TotalCashValue;

    console.log("acc id: " + accountId)
    console.log("cashVal: " + totalCashValue)
    console.log(v)
  })
  .catch((e) => {
    console.log("Connection Failed.");
    console.log(e);
  });

Can you please explain or please create a more detailed get started guide?

Also in my code, or in general, how can I handle/catch and sudden TWS/API connection lost? This is critical, because at the moment the program just ends.

Thanks for your support!

node: 14.15.1
os: win10pro 64bit

Deadlook in reqHistoricalData with invalid requests

If an invalid combination of parameters or invalid strings are passed to the reqHistoricalData function, there is a deadlook.

Example

import ibkr, { IBKRConnection, IbkrEvents, HistoricalData } from '@stoqey/ibkr';

const ibkrEvents = IbkrEvents.Instance;


const main = async () => {
  // @ts-ignore
  const connectionStatus = await ibkr({ port: 7496, host: '127.0.0.1' });

  HistoricalData.Instance;

  const symbol = 'aapl'

  const data = await HistoricalData.Instance.reqHistoricalData({
    symbol,
    endDateTime: '',
    durationStr: '1 W',
    barSizeSetting: '1 day',
    //whatToShow: 'TRADES',
    whatToShow: 'YIELD_BID'
  })
  console.log(data)
  IBKRConnection.Instance.disconnectIBKR()
};

main();

The log writes the error in debug mode, but there is no error from the Promise

Log

error Historical Market Data Service error message:No historical market data for AAPL/STK@NASDAQBBO BidYield 1d

I have not yet checked if there are exceptions in other functions.

Not an issue

Hello, @ceddybi, good man!
I was just in the beginning of writing a npapi plugin based on TWS c++ client, when I finally found this, and it is so much better.

Did you run this client live?
Is it somewhat tested and reliable?
How do you plan to keep it up to date with the official protocol/clients?

I'll def be contributing if I end up using it for my algos.
Thank you!

getContractDetails should be able to deliver several contracts

With getContractDetails it is currently not possible to deliver multiple ContractDetails like an option chain.

{
  currency: 'USD',
  exchange: 'SMART',
  //expiry: '202007',
  multiplier: 100,
  right: 'C',
  secType: 'OPT',
  strike: 300,
  symbol: 'AAPL'
}

Currently this query returns 16 options in the TWS API but getContractDetails returns only one of them.

Compatible with IBeam?

Hey,

I'm running IBeam and Node in Docker compose. When I try to connect to my IBeam gateway nothing happens. Even though I have set DEBUG=ibkr* env variable.

I use the following code with node18:

import ibkr, { AccountSummary, IBKREVENTS, IbkrEvents, PortFolioUpdate, getContractDetails } from '@stoqey/ibkr';

const ibkrEvents = IbkrEvents.Instance;

console.log('connecting ibkr');

ibkr({ port: 5000, host: 'ibeam' })
  .then(started => {
    if (!started) {
      // Error IBKR has not started
      console.log('error cannot start ibkr');
      //   Not to proceed if not connected with interactive brokers
      return process.exit(1);
    } else {
      console.log('ibkr agent started');
    }

    // subscribe for price updates
    ibkrEvents.on(IBKREVENTS.ON_PRICE_UPDATES, priceUpdates => {
      console.log(priceUpdates);
      // use the price updates here
    });

    //  Request price updates
    ibkrEvents.emit(IBKREVENTS.SUBSCRIBE_PRICE_UPDATES, { symbol: 'AAPL' });
  })
  .catch(e => {
    console.error(e);
  });

What my console logs is only "connecting ibkr".

I've tried to wait for over 10 minutes. If I change the host or port, I get errors so I guess those are correct. Is there a timeout for the requests?

Can't get PriceUpdates to work

I have the following code:

const ibkr = require('@stoqey/ibkr').default
const {
  AccountSummary,
  IBKREVENTS,
  IbkrEvents,
  HistoricalData,
  PriceUpdates,
  Portfolios,
  MosaicScanner,
} = require('@stoqey/ibkr')
const ibkrEvents = IbkrEvents.Instance

const getPriceUpdates = async (params) => {
  try {
    const connected = await ibkr()
    console.log('Connected to IBKR API : ',connected)

     PriceUpdates.Instance

    ibkrEvents.on(IBKREVENTS.ON_PRICE_UPDATES, (priceUpdates) => {
      // use the price updates here
      console.log(priceUpdates)
    })
    ibkrEvents.emit(IBKREVENTS.SUBSCRIBE_PRICE_UPDATES, {
      symbol: 'QQQ',
    })
  } catch (e) {
    console.error(e)
  }
}

When I call getPriceUpdates i get the following:
Connected to IBKR API : true
{ symbol: 'QQQ' }

No price updates or any data is logged...Any help?

AccountSummary only returns data from 1 account for clients with multiple account IDs

For clients with multiple accounts (eg separate IRA and brokerage accounts), the AccountSummary class will only return data from one of their accounts, when issuing init or getAccountSummary

Reason:
IBKR callback accountSummary is called for each account, yet the result overwrites each time so only the data from the last account will be returned.

eg in src/account/AccountSummary:

 // Record values from here
        ib.on('accountSummary', (reqId, account, tag, value, currency) => {
            self.tickerId = reqId;
            self.AccountId = account;
            self.accountSummary.AccountId = account;
            self.accountSummary[tag] = value; // set the account value
            self.accountSummary.Currency = currency; // always set the account currency
            // log('accountSummaryEnd', { account, tag, value, });
        });

        // Return values from here
        ib.once('accountSummaryEnd', () => {
            const {AccountId = 'unknown', tickerId, accountReady, accountSummary} = self;

            log('accountSummaryEnd', {AccountId, tickerId, accountReady});

            ib.cancelAccountSummary(tickerId);

            publishDataToTopic({
                topic: IBKREVENTS.ON_ACCOUNT_SUMMARY,
                data: accountSummary,
            });

            self.accountReady = true;
        });

Solution:
make self.accountSummary an object with accountId as keys. Store data from each accountSummary callback under the right key (so adding a [tag] key under that accountId). Only resolve promise of getAccountSummary or call publishDataToTopic after you receive an accountSummaryEnd since only then will you have received data from all accountIds for the currently logged in user.

Here is a gist with a corrected AccountSummary.ts. Note that I also first-letter-lowercased the returned tags to be more JS-style compliant, so you will need to make some changes to the interface file and some other files also that use accountId which has been replaced by accountIds. For instance you will need to change Portfolios so it takes an accountId as an input so you can return a portfolio per account.

https://gist.github.com/bayareacoder/0f173afe96f2a601e21d6f581396f739#file-accountsummary-ts

Please stop using console.log and chalk

Currently the ibkr writes a lot of text with chalk on the console, which cannot be deactivated. Better would be an output with debug or a deactivation of the console log.

stock and option contract for the same ticker

Hello,
I have a stock position for ticker X and a open option position for the same ticker X.
When I retrieve my portfolios, I can only see one.

Do you have any suggestions?
Cheers

Is there a way to use this with nodejs without having to use typescritp?

Can this package be used without typescript?

const { ibkr, AccountSummary, IBKREVENTS, IbkrEvents, PortFolioUpdate, getContractDetails } = require('@stoqey/ibkr')
async f() {
   await ibkr({ port: 7496, host: '127.0.0.1' })

    const accountId = AccountSummary.Instance.accountSummary.AccountId;
    const totalCashValue = AccountSummary.Instance.accountSummary.TotalCashValue;

    console.log('acc id:' + accountId)
}
f()
(node:20068) UnhandledPromiseRejectionWarning: TypeError: ibkr is not a function

`comboLegsDescrip` in `ContractObject` should be optional

Hi there, and thanks for your work on this library! I was trying it out for saving some of my IB data, and it looks like the comboLegsDescrip isn't always present for ContractObjects. Would you be able to make it an option parameter in the interface?

Property 'on' does not exist on type 'IbkrEvents'

import ibkr, {AccountSummary, IBKREVENTS, IbkrEvents, PortFolioUpdate, getContractDetails,HistoricalData } from '@stoqey/ibkr';
const ibkrEvents = IbkrEvents.Instance;

// 3.2. Subscribe to market data results
    ibkrEvents.on(IBKREVENTS.ON_MARKET_DATA, ({ symbol, marketData }) => {
        //  Use the data here
        console.log("symbol:",symbol);
        console.log("marketData:",marketData);
    });

show error:
Property 'on' does not exist on type 'IbkrEvents'

ibkr().then not working

import ibkr,{IBKREVENTS, IbkrEvents, HistoricalData} from '@stoqey/ibkr';

const ibkrEvents = IbkrEvents.Instance;

ibkr({host:'127.0.0.1',port:4001}) // add your port and  host if you want
    .then((started: boolean) => {
        console.log('done', started);
        const symbol = 'PPSI';

        HistoricalData.Instance; // initialize HistoricalData module
        // Request for market data
        ibkrEvents.emit(IBKREVENTS.GET_MARKET_DATA, {
            symbol,
            whatToShow: 'TRADES',
            durationStr: '3600 S',
            barSizeSetting: '5 secs',
        });

        // get the market data
        ibkrEvents.on(
            IBKREVENTS.ON_MARKET_DATA,
            async ({symbol, marketData}: {symbol: string; marketData: any[]}) => {
                console.log('data', {symbol, marketData: marketData.length});
            }
        );
    })
    .catch((e: Error) => {
        console.log('error starting  ibkr', e);
    });

after runing ๏ผŒno anything output:
image

Order values are in max_int

I'm testing the order entry and event that confirms Fill has MAX int values. What should I do?

trailStopPrice: 1.7976931348623157e+308,
trailingPercent: 1.7976931348623157e+308,
basisPoints: 1.7976931348623157e+308,
basisPointsType: 1.7976931348623157e+308,
scaleInitLevelSize: 1.7976931348623157e+308,
scaleSubsLevelSize: 1.7976931348623157e+308,
scalePriceIncrement: 1.7976931348623157e+308,

How to contribute?

I'd like to fix some stuff with historical Data, but current repo settings does not allow me to create push to separate branch for PR

Issues with account portfolio code

It seems to me there are a few issues inPortfolio.ts to retrieve an account's portfolio:

  • init issues reqAccountUpdates and listens for updatePortfolio.
  • on each updatePortfolio (which is a callback for each position in the portfolio), there is a nested call to self.getPortfolios which by itself then issues reqPositions with separate listeners.

Per: http://interactivebrokers.github.io/tws-api/account_updates.html, reqAccountUpdates will already receive updatePortfolio for each position in the account, and then a accountDownloadEnd when all data is received (for which there is no listener in the current code). So it seems to me there is no need to also use reqPositions.

It's not clear to me how to make a distinction between an initial snapshot and later updates to the portfolio as there is only 1 event topic IBKREVENTS.PORTFOLIO. So how to know if it's a full portfolio download or an update with only a change?

I also wouldn't think you need separate listeners for filled orders, since I'd expect that would trigger updatePortfolio callback automatically if a subscription is setup, see below.

Per #66 accountId should also be an input to Portfolio class to support clients with multiple accounts so you can retrieve the portfolio per account (probably passing accountId in the Portfolio constructor so you get a portfolio instance per accountId will be easiest, and then can do a subscription per accountId), see next point.

You should be able to either only get a full snapshot of the portfolio, or do a subscription so that after an initial snapshot you continue to get portfolio updates, and then be able to stop that subscription at a later time.

PS
I would call the class Portfolio instead of Portfolios if implemented per above (a portfolio assumes there are multiple positions).

I'm working on a re-write.

contract 'right' attribute is always undefined for options

Hi,
Great work on this project! Thank you for making our lives easier!

I have a tiny bug to report, it seems that the "right" element of a contract is not captured for options. It's supposed to be "C" or "P" not sure if it's an IBKR issue or a library issue.

{
 contract: {
          symbol: 'TSLA',
          secType: 'OPT',
          lastTradeDateOrContractMonth: '20220617',
          strike: 900,
          right: undefined,
          exchange: 'SMART',
          currency: 'USD',
          localSymbol: 'TSLA  220617P00900000',
          tradingClass: 'TSLA',
          conId: 442955799,
          multiplier: 100,
          primaryExch: ''
        }
 }

Deadlook in reqHistoricalData with invalid requests (CSCO is ambiguous)

There is another deadlock in reqHistoricalData

  • Symbol: csco
  • error The contract description specified for CSCO is ambiguous.

Example code

import ibkr, { IBKRConnection, IbkrEvents, HistoricalData } from '@stoqey/ibkr';

const ibkrEvents = IbkrEvents.Instance;


const main = async () => {
  try {
    // @ts-ignore
    const connectionStatus = await ibkr({ port: 7496, host: '127.0.0.1' });

    HistoricalData.Instance;

    const symbol = 'csco'

    const data = await HistoricalData.Instance.reqHistoricalData({
      symbol,
      endDateTime: '',
      durationStr: '1 W',
      barSizeSetting: '1 day',
      whatToShow: 'TRADES',
      //whatToShow: 'YIELD_BID'
    })
    console.log(data)
    IBKRConnection.Instance.disconnectIBKR()
  } catch (error) {
    console.error(error)
  }
};

main();

Error in debug

ibkr:info error The contract description specified for CSCO is ambiguous. +304ms

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.