Coder Social home page Coder Social logo

stoqey / ib Goto Github PK

View Code? Open in Web Editor NEW
190.0 13.0 45.0 1.82 MB

Interactive Brokers TWS/IB Gateway API client library for Node.js (TS)

Home Page: https://stoqey.github.io/ib-doc/

License: MIT License

TypeScript 100.00%
interactive-brokers stocks-api forex-api options-trading twsapi market-data price-ticker ib-gateway typescript tws

ib's Introduction

Typescript API

@stoqey/ib is an Interactive Brokers TWS (or IB Gateway) Typescript API client library for Node.js. It is a port of Interactive Brokers' Java Client Version 10.29.01 ("latest") from June 18th, 2024.

Refer to the Trader Workstation API for the official documentation and the C#/Java/VB/C++/Python client.

The module makes a socket connection to TWS (or IB Gateway) using the net module and all messages are entirely processed in Typescript. It uses EventEmitter to pass the result back to user.

Installation

$ npm install @stoqey/ib

or

$ yarn add @stoqey/ib

Update from 1.1.x to 1.2.x

If you currently use version 1.1.x and want to upgrade to 1.2.x please note that there is a breaking change that might affect your code:

Versions up to 1.1.x did return Number.MAX_VALUE on values that are not available. This was to be in-sync with the official TWS API Java interfaces. Since the usage of Number.MAX_VALUE is very uncommon in JScript/TS and caused / causes lot of confusion, all versions starting from 1.2.1 will return undefined instead.

If you have checked for Number.MAX_VALUE up to now, you can drop this check. If you have not checked for undefined yet, you should add it.

Example:

ib.on(EventName.pnlSingle, (
      reqId: number,
      pos: number,
      dailyPnL: number,
      unrealizedPnL: number,
      realizedPnL: number,
      value: number
    ) => {
      ...
    }
  );

now is (look at unrealizedPnL and realizedPnL)

ib.on(EventName.pnlSingle, (
      reqId: number,
      pos: number,
      dailyPnL: number,
      unrealizedPnL: number | undefined,
      realizedPnL: number | undefined,
      value: number
    ) => {
      ...
    }
  );

API Documentation

See API documentation here.

IBApi vs IBApiNext

There are two APIs on this package, IBApi and IBApiNext.

IBApi replicates the official TWS API as close as possible, making it easy to migrate or port existing code. It implements all functions and provides same event callbacks as the official TWS API does.

IBApiNext is a preview of a new API that is currently in development. The goal of IBApiNext is it, to provide same functionality as IBApi, but focus on usability rather than replicating the official interface. It is not based on a request/event design anymore, but it does use RxJS instead. IBApiNext still is in preview stage. Not all functions are available yet, and we cannot guarantee stable interfaces (although are we confident that public signatures of already existing functions won't change anymore).

IB socket ports

Platform Port
IB Gateway live account  4001
IB Gateway paper account  4002
TWS Live Account 7496
TWS papertrading account 7497 

IBApi Examples

/* Example: Print all portfolio positions to console. */

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();

Sending first order

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();

IBApiNext and RxJS

While IBApi uses a request function / event callback design where subscriptions are managed by the user, IBApiNext does use RxJS 7 to manage subscriptions.
In general, there are two types of functions on IBApiNext:

  • One-shot functions, returning a Promise, such as IBApiNext.getCurrentTime or IBApiNext.getContractDetails. Such functions will send a request to TWS and return the result (or error) on the Promise.

  • Endless stream subscriptions, returning an Observable, such as IBApiNext.getAccountSummary or IBApiNext.getMarketData. Such functions will deliver an endless stream of update events. The complete callback will NEVER be invoked (do not try to convert to a Promise - it will never resolve!)

IB-Shell / IBApiNext Examples

The src/tools folder contains a collection of command line tools to run IBApiNext from command line. Have look on it if you search for IBApiNext sample code.

Example:

node ./dist/tools/account-summary.js -group=All -tags="NetLiquidation,MaintMarginReq" -watch -inc -port=4002
{
  "all": [
    [
      "DU******",
      [
        [
          "MaintMarginReq",
          [
            [
              "EUR",
              {
                "value": "37688.07",
                "ingressTm": 1616849611611
              }
            ]
          ]
        ]
      ]
    ]
  ],
  "added": [
    [
...

Testing

Locally

! WARNING ! - Make sure to test on papertrading account as tests could contain actions that result in selling and buying financial instruments.

The easiest way to start testing and playing around with the code is to run included IB Gateway docker container. To set it up use following steps.

Copy sample.env to file .env

  1. run yarn to install dependencies
  2. cp sample.env .env
  3. fill in the account info
  4. you might need to change the value of IB_PORT from 4002 to 4004 if using IB Gateway from docker-compose (Step 6)
  5. run command yarn build to compile TypeScript code
  6. run command docker-compose up (use flag -d to run de-attached mode in background). Now the docker instance of IB Gateway should be running.
  7. to take the container down just run docker-compose down

Once docker is up and running with correct credentials it should be ready to accept connections.

Running jest test

Tests can be run from CLI with jest tool. Either a single one or multiple tests at once.

Running single/multiple tests

jest src/test/unit/api/api.test.ts

To run multiple, just use path instead of specific file.

To run all tests run the following command.

yarn test

CI

Will be added later once it's stable

Deprecation process

Public interfaces, that are planned to be removed, will be marked with a @deprecated.
The @deprecated tag will contain a description or link on how migrate to new API (example: IBApiCreationOptions.clientId).
VSCode will explicitly mark deprecated functions and attributes, so you cannot miss it.

If you write new code, don't use deprecated functions.
If you already use deprecated functions on existing code, migrate to new function on your next code-clean up session. There is no need for immediate change, the deprecated function will continue to work for a least a half more year, but at some point it will be removed.

How to contribute

IB does regularly release new API versions, so this library will need permanent maintenance in order to stay up-to-date with latest TWS features.
Also, there is not much testing code yet. Ideally there should be at least one test-case for each public function.
In addition to that, a little demo / example app would be nice, to demonstrate API usage (something like a little live-portoflio-viewer app for node.js console?).
Any kind of bugfixes are welcome as well.

If you want to contribute, read the Developer Guide and start coding.

ib's People

Contributors

ajanian avatar andersonaguiar avatar bennycode avatar businessduck avatar ceddybi avatar ctoesca avatar dependabot[bot] avatar efernandesng avatar innovatingdev avatar kharitonoff avatar mafianekcek avatar mfrener avatar mikedavies-dev avatar netshade avatar rexqin avatar rylorin avatar scrivna avatar tsopic avatar usmanrehmat 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ib's Issues

reqPositionsMulti decoder broken

Issue
The POSITION_MULTI Decoder function is missing the extraction of the modelCode value.
This causes decoding of the next notification to fail.
I'm currently working around this by applying my code fix locally in my own environments using patch-package.

Source File
node_modules/@stoqey/ib/dist/io/decoder.js

Code Fix

    /**
     * Decode a POSITION_MULTI message from data queue and emit a accountSummary event.
     */
    Decoder.prototype.decodeMsg_POSITION_MULTI = function () {
        this.readInt(); // version
        var reqId = this.readInt();
        var account = this.readStr();
        var modelCode = null;
        var contract = {};
        contract.conId = this.readInt();
        contract.symbol = this.readStr();
        contract.secType = this.readStr();
        contract.lastTradeDateOrContractMonth = this.readStr();
        contract.strike = this.readDouble();
        contract.right = this.readStr();
        contract.multiplier = this.readInt();
        contract.exchange = this.readStr();
        contract.currency = this.readStr();
        contract.localSymbol = this.readStr();
        contract.tradingClass = this.readStr();
        var pos = this.readInt();
        var avgCost = this.readDouble();

        // added by dalesmckay 2021-01-23
        modelCode = this.readStr();     // <<<===== MISSING THIS LINE !!!

        this.emit(api_1.EventName.positionMulti, reqId, account, modelCode, contract, pos, avgCost);
    };

Why no types?

Hi.
I'm working on Typescript node.js app that wants to use IBKR API.
Found your ts lib and would like to use it (https://github.com/stoqey/ib seems to be inactive) .
I was wondering why you do not use strong typing on the library code, or at least provide type declarations?
There shall be no 'any' type anywhere Typescript my projects, so I will probably implement type declarations for your lib in my own .. unless there are plans to add this at a later point? (or maybe you want a pull-request after I'm done?)

Forger about it, I have found: https://github.com/stoqey/ibkr

support for account with contracts in multiple currencies

I've been looking at the api-next branch, which is very well programmed and very clean code.

One issue is that an AccountSummary could have multiple currencies and the current data structure does not support that. IBKR could do margin calculations per currency and report tag/values by currency.

In api-next.ts, method: getAccountSummary the callback will overwrite the tag for whichever is the last reported currency:

const onAccountSummary = (reqId: number, account: string, tag: string, value: string, currency: string): void => {
      // get the subscription
      const subscription = this._subscriptions.get(reqId) as IBApiNextSubscription<AccountSummariesUpdate>;
      if (!subscription) {
        return;
      }

      // update cache
      const cached = subscription.value ?? new AccountSummariesUpdate();
      cached.all.getOrAdd(account).values.set(tag, { value, currency });

You may need an AccountSummaryValues map by currency.Something similar what I did here (but your code with observables is way nicer!): stoqey/ibkr#68 (comment)

Missing attributes in the Future(Contract) class

Hi, I tried to subscribe to GLOBEX market data (level 1) by using the request 'reqMktData'.
I got an error as IB is asking for more attributes to be provided. I managed to get it to work by adding 'lastTradeDateOrContractMonth' and 'localSymbol' attributes.

This is the class I ended with, in case you would like to test it.

    class Future implements Contract {
         secType: SecType;
         symbol: string;
         localSymbol: string;
         lastTradeDateOrContractMonth: string;
         exchange: string;
         multiplier: number;
         currency: string;

        constructor(symbol: string, localSymbol: string, lastTradeDateOrContractMonth: string, 
                       exchange: string, multiplier: number, currency: string) {
        this.secType = SecType.FUT;
        this.symbol = symbol;
        this.lastTradeDateOrContractMonth = lastTradeDateOrContractMonth;
        this.localSymbol = localSymbol;
        this.exchange = exchange;
        this.multiplier = multiplier;
        this.currency = currency;
    }
}

Thank you for your hard work!
Great repository.

IB test papertrading account for CI

Interactive Brokers used to have demo accounts but now it's more difficult to obtain a PaperTrading account.

I'm looking into ways to make CI work with tests, and need an IB paper trading account to use in CircleCI.

Anyone, having good connections with IB staff?

Update to IB API 9.81

Since a couple of days TWS brings up "Please update your client to version 980" because of some new risk-analysis-whatever feature.
Had a look on the change notes between 9.76 and 9.81 and doesn't seem to be that complicated. The have added "support for Price Based Volatility Quotes" and a couple of bugfixes. Shouldn't be that much work to update our lib as well.

Created that task to have it on backlog and not forget about (not sure when I have time to work on).

_TICK_OPTION_COMPUTATION might be buggy

Hi.
I have been using pilwon/node-ib (but will switch to your one as soon as I have time ;) ) and did run into a bug where vega option greeks did not display.
Issue is a check for > 1 that sets it to MAX_VALUE. It is not good, as vega, gamma & co can be > 1.
Think you have the same issue on Incoming.prototype._TICK_OPTION_COMPUTATION.
See my PR for node-ib pilwon/node-ib#166

Add support rxjs

Backlog item:
The original IB API has a request + a callback (we have EventEmitter not callback) design, which is very old-school and a f*cking pain in the ass to use..
We can still keep that API in order to be compatible with IB API but in addition we should offer rxjs.

Goals is to allow both models, example:

  1. Traditional via EventEmitter:
    // register event receiver to receive events and log if it is PnL request 43
    ib.on(EventName.pnl, (reqId: number, pnl: number) => {
    if (reqId==43) {
    console.log(pnl);
    }
    });
    // start PnL request 43
    ib.reqPnL(43, account);

  2. To be added, via rxjs:
    // call request function and get an rxjs Observable
    ib.reqPnL(account).subscribe((pnl) => console.log(pnl));

Placing Conditional Orders

Hi,

I'm getting errors when I try to place an Order using the conditions property. I've tried using Time Condition, Price Condition and Margin Condition but it just doesn't works.

I've been reading and logging the encoder code but I don't see nothing wrong there. Maybe it is a problem from TWS? Am I placing the order in a wrong way?

Below is the code that throws error

import IBApi, { ConjunctionConnection, Contract, ErrorCode, EventName, ExecutionCondition, MarginCondition, Order, OrderAction, OrderState, OrderType, SecType, TimeCondition } from '../ib-master/dist/index';

const ib = new IBApi({
    // clientId: 0,
    // host: '127.0.0.1',
    port: 7497,
});

function handleOrderPlacement() {

    ib
    .on(EventName.error, (error: Error, code: ErrorCode, reqId: number) => {
        console.log(`Error ${error.name} msg: ${error.message} - Code ${code} - reqId ${reqId}`, error.stack)
    })
    .once(EventName.nextValidId, (orderId: number) => {
        const contract: Contract = {
            symbol: "A",
            exchange: "NYSE",
            currency: "USD",
            secType: SecType.STK
        };

        const timeCondition: TimeCondition = new TimeCondition("20210118 23:59:59 EST", true, ConjunctionConnection.OR);
        // const marginCondition: MarginCondition = new MarginCondition(10, true, ConjunctionConnection.OR);
        // const execCondition: ExecutionCondition = new ExecutionCondition("ISLAND", SecType.STK, "FB", ConjunctionConnection.OR);
        const order: Order = {
            orderType: OrderType.LMT,
            action: OrderAction.BUY,
            lmtPrice: 1,
            orderId,
            totalQuantity: 1,
            account: 'DU3746845',
            conditionsIgnoreRth: true,
            conditionsCancelOrder: false
        };
        order.conditions = [timeCondition];
        console.log(order);
        ib.placeOrder(orderId, contract, order);
    });
}

handleOrderPlacement();
ib.connect();
ib.reqIds();

The errors are these:

Error Error msg: Error reading request.Message id 135.  Unable to parse data. java.lang.NumberFormatException: For input string: "o" - Code 320 - reqId 135 Error: Error reading request.Message id 135.  Unable to parse data. java.lang.NumberFormatException: For input string: "o"

Error Error msg: Error validating request.-'bX' : cause - Please enter exchange - Code 321 - reqId 0 Error: Error validating request.-'bX' : cause - Please enter exchange

Thanks in advance

Can't send order to TWS

Can't send any order to TWS with the last version API(1.02, but can send in more early 0.1.

Error in the encoder.ts
if (this.serverVersion >= MIN_SERVER_VER.SOFT_DOLLAR_TIER) {
tokens.push(order.softDollarTier.name); <<<<<<<<<<<<<<<<<<<<<<<<<<<<< Can't read property name
tokens.push(order.softDollarTier.value);
}

Error object really without softDollarTier , but looks like it needs to set some value, or  what is the way to solve the problem with softDollarTier. Variants like softDollarTier = {} , or softDollarTier ={name:'', value:''} are not help.

Thanks,
Victor

Forex class use incorrect SekType (FOP but should be CASH)

Unless I'm misunderstanding something, the Forex class sets the secType property incorrectly. It should be of type CASH instead of FOP.

This works:

const contract: Contract = {
  symbol: "USD",
  exchange: "IDEALPRO",
  currency: "CAD",
  secType: SecType.CASH,
};

ib.reqHistoricalData(4002, contract, '20221126 15:59:00 US/Eastern', "1 M", BarSizeSetting.DAYS_ONE, "MIDPOINT", 1, 1, `false);

but this does not:

const contract = new Forex("EUR", "USD") // this does not work, because the Forex class set secType to FOP (which is dedicated to options)

ib.reqHistoricalData(4002, contract, '20221126 15:59:00 US/Eastern', "1 M", BarSizeSetting.DAYS_ONE, "MIDPOINT", 1, 1, false);

Error with JEST

It install but cannot start with yarn dev command, conflict with JEST

I try everything show in the error without success, even disabling the check is not working... don't really know why

[0] Listening on port 5000
[1]
[1] There might be a problem with the project dependency tree.
[1] It is likely not a bug in Create React App, but something you need to fix locally.
[1]
[1] The react-scripts package provided by Create React App requires a dependency:
[1]
[1] "jest": "26.6.0"
[1]
[1] Don't try to install it manually: your package manager does it automatically.
[1] However, a different version of jest was detected higher up in the tree:
[1]
[1] /node_modules/jest (version: 26.6.3)
[1]
[1] Manually installing incompatible versions is known to cause hard-to-debug issues.
[1]
[1] If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
[1] That will permanently disable this message but you might encounter other issues.
[1]
[1] To fix the dependency tree, try following the steps below in the exact order:
[1]
[1] 1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
[1] 2. Delete node_modules in your project folder.
[1] 3. Remove "jest" from dependencies and/or devDependencies in the package.json file in your project folder.
[1] 4. Run npm install or yarn, depending on the package manager you use.
[1]
[1] In most cases, this should be enough to fix the problem.
[1] If this has not helped, there are a few other things you can try:
[1]
[1] 5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
[1] This may help because npm has known issues with package hoisting which may get resolved in future versions.
[1]
[1] 6. Check if /node_modules/jest is outside your project directory.
[1] For example, you might have accidentally installed something in your home folder.
[1]
[1] 7. Try running npm ls jest in your project folder.
[1] This will tell you which other package (apart from the expected react-scripts) installed jest.
[1]
[1] If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
[1] That would permanently disable this preflight check in case you want to proceed anyway.
[1]
[1] P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!

Commission returns incorrect large number

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.)

Decoder missing handlers for some message ids

Issue
The decoder is missing handlers for some message ids.
Once encountered, this causes the queue to fall out of sync for a few cycles until the application crashes.

Source File
https://github.com/stoqey/ib/blob/master/src/io/decoder.ts

Code Fix

Add the following values to enum IN_MSG_ID:

REROUTE_MKT_DATA = 91,
REROUTE_MKT_DEPTH = 92,
MARKET_RULE = 93,

Add the following handler functions:

    /**
     * Decode a REROUTE_MKT_DATA message from data queue and emit a rerouteMktDataReq event.
     */
    private decodeMsg_REROUTE_MKT_DATA(): void {
        const reqId    = this.readInt();
        const conId    = this.readInt();
        const exchange = this.readStr();
        this.emit(EventName.rerouteMktDataReq, reqId, conId, exchange);
    }

    /**
     * Decode a REROUTE_MKT_DEPTH message from data queue and emit a rerouteMktDepthReq event.
     */
    private decodeMsg_REROUTE_MKT_DEPTH(): void {
        const reqId    = this.readInt();
        const conId    = this.readInt();
        const exchange = this.readStr();
        this.emit(EventName.rerouteMktDepthReq, reqId, conId, exchange);
    }

    /**
     * Decode a MARKET_RULE message from data queue and emit a marketRule event.
     */
    private decodeMsg_MARKET_RULE(): void {
        const marketRuleId     = this.readInt();
        const nPriceIncrements = this.readIncrements();
        const priceIncrements  = new Array(nPriceIncrements);

        for (let ii = 0; ii < nPriceIncrements; ii++) {
            priceIncrements[ii] = {
                lowEdge   : this.readDouble(),
                increment : this.readDouble()
            };
        }

        this.emit(EventName.marketRule, marketRuleId, priceIncrements);
    }

Sorry, my dev environment is not setup to modify the typescript files and make a pull request.
I'm currently working around this by applying my code fix locally in my own environments using patch-package directly on the .js files in the node_modules folder.

Cannot find module '/usr/src/app/dist/tools/positions.js'

When running docker-compose up, then I am getting the following error:

tws_1     | 2021-07-26 08:30:24:925 IBC: Using default settings provider: ini file is /opt/ibc/config.ini
tws_1     | 2021-07-26 08:30:24:926 IBC: Using default login manager: getting username and password from args but not found. Will get from settings
tws_1     | 2021-07-26 08:30:24:926 IBC: Using default main window manager: constructor parameter isGateway=true
tws_1     | 2021-07-26 08:30:24:926 IBC: Using default trading mode manager: constructor parameter args but trading mode not present - will be taken from settings
tws_1     | 2021-07-26 08:30:24:927 IBC: Using default config dialog manager
tws_1     | 2021-07-26 08:30:24:932 IBC: CommandServer is not started because the port is not configured
tws_1     | 2021-07-26 08:30:25:008 IBC: TWS Settings directory is: /root/Jts
tws_1     | 2021-07-26 08:30:25:009 IBC: Creating minimal /root/Jts/jts.ini
tws_1     | 2021-07-26 08:30:25:009 IBC:     jts.ini: [Logon]
tws_1     | 2021-07-26 08:30:25:010 IBC:     jts.ini: s3store=true
tws_1     | 2021-07-26 08:30:25:010 IBC:     jts.ini: Locale=en
tws_1     | 2021-07-26 08:30:25:010 IBC:     jts.ini: displayedproxymsg=1
tws_1     | 2021-07-26 08:30:25:010 IBC:     jts.ini: [IBGateway]
tws_1     | 2021-07-26 08:30:25:010 IBC:     jts.ini: ApiOnly=true
tws_1     | 2021-07-26 08:30:25:010 IBC: Starting session: will exit if login dialog is not displayed within 30 seconds
tws_1     | 2021-07-26 08:30:25:805 IBC: Getting config dialog
tws_1     | 2021-07-26 08:30:25:805 IBC: Creating config dialog future
tws_1     | 2021-07-26 08:30:25:806 IBC: Getting main window
tws_1     | 2021-07-26 08:30:25:806 IBC: Creating main window future
ib-api    | internal/modules/cjs/loader.js:905
ib-api    |   throw err;
ib-api    |   ^
ib-api    |
ib-api    | Error: Cannot find module '/usr/src/app/dist/tools/positions.js'
ib-api    |     at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)
ib-api    |     at Function.Module._load (internal/modules/cjs/loader.js:746:27)
ib-api    |     at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
ib-api    |     at internal/main/run_main_module.js:17:47 {
ib-api    |   code: 'MODULE_NOT_FOUND',
ib-api    |   requireStack: []
ib-api    | }
ib-api exited with code 1

Any tips why /usr/src/app/dist/tools/positions.js cannot be found?

Emitting values after .complete() must be avoided

Following problem:
We have a couple of functions that collection a set of items, after collected it calls .complete() on the Observable and then continue to emit changes into it. Example: the positions list. It will first collect all positions, call .complete() to signal initial collection and then send any further update to it afterwards.
This will not work anymore in future RxJS versions. You shouldn't call .next() after a .complete() or .error(). Up to now it still works for some reason, but it will start break (it did already it 8.0).

That we need to change:
Any returned Observable must never complete.
If there is a case where you can get an "initial collection", there will be an additional function returning a Promise.

============= OUTDATED (see next post) =============

Example:
Right now we have:
getPositions(): Observable<AccountPositionsUpdate>
which will complete after initial collection and afterwards continue to emit updates.
We will change this to:
getPositions(): Observable<AccountPositionsUpdate>
getPositionsSnapshot(): Promise<AccountPositions>

We don't need to change function signature, however the behavior will be different.
This will be broken, because there is no last value (never completes):
lastValueFrom(ib.getPositions()).then(() => ...)
instead you should do this:
ib.getPositionsSnapshot().then(() => ...)

@Tsopic what do think? Any better idea?

cancelOrder does not work

Firstly, I open SELL LMT order (take profit order):

const contract: Contract = {
    secType: SecType.CASH,
    currency: 'USD',
    symbol: 'EUR',
    exchange: 'IDEALPRO',
}

const order: Order = {
  orderType: OrderType.LMT,
  action: OrderAction.SELL,
  lmtPrice: 6.057,
  totalQuantity: TOTAL_QUANTITY,
};

const orderId = await ib.placeNewOrder(contract, order); // 42

// place orderId to mongoDB

Secondly, I want to change take profit: cancel first order and place new order with new lmtPrice:

const takeProfitOrderId = getFromMongoDb(); // 42
const contract: Contract = {
    secType: SecType.CASH,
    currency: 'EUR',
    symbol: 'USD',
    exchange: 'IDEALPRO',
}

const order: Order = {
  orderType: OrderType.LMT,
  action: OrderAction.SELL,
  lmtPrice: 7.057,
  totalQuantity: TOTAL_QUANTITY,
};

ib.cancelOrder(takeProfitOrderId);
await sleep(50);
ib.modifyOrder(takeProfitOrderId, contract, order);

But first order does not canceled: I have 2 open orders in TWS:

image

Please Help

connect issue

Hi, I am facing a problem which I have tested even with this simple script:

const IBAPI = require("@stoqey/ib");
const ib = new IBAPI.IBApi({
	clientId: 1,
	host: '127.0.0.1',
	port: 7496
});
ib.on(IBAPI.EventName.all, (event, args) => {
	console.log(event, JSON.stringify(args))
})
ib.on(IBAPI.EventName.error, (err, code, reqId) => {
	console.error(err, code, reqId);
})

ib.connect()

The problem is that sometimes after run script it connects me to the API but immediately disconnects as you can see in console output:

[17:29:31.561] [LOG]   sent [["API\u0000",0,0,0,9,"v100..151"],"v100..151"]
[17:29:31.564] [LOG]   received [["151","20221216 17:29:41 CET"],"151\u000020221216 17:29:41 CET\u0000"]
[17:29:31.565] [LOG]   sent [[71,2,1,""],"71\u00002\u00001\u0000"]
[17:29:31.566] [LOG]   sent [[17,1],"17\u00001"]
[17:29:31.566] [LOG]   connected []
[17:29:31.566] [LOG]   server [151,"20221216 17:29:41 CET"]
[17:29:31.570] [LOG]   disconnected []

Do you have any ideas please? Thank you

Getting testing setup

Hey all,

I've noticed an issue with reqHistoricalTicks that I'd like to fix and add associated tests but I'm having getting the test suit up and running. I'm probably missing something in my setup.

I'm running IB Gateway on port 4002 (paper trading account) and a lot of the API tests seem to work (i.e. I can see the test suite connecting to IB Gateway etc), but a lot of the tests timeout (test results below). The test suite is obviously connecting to IB Gateway in some tests because I can see active connections there and a lot of the API tests pass OK.

I've also tried running the docker image but that shows connection errors on 4002. I'm not sure if that needs to be running for the tests to work?

Any thoughts on what I might be missing in my dev setup?

yarn run v1.22.10
$ jest --maxWorkers=8 --reporters=default --useStderr --detectOpenHandles
 FAIL  src/tests/unit/api/api.test.ts (61.007 s)
  ● IBApi Tests › Test connect / disconnect

    : Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error:

      13 |   let _clientId = 0; // ensure unique client
      14 | 
    > 15 |   it("Test connect / disconnect", (done) => {
         |   ^
      16 |     const ib = new IBApi({
      17 |       clientId: _clientId++,
      18 |       host: TEST_SERVER_HOST,

      at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (src/tests/unit/api/api.test.ts:15:3)

  ● IBApi Tests › Test reqPositions / cancelPositions

    expect(received).toBeFalsy()

    Received: "connect EADDRNOTAVAIL 127.0.0.1 - Local (0.0.0.0:49365) - code: 502 - id: -1"

      46 | 
      47 |     ib.on(EventName.error, (err: Error, code: ErrorCode, id: number) => {
    > 48 |       expect(`${err.message} - code: ${code} - id: ${id}`).toBeFalsy();
         |                                                            ^
      49 |     })
      50 |       .on(
      51 |         EventName.position,

      at IBApi.<anonymous> (src/tests/unit/api/api.test.ts:48:60)
      at IBApi.emit (node_modules/eventemitter3/index.js:183:35)
      at Controller.emitEvent (src/core/io/controller.ts:168:13)
      at Controller.emitError (src/core/io/controller.ts:207:10)
      at Socket.onError (src/core/io/socket.ts:421:21)
      at Socket.<anonymous> (src/core/io/socket.ts:148:36)

  ● IBApi Tests › Test reqPnL / cancelPositions

    expect(received).toBeFalsy()

    Received: "Server Version 0: It does not support position requests. - code: 503 - id: -1"

      46 | 
      47 |     ib.on(EventName.error, (err: Error, code: ErrorCode, id: number) => {
    > 48 |       expect(`${err.message} - code: ${code} - id: ${id}`).toBeFalsy();
         |                                                            ^
      49 |     })
      50 |       .on(
      51 |         EventName.position,

      at IBApi.<anonymous> (src/tests/unit/api/api.test.ts:48:60)
      at IBApi.emit (node_modules/eventemitter3/index.js:183:35)
      at Controller.emitEvent (src/core/io/controller.ts:168:13)
      at Controller.emitError (src/core/io/controller.ts:207:10)
      at Encoder.emitError (src/core/io/encoder.ts:179:19)
      at Encoder.reqPositions (src/core/io/encoder.ts:2414:19)
      at src/api/api.ts:1239:60
      at src/core/io/controller.ts:84:34
      at Controller.execute (src/core/io/controller.ts:220:5)
      at CommandBuffer.Object.<anonymous>.CommandBuffer._process (node_modules/command-buffer/dist/command-buffer.js:65:16)

  ● IBApi Tests › Test reqPnLSingle / cancelPnLSingle

    : Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error:

      102 |   });
      103 | 
    > 104 |   it("Test reqPnLSingle / cancelPnLSingle", (done) => {
          |   ^
      105 |     const ib = new IBApi({
      106 |       clientId: _clientId++,
      107 |       host: TEST_SERVER_HOST,

      at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (src/tests/unit/api/api.test.ts:104:3)

 FAIL  src/tests/unit/api/order/placeOrder.test.ts (20.321 s)
  ● RequestAllOpenOrders › placeOrder with PriceCondition

    Failed: undefined

      72 |       }).on(EventName.openOrderEnd, () => {
      73 |         if (!finished) {
    > 74 |           fail();
         |           ^
      75 |         }
      76 |       });
      77 | 

      at Env.fail (node_modules/jest-jasmine2/build/jasmine/Env.js:722:61)
      at IBApi.<anonymous> (src/tests/unit/api/order/placeOrder.test.ts:74:11)
      at IBApi.emit (node_modules/eventemitter3/index.js:180:35)
      at Controller.emitEvent (src/core/io/controller.ts:168:13)
      at src/core/io/decoder.ts:381:23
          at Array.forEach (<anonymous>)
      at Decoder.process (src/core/io/decoder.ts:380:14)
      at Controller.processIngressQueue (src/core/io/controller.ts:100:18)
      at Socket.onMessage (src/core/io/socket.ts:303:23)

  ● RequestAllOpenOrders › placeOrder with PriceCondition

    : Timeout - Async callback was not invoked within the 20000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 20000 ms timeout specified by jest.setTimeout.Error:

      18 |   jest.setTimeout(20000);
      19 | 
    > 20 |   test("placeOrder with PriceCondition", (done) => {
         |   ^
      21 |     const ib = new IBApi({
      22 |       port: 4002, // use Gateway
      23 |     });

      at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (src/tests/unit/api/order/placeOrder.test.ts:20:3)

 FAIL  src/tests/unit/api/order/reqAllOpenOrders.test.ts (20.252 s)
  ● Console

    console.log
      Using host: undefined and port: undefined for test

      at Object.info (src/common/logger.ts:15:42)

  ● RequestAllOpenOrders › Test reqAllOpenOrders

    : Timeout - Async callback was not invoked within the 20000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 20000 ms timeout specified by jest.setTimeout.Error:

      12 | describe("RequestAllOpenOrders", () => {
      13 |   jest.setTimeout(20000);
    > 14 |   it("Test reqAllOpenOrders", (done) => {
         |   ^
      15 |     logger.info(
      16 |       `Using host: ${TEST_SERVER_HOST} and port: ${TEST_SERVER_POST} for test `
      17 |     );

      at new Spec (node_modules/jest-jasmine2/build/jasmine/Spec.js:116:22)
      at Suite.<anonymous> (src/tests/unit/api/order/reqAllOpenOrders.test.ts:14:3)

 FAIL  src/tests/unit/configuration.test.ts
  ● configuration › ENV vars take priority

    expect(received).toEqual(expected) // deep equality

    Expected: "ENV"
    Received: undefined

       7 | describe("configuration", () => {
       8 |   test("ENV vars take priority", async () => {
    >  9 |     expect(configuration.env_config_test).toEqual("ENV");
         |                                           ^
      10 |   });
      11 | 
      12 |   test("ENV vars must be specified in includes array", async () => {

      at Object.<anonymous> (src/tests/unit/configuration.test.ts:9:43)

  ● configuration › ENV vars must be specified in includes array

    expect(received).toEqual(expected) // deep equality

    Expected: "default"
    Received: undefined

      11 | 
      12 |   test("ENV vars must be specified in includes array", async () => {
    > 13 |     expect(configuration.env_not_included_config_test).toEqual("default");
         |                                                        ^
      14 |   });
      15 | 
      16 |   test("environment specific files take priority over local", async () => {

      at Object.<anonymous> (src/tests/unit/configuration.test.ts:13:56)

  ● configuration › environment specific files take priority over local

    expect(received).toEqual(expected) // deep equality

    Expected: "test"
    Received: undefined

      16 |   test("environment specific files take priority over local", async () => {
      17 |     const env = configuration.ci ? "development" : "test";
    > 18 |     expect(configuration.environment_config_test).toEqual(env);
         |                                                   ^
      19 |   });
      20 | 
      21 |   test("local takes priority over default", async () => {

      at Object.<anonymous> (src/tests/unit/configuration.test.ts:18:51)

  ● configuration › local takes priority over default

    expect(received).toEqual(expected) // deep equality

    Expected: "local"
    Received: undefined

      21 |   test("local takes priority over default", async () => {
      22 |     if (!configuration.ci) {
    > 23 |       expect(configuration.local_config_test).toEqual("local");
         |                                               ^
      24 |     }
      25 |   });
      26 | 

      at Object.<anonymous> (src/tests/unit/configuration.test.ts:23:47)

  ● configuration › default is lowest priority

    expect(received).toEqual(expected) // deep equality

    Expected: "default"
    Received: undefined

      26 | 
      27 |   test("default is lowest priority", async () => {
    > 28 |     expect(configuration.default_config_test).toEqual("default");
         |                                               ^
      29 |   });
      30 | });
      31 | 

      at Object.<anonymous> (src/tests/unit/configuration.test.ts:28:47)

 PASS  src/tests/unit/api-next/get-account-summary.test.ts

  ●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "Error: connect EADDRNOTAVAIL 127.0.0.1 - Local (0.0.0.0:49374)
        at Controller.emitError (/Users/miked/Projects/temp/ib2/src/core/io/controller.ts:207:37)
        at Socket.onError (/Users/miked/Projects/temp/ib2/src/core/io/socket.ts:337:25)
        at Socket.<anonymous> (/Users/miked/Projects/temp/ib2/src/core/io/socket.ts:117:42)
        at Socket.emit (events.js:314:20)
        at emitErrorNT (internal/streams/destroy.js:100:8)
        at emitErrorCloseNT (internal/streams/destroy.js:68:3)
        at processTicksAndRejections (internal/process/task_queues.js:80:21)".

      26 |   );
      27 | 
    > 28 |   console.error(...newArgs);
         |           ^
      29 | };
      30 | 
      31 | const testError = (...args: any[]) => {

      at BufferedConsole.error (node_modules/@jest/console/build/BufferedConsole.js:161:10)
      at Object.error (src/common/logger.ts:28:11)
      at IBApi.<anonymous> (src/tests/unit/api/connect.test.ts:30:14)
      at IBApi.emit (node_modules/eventemitter3/index.js:183:35)
      at Controller.emitEvent (src/core/io/controller.ts:168:13)
      at Controller.emitError (src/core/io/controller.ts:207:10)
      at Socket.onError (src/core/io/socket.ts:421:21)
      at Socket.<anonymous> (src/core/io/socket.ts:148:36)

 PASS  src/tests/unit/api/connect.test.ts
  ● Console

    console.error
      Error: Cannot disconnect if already disconnected.
          at Controller.emitError (/Users/miked/Projects/temp/ib2/src/core/io/controller.ts:207:37)
          at Controller.executeDisconnect (/Users/miked/Projects/temp/ib2/src/core/io/controller.ts:249:12)
          at Controller.disconnect (/Users/miked/Projects/temp/ib2/src/core/io/controller.ts:74:10)
          at IBApi.disconnect (/Users/miked/Projects/temp/ib2/src/api/api.ts:137:21)
          at Object.<anonymous> (/Users/miked/Projects/temp/ib2/src/tests/unit/api/connect.test.ts:22:10)
          at Object.asyncJestLifecycle (/Users/miked/Projects/temp/ib2/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:58:37)
          at /Users/miked/Projects/temp/ib2/node_modules/jest-jasmine2/build/queueRunner.js:45:12
          at new Promise (<anonymous>)
          at mapper (/Users/miked/Projects/temp/ib2/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
          at /Users/miked/Projects/temp/ib2/node_modules/jest-jasmine2/build/queueRunner.js:75:41

      26 |   );
      27 | 
    > 28 |   console.error(...newArgs);
         |           ^
      29 | };
      30 | 
      31 | const testError = (...args: any[]) => {

      at Object.error (src/common/logger.ts:28:11)
      at IBApi.<anonymous> (src/tests/unit/api/connect.test.ts:30:14)
      at IBApi.emit (node_modules/eventemitter3/index.js:183:35)
      at Controller.emitEvent (src/core/io/controller.ts:168:13)
      at Controller.emitError (src/core/io/controller.ts:207:10)
      at Controller.executeDisconnect (src/core/io/controller.ts:249:12)
      at Controller.disconnect (src/core/io/controller.ts:74:10)
      at IBApi.disconnect (src/api/api.ts:137:21)

 PASS  src/tests/unit/api-next/get-contract-details.test.ts
 PASS  src/tests/unit/api-next/get-managed-accounts.test.ts
 PASS  src/tests/unit/api-next/get-market-data.test.ts
 PASS  src/tests/unit/api-next/get-historical-data.test.ts
 PASS  src/tests/unit/api-next/get-pnl.test.ts
 PASS  src/tests/unit/api-next/get-pnl-signle.test.ts
 PASS  src/tests/unit/api-next/get-positions.test.ts
 PASS  src/tests/unit/api-next/get-historical-data-updates.test.ts
 PASS  src/tests/unit/api-next/get-current-time.test.ts
 PASS  src/tests/unit/api-next/ib-api-next-map.test.ts

Test Suites: 4 failed, 12 passed, 16 total
Tests:       11 failed, 32 passed, 43 total
Snapshots:   0 total
Time:        103.334 s
Ran all test suites.

How To Subscribe To Delayed Market Data?

Hi there!
First of all...congrats!! The library is absolutely amazing.
I'm using [email protected].

I would like to receive delayed market data from my paper account. This is what I've done:

export class TwsService {
  private _client = new IBApiNext({
    host: '127.0.0.1',
    port: 7497,
  });

  constructor() {
    this._client = this._client.connect();
  }

  public getMarketData(contract: Contract): Observable<MarketDataUpdate> {
    contract.exchange = 'SMART';
    this._client.setMarketDataType(MarketDataType.DELAYED);
    const obs = this._client.getMarketData(contract, '221', false, false);
    return obs;
  }
}

However, the error I get is:
error: Error: Requested market data is not subscribed. Displaying delayed market data.

What am I missing?
Thank you for your incredible work, once again

Error requesting market data for options contract - When the local symbol field is empty, please fill the following fields (right, strike, expiry)

I have a market data subscription for equities and options. If I submit a reqMktData for an options contract, I keep getting an error message
"Error validating request.-'b1' : cause - When the local symbol field is empty, please fill the following fields (right, strike, expiry) - code: 321 - reqId: 1".

Sending a market data request for stocks works fine but its only with options where I get an error: Below is my request:

let contract = new Option('NVDA', '20230713', 440, OptionType.Call);

Once I received the 'connected' event, I send the following:
ib.reqMarketDataType(4);
ib.reqMktData(1, contract, "", false, false, [])

Prior to sending the mktdata request, I console logged the contract detail to confirm I have the fields filled out
Option {
symbol: 'NVDA',
expiry: '20230713',
strike: 440,
right: 'C',
exchange: 'SMART',
currency: 'USD',
secType: 'OPT',
multiplier: 100
}`

Any help or guidance would be appreciated.

IB API timeouts for large data requests

Is there a way to set a longer timeout interval for large data requests, or handle / avoid / correct api timeouts for large data requests?
In TWS, I tried changing the value of edit>Global Configuration>API>Settings>Timeout to send bulk data to API, but this did not seem to produce a change in behavior, the timeout is still generated at 30s after the request is submitted.

Why do you need large requests?
The API provides historical ADJUSTED_LAST data, apparently going back a long way. For example:
{contract: Contract.stock('GE'),duration: '10 Y', barSizeSetting: '1 hour', whatToShow: 'ADJUSTED_LAST', useRth: 1, formatDate: 1}
However, pulling a lot of data results in an api timeout.
I don't see a way to page the data because with the use of whatToShow: 'ADJUSTED_LAST', it is disallowed to use endDateTime to request the data in chunks. There are probably other circumstances where people need to make large data requests.

Is there a way to override the api timeout duration, or otherwise succeed in making a large data request?

Thank you

Error: Decoding error on OPEN_ORDER: unprocessed data left on queue

After submitting complex order with "hedgeType": "P" I get this error in the log

Decoding error on OPEN_ORDER: unprocessed data left on queue

(["0","None","1.7976931348623157E308","62.0","1.7976931348623157E308","1.7976931348623157E308","1.7976931348623157E308","1.7976931348623157E308","0","","","","0","0","0","0","0",null]).

Please report to https://github.com/stoqey/ib 
- code: 505 - reqId: -1 Error: Decoding error on OPEN_ORDER: unprocessed data left on queue 
(["0","None","1.7976931348623157E308","62.0","1.7976931348623157E308","1.7976931348623157E308","1.7976931348623157E308","1.7976931348623157E308","0","","","","0","0","0","0","0",null]). 
Please report to https://github.com/stoqey/ib

This is the order submitted:

[
  {
    "order": {
      "action": "BUY",
      "tif": "GTC",
      "orderType": "LMT",
      "totalQuantity": 1,
      "lmtPrice": 73.5,
      "auxPrice": 0,
      "transmit": false,
      "conditions": [
        {
          "time": "20211107 11:11:00",
          "isMore": true,
          "conjunctionConnection": "o",
          "type": 3
        }
      ],
      "conditionsCancelOrder": true,
      "conditionsIgnoreRth": false,
      "orderId": 92
    },
    "contract": {
      "symbol": "ES",
      "secType": "FOP",
      "lastTradeDateOrContractMonth": "20211217 08:30 CST",
      "strike": 4630,
      "right": "C",
      "exchange": "GLOBEX",
      "currency": "USD",
      "localSymbol": "ESZ1 C4630",
      "tradingClass": "ES",
      "multiplier": 50
    }
  },
  {
    "order": {
      "action": "SELL",
      "orderType": "MKT",
      "tif": "GTC",
      "totalQuantity": 0,
      "transmit": false,
      "conditionsCancelOrder": false,
      "conditionsIgnoreRth": false,
      "hedgeType": "P",
      "hedgeParam": "1",
      "conditions": [
        {
          "price": 4628.5,
          "triggerMethod": 0,
          "conId": 446091461,
          "exchange": "GLOBEX",
          "isMore": true,
          "conjunctionConnection": "a",
          "type": 1
        },
        {
          "price": 110.25,
          "triggerMethod": 1,
          "conId": 497082427,
          "exchange": "GLOBEX",
          "isMore": true,
          "conjunctionConnection": "a",
          "type": 1
        }
      ],
      "orderId": 93,
      "parentId": 92
    },
    "contract": {
      "symbol": "ES",
      "secType": "FOP",
      "lastTradeDateOrContractMonth": "20211217 08:30 CST",
      "strike": 4650,
      "right": "C",
      "exchange": "GLOBEX",
      "currency": "USD",
      "localSymbol": "ESZ1 C4650",
      "tradingClass": "ES",
      "multiplier": 50,
      "primaryExch": ""
    }
  },
  {
    "order": {
      "action": "SELL",
      "orderType": "MKT",
      "tif": "GTC",
      "totalQuantity": 1,
      "conditions": [
        {
          "time": "20211212 11:11:00",
          "isMore": true,
          "conjunctionConnection": "o",
          "type": 3
        }
      ],
      "transmit": false,
      "conditionsCancelOrder": false,
      "conditionsIgnoreRth": false,
      "orderId": 94,
      "parentId": 92
    },
    "contract": {
      "symbol": "ES",
      "secType": "FOP",
      "lastTradeDateOrContractMonth": "20211217 08:30 CST",
      "strike": 4630,
      "right": "C",
      "exchange": "GLOBEX",
      "currency": "USD",
      "localSymbol": "ESZ1 C4630",
      "tradingClass": "ES",
      "multiplier": 50
    }
  }
]

open order event decoder error

After sending an successful order to IB TWS there are 2 issues.

  1. I'm not sure how to switch successfully between preMarket allowed orders and Afterhours (Outside - RHA or whatev) Premarket orders can be done with IB API order template default value only at this point?

  2. After the order is successfully processed. Facing decoder issue. Haven't dug into code yet.

Decoding error on decodeMsg_OPEN_ORDER: unprocessed data left on queue. Please report to https://github.com/stoqey/ib - code: 505 - reqId: -1' Error: Decoding error on decodeMsg_OPEN_ORDER: unprocessed data left on queue. Please report to https://github.com/stoqey/ib

Volume of historical data is always -1

I am using client.reqHistoricalData but every candle that I get has a volume of -1. Am I doing something wrong here?

client
  .on(EventName.error, error => {
    reject(error);
  })
  .on(
    EventName.historicalData,
    (
      reqId: number,
      timeInSeconds: string,
      open: number,
      high: number,
      low: number,
      close: number,
      volume: number
    ) => {
      if (timeInSeconds.startsWith('finished')) {
        client.unsubscribeFromGroupEvents(reqId);
      } else {
        console.log('volume', volume);
      }
    }
  );

const useRegularTradingHours = 0;
const dateFormat = 2;

client.reqHistoricalData(
  1337,
  new Stock('AAPL', undefined, 'USD'),
  '20210810 17:00:00 UTC',
  `3600 S`,
  BarSizeSetting.HOURS_ONE,
  'BID_ASK',
  useRegularTradingHours,
  dateFormat,
  false
);

Tested with @stoqey/ib v1.2.5.

API client version missing

First time trying to connect with IBKR API. I don't know if I missed some step, just I am stupid etc. Tried to google that error, but personally didn't found anything. Used just example code.

IB Gateway Build 978.2n, Feb 17, 2021 2:48:21 PM

JS:
Uncaught TypeError: Invalid data, chunk must be a string or buffer, not object at Socket.write (net.js:701) at Socket.send (...\node_modules\@stoqey\ib\dist\io\socket.js:166) at Socket.onConnect (...\node_modules\@stoqey\ib\dist\io\socket.js:315) at Socket.client.net_1.default.connect (...\node_modules\@stoqey\ib\dist\io\socket.js:113) at Object.onceWrapper (events.js:313) at emitNone (events.js:111) at Socket.emit (events.js:208) at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1169)

IB Gateway logs:
2021-03-04 22:09:02.777 [VW] INFO [JTS-SocketListener-48] - Error identifying stream Connection reset 2021-03-04 22:09:02.778 [VW] INFO [JTS-SocketListener-48] - State: STOP, IsAPI: NO 2021-03-04 22:09:02.778 [VW] ERROR [JTS-SocketListener-48] - API failed to read client version java.net.SocketException: Connection reset at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at jextend.io.a.a(a.java:234) at jextend.io.a.b(a.java:208) at jextend.eh.d(eh.java:65) at jextend.bg.a(bg.java:770) at jextend.bg.b(bg.java:341) at jextend.cH.b(cH.java:349) at jextend.bg.p(bg.java:912) at jextend.ex.c(ex.java:480) at jextend.ex.run(ex.java:299) at java.lang.Thread.run(Unknown Source) 2021-03-04 22:09:02.778 [VW] WARN [JTS-SocketListener-48] - Error twslaunch.jutils.SLogging$Warning: API client version is missing. at twslaunch.jutils.at.v(at.java:263) at jextend.ex.run(ex.java:302) at java.lang.Thread.run(Unknown Source)

Does ApiNext support reqTickByTickData?

From the source codes, it seem that apiNext.getMarketData(...) is an wrapper for api.reqMktData(...).

Does apiNext have the function similar to api.reqTickByTickData(...)?

Thanks.

How to send first stock order? [ Help wanted ]

Could someone from the team help me out with sending the first stock order?

I'm getting Socket Error -

Update: updating the code

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();

The error I'm facing...

Error reading request.Message id 1. Socket I/O error - - code: 320 - reqId: 1
I was unable to determine the origin of where it fired off.

Would appreciate any help from the team. I'd also include the example in the readme.

handling multiple simultaneous subscriptions

I think below does not guarantee that an event handler (which is correctly added only once on first of multiple simultaneous subscriptions) updates all subscriptions, since basically this starts from a new empty reqIds Set each time you call getPositions so the event handler will only see 1 subscription (the first one). You'd need a static variable inside the method but that doesn't exist in JS...

A solution can be to have an ivar reqIdsByEventName in the class, and then add/remove to/fromreqIdsByEventName[EventName.position] in your request & cancel functions as in below, as you start/stop subscriptions that would generate that event. Then in your event handler loop over all those reqIds.

This one is tricky since you don't get a reqId in the callback...

getPositions(): Observable<PositionsUpdate> {
    const requestIds = new Set<number>();

    // position event handler
    const onPosition = (account: string, contract: IContract, pos: number, avgCost: number): void => {
      const updatedPosition: Position = { account, contract, pos, avgCost };
          requestIds.forEach((id) => {
          // get subscription
          const subscription = this._subscriptions.get(id) as IBApiNextSubscription<PositionsUpdate>;
          if (!subscription) {
            return;
          }
// ...
    }

// ...
    // register event handlers
    this.registerEventHandler(EventName.position, onPosition);
// ...

    // create the subscription
    return new IBApiNextSubscription<PositionsUpdate>(
      this,
      this._subscriptions,
      (reqId) => {
        requestIds.add(reqId);
        this._api.reqPositions();
      },
      (reqId) => {
        this._api.cancelPositions();
        requestIds.delete(reqId);
      },
    ).createObservable();

Implement IBApiNext

Edit:
Latest information about IBApiNext can be found on https://github.com/stoqey/ib/wiki/IBApi-next-generation-(IBApiNext)

IBApiNext will be an second, more modern way of using IB API, in parallel (actually on top) of current IBApi interface.
Development will happen on https://github.com/stoqey/ib/tree/api-next
Design goal:

  • Provide support for automatic re-connection, including a watchdog that regularly checks the connection (not relying on socket termination events). A preview of this is available on https://github.com/stoqey/ib/blob/api-next/src/api/api-auto-connection.ts
    The IBApiAutoConnection object does host an IBApi (use IBApiAutoConnection.api to access it), handles connect / disconnect / error events and provides connect & disconnect functions. It implements a connection-state watchdog and re-connect timer.
  • Provide rxjs wrappers for all req/cancel methods and introduce better TS compatibility (i.e. return undefined instead of MAX_VALUE).
    This has been started on https://github.com/stoqey/ib/blob/api-next/src/api/api-next.ts
    Basic design pattern: a function must return an rxjs Observable that first delivers any cached values and than notifies about changes.

@Tsopic feel free to comment or continue to work on it (I will spend more time on that over the weekend, so by next week we should have most the of read-only methods as rxjs) ;)

The container name "/ib-api" is already in use

I cloned this repo and executed all steps descripted in test locally. Unfortunately, it crashes on my end after the last build step:

Step 9/10 : ENV NODE_ENV development
 ---> Running in 8594b5a5914e
Removing intermediate container 8594b5a5914e
 ---> 996fb3732c20
Step 10/10 : CMD ["node","./dist/tools/positions.js", "-watch"]
 ---> Running in 96881fa0bc47
Removing intermediate container 96881fa0bc47
 ---> ff129a7b7581

Successfully built ff129a7b7581
Successfully tagged ib_ib-api:latest
WARNING: Image for service ib-api was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating ib_tws_1 ... done
Creating ib-api   ... error

ERROR: for ib-api  Cannot create container for service ib-api: Conflict. The container name "/ib-api" is already in use by container "fdb5e8893d149718d710db8b5c267ac2f7c8fb275c57ff017dadaec91bda2b02". You have to remove (or rename) that container to be able to reuse that name.

ERROR: for ib-api  Cannot create container for service ib-api: Conflict. The container name "/ib-api" is already in use by container "fdb5e8893d149718d710db8b5c267ac2f7c8fb275c57ff017dadaec91bda2b02". You have to remove (or rename) that container to be able to reuse that name.
ERROR: Encountered errors while bringing up the project.

Error when trying to get empty list of open orders

If the list of open orders is empty, an error is thrown

code: await ibApiNext.getAllOpenOrders();

/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/util/createErrorClass.ts:13
    instance.stack = new Error().stack;
                     ^
Error
    at _super (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/util/createErrorClass.ts:13:22)
    at new EmptyErrorImpl (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/util/EmptyError.ts:26:3)
    at Object.complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/lastValueFrom.ts:72:18)
    at Object.complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:194:14)
    at SafeSubscriber.Subscriber._complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:132:24)
    at SafeSubscriber.Subscriber.complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:106:12)
    at OperatorSubscriber.Subscriber._complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:132:24)
    at OperatorSubscriber.Subscriber.complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:106:12)
    at OperatorSubscriber.Subscriber._complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:132:24)
    at OperatorSubscriber.Subscriber.complete (/Users/ildar/DIPLOM/ibkr-signal/node_modules/rxjs/src/internal/Subscriber.ts:106:12) {
  message: 'no elements in sequence'
}

Can you return promise from IbApiNext.connect()?

After connecting, I have to execute sleep function (const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) in the code so that the system has time to connect and then perform operations.

Can IbApiNext return a promise to not rely on setTimeout?

Now:

ib.connect();

sleep(1000) // 🤮
.then(() => {
  positionsSubscription = ib.getPositions().subscribe(_ => positions = _);
})

Would like:

ib.connect()
.then(() => {
  positionsSubscription = ib.getPositions().subscribe(_ => positions = _);
})

Error: Decoding error on undefined: unprocessed data left on queue

Hello, I'd just received this error while using the API:
Error: Decoding error on undefined: unprocessed data left on queue (["20230727 02:49:21 EST",null]). Please report to https://github.com/stoqey/ib 505
It says to report it, so I am making this issue thread, feel free to close.
To get this error, I am using the reqMatchingSymbols method on IBApi. In particular, I am using React to take a text input, and whenver the user types, then sending this request using your library to IB, and getting the response. Furthermore, I am using both the ib.connect and ib.disconnect method every time the user types a single character in the react field, and the data itself is passed through electron IPC, so there is a lot of friction.Therefore, this error is most likely due to a very large amount of requests in a short amount of time, as I'm getting a couple other errors such as "Error: No parser implementation found for token: undefined (166). 505". If you would like to see the code, please let me know. Thank you for your time.

How to unsubscribe to e.g. getMarketData?

it might be something extremely obvious, but I just can't wrap my head around, so, apologies for opening a ticket in advance.

I am creating a new subscription to getMarketData - that works fine.

Then I get a subscription object back and so a .subscribe({next... etc etc})

I tried to .unsubscribe() on that subscription object, that isn't working.

How to unsubscribe to a market subscription?

Update to TS 4.1

Backlog item:
Current code still is mix between old-school-JS-style-Typescript and TS 3.7 as main focus for v1.0.0 was to port existing code from JS to TS.
We should spend some more time on code-cleanup and bring all codebase to TS 4.1.
Top prio:
Consistently introduce Optional Chaining + review API for correct usage of ? and ! operators on attributes.
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html
Than we should enable:
"noImplicitAny": true
"strictNullChecks": true,
"strictFunctionTypes": true
"strictBindCallApply": true
"strictPropertyInitialization": true
"noImplicitThis": true,
"noUnusedParameters": true
"noImplicitReturns": true
on tsconf at least and fix compile errors as they show up.

Searching securities

As requested, I'm moving this issue on this repo (stoqey/ibkr#91).

--
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 ?

EventName.info missing id

Hello, could you please add the reqId and errorCode to the ib.on(EventName.info ?
The reqId (-1) and ErrorCore (2158) is being received so it should be easy for you to add it

received [
  [
    '4',
    '2',
    '-1',
    '2158',
    'Sec-def data farm connection is OK:secdefil',
    ''
  ],
  '4\x002\x00-1\x002158\x00Sec-def data farm connection is OK:secdefil\x00\x00'
]

You may ask why? Its simple, I am building a bot for people and I need to know about every info, and there are many languages in the TWS and also on its white label, so message only is not practical because it would be different in each language, however code is always the same.
Right now there is only message listener but the error code is very important for me and I would be glad if you could add it there.
Thank you

Conditional orders raise issues when used

We already have it on https://github.com/stoqey/ib
Have a look at https://github.com/stoqey/ib/tree/master/src/api/order/condition and pick the conditions you need.
Than set it to Oder.conditions (works similar to official TWS API Order.Conditions )

Originally posted by @mfrener in stoqey/ibkr#38 (comment)


First of all, thanks for the work on this very useful api.

Whatever the tests I made with conditional orders, TWS raise an issue when placing the order.

Here is the printing of the condition list (one condition) :

Placing BUY order AAPL 20230616 130 with conditions : [
PriceCondition {
price: 29,
triggerMethod: 0,
conId: 478483723,
exchange: 'CBOE',
isMore: true,
conjunctionConnection: 'o',
type: 1
}
]

Below the error raised;

Erreur de lecture de la demande.Message id 2989. Unable to parse data. java.lang.NumberFormatException: For input string: "o" - code: 320 - reqId: 2989
Erreur de lecture de la demande.Message id 478483723. Unable to parse data. java.lang.NumberFormatException: For input string: "CBOE" - code: 320 - reqId: 478483723

Please find below the whole test code.

export function test() {
let optionType: OptionType;
let multiplier: number;
let orderId: number;
let symbol: string;
let strike: number;
let expirationDate: string;
let quantity: number;
let exchange: string;
let conditions: Array;
let oneCondition : OrderCondition;

symbol = 'AAPL';
strike = 130;
multiplier = 100;
orderId = nextValidID; // Actually picked from event nextValidId : .on(EventName.nextValidId...)
optionType = OptionType.Call;
expirationDate = '20230616';
quantity = 1;
exchange = 'CBOE';

conditions = new Array()

// Condition data
let triggerPrice : number = 29;
let conID : number = 478483723;
let isMore : boolean = true;

oneCondition = new PriceCondition(triggerPrice, TriggerMethod.Default, conID, exchange, isMore, ConjunctionConnection.OR);
conditions.push(oneCondition);

// Contract definition
let contract: Contract = {
symbol: symbol,
exchange: exchange,
currency: "USD",
secType: SecType.OPT,
right: optionType,
lastTradeDateOrContractMonth: expirationDate,
strike: strike,
multiplier: multiplier,
};

// Order definition
let order: Order = {
orderType: OrderType.MKT,
action: OrderAction.BUY,
orderId: orderId,
totalQuantity: quantity,
account: Config.ACCOUNT,
transmit: true,
conditions: conditions // Once this conditions line removed its works
};

console.log(Placing BUY order ${symbol} ${expirationDate} ${strike} with conditions : , conditions);
ib.placeOrder(orderId, contract, order);
}

Is it possible to have an example of how it should be implemented ?

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.