@stoqey/ib
Version:
Interactive Brokers TWS/IB Gateway API client library for Node.js (TS)
1,201 lines • 114 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Decoder = exports.UnderrunError = void 0;
const event_name_1 = require("../../api/data/enum/event-name");
const min_server_version_1 = __importDefault(require("../../api/data/enum/min-server-version"));
const option_type_1 = __importDefault(require("../../api/data/enum/option-type"));
const sec_type_1 = __importDefault(require("../../api/data/enum/sec-type"));
const tickType_1 = require("../../api/market/tickType");
const execution_condition_1 = __importDefault(require("../../api/order/condition/execution-condition"));
const margin_condition_1 = __importDefault(require("../../api/order/condition/margin-condition"));
const percent_change_condition_1 = __importDefault(require("../../api/order/condition/percent-change-condition"));
const price_condition_1 = __importDefault(require("../../api/order/condition/price-condition"));
const time_condition_1 = __importDefault(require("../../api/order/condition/time-condition"));
const volume_condition_1 = __importDefault(require("../../api/order/condition/volume-condition"));
const order_condition_type_1 = require("../../api/order/enum/order-condition-type");
const orderType_1 = require("../../api/order/enum/orderType");
const errorCode_1 = require("../../common/errorCode");
const in_msg_id_1 = require("./enum/in-msg-id");
/**
* @internal
*
* Verify if the value is a valid OptionType.
* Returns the value is valid, undefined otherwise.
*/
function validateOptionType(v) {
return Object.values(option_type_1.default).indexOf(v) !== -1 ? v : undefined;
}
/**
* @internal
*
* An underrun error on the input de-serialization.
*/
class UnderrunError extends Error {
constructor(message = "An underrun error has occurred") {
super();
this.message = message;
this.stack = new Error().stack;
this.name = "UnderrunError";
}
}
exports.UnderrunError = UnderrunError;
/**
* @internal
*
* Class for decoding token data to messages and emitting events it to the
* [[Controller]] event queue.
*/
class Decoder {
/**
* Create an [[Incoming]] object.
*
* @param callback A [[DecoderCallbacks]] implementation.
*/
constructor(callback) {
this.callback = callback;
/**
* Input data queue.
*
* If the value is a string, this is a tokens as received from TWS / IB Gateway.
* If the value is undefined, this signals the boundary (start or end) of a message (used with V100 protocol only).
*/
this.dataQueue = [];
/** Data emit queue (data to be emitted to controller). */
this.emitQueue = [];
/**
* Read a token from queue and return it as boolean value.
*
* @deprecated readBool is probably what you are looking for
*/
this.readBoolFromInt = this.readBool;
/**
* Read a token from queue and return it as integer value.
*
* Returns Number.MAX_VALUE if the token is empty.
* @deprecated readIntOrUndefined is probably what you are looking for
*/
this.readIntMax = this.readIntOrUndefined;
}
/**
* Add a new message to queue.
*
* Used on V100 protocol.
*/
enqueueMessage(tokens) {
this.dataQueue.push(undefined); // signal start boundary
this.dataQueue = this.dataQueue.concat(tokens);
this.dataQueue.push(undefined); // signal end boundary
}
/**
* Add new tokens to queue.
*
* Used on pre-V100 protocol.
*/
enqueueTokens(tokens) {
this.dataQueue = this.dataQueue.concat(tokens);
}
/**
* Process a message on data queue.
*/
processMsg(msgId) {
switch (msgId) {
case in_msg_id_1.IN_MSG_ID.TICK_PRICE:
return this.decodeMsg_TICK_PRICE();
case in_msg_id_1.IN_MSG_ID.TICK_SIZE:
return this.decodeMsg_TICK_SIZE();
case in_msg_id_1.IN_MSG_ID.ORDER_STATUS:
return this.decodeMsg_ORDER_STATUS();
case in_msg_id_1.IN_MSG_ID.ERR_MSG:
return this.decodeMsg_ERR_MSG();
case in_msg_id_1.IN_MSG_ID.OPEN_ORDER:
return this.decodeMsg_OPEN_ORDER();
case in_msg_id_1.IN_MSG_ID.ACCT_VALUE:
return this.decodeMsg_ACCT_VALUE();
case in_msg_id_1.IN_MSG_ID.PORTFOLIO_VALUE:
return this.decodeMsg_PORTFOLIO_VALUE();
case in_msg_id_1.IN_MSG_ID.ACCT_UPDATE_TIME:
return this.decodeMsg_ACCT_UPDATE_TIME();
case in_msg_id_1.IN_MSG_ID.NEXT_VALID_ID:
return this.decodeMsg_NEXT_VALID_ID();
case in_msg_id_1.IN_MSG_ID.CONTRACT_DATA:
return this.decodeMsg_CONTRACT_DATA();
case in_msg_id_1.IN_MSG_ID.EXECUTION_DATA:
return this.decodeMsg_EXECUTION_DATA();
case in_msg_id_1.IN_MSG_ID.MARKET_DEPTH:
return this.decodeMsg_MARKET_DEPTH();
case in_msg_id_1.IN_MSG_ID.MARKET_DEPTH_L2:
return this.decodeMsg_MARKET_DEPTH_L2();
case in_msg_id_1.IN_MSG_ID.NEWS_BULLETINS:
return this.decodeMsg_NEWS_BULLETINS();
case in_msg_id_1.IN_MSG_ID.MANAGED_ACCTS:
return this.decodeMsg_MANAGED_ACCTS();
case in_msg_id_1.IN_MSG_ID.RECEIVE_FA:
return this.decodeMsg_RECEIVE_FA();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_DATA:
return this.decodeMsg_HISTORICAL_DATA();
case in_msg_id_1.IN_MSG_ID.BOND_CONTRACT_DATA:
return this.decodeMsg_BOND_CONTRACT_DATA();
case in_msg_id_1.IN_MSG_ID.SCANNER_PARAMETERS:
return this.decodeMsg_SCANNER_PARAMETERS();
case in_msg_id_1.IN_MSG_ID.SCANNER_DATA:
return this.decodeMsg_SCANNER_DATA();
case in_msg_id_1.IN_MSG_ID.TICK_OPTION_COMPUTATION:
return this.decodeMsg_TICK_OPTION_COMPUTATION();
case in_msg_id_1.IN_MSG_ID.TICK_GENERIC:
return this.decodeMsg_TICK_GENERIC();
case in_msg_id_1.IN_MSG_ID.TICK_STRING:
return this.decodeMsg_TICK_STRING();
case in_msg_id_1.IN_MSG_ID.TICK_EFP:
return this.decodeMsg_TICK_EFP();
case in_msg_id_1.IN_MSG_ID.CURRENT_TIME:
return this.decodeMsg_CURRENT_TIME();
case in_msg_id_1.IN_MSG_ID.REAL_TIME_BARS:
return this.decodeMsg_REAL_TIME_BARS();
case in_msg_id_1.IN_MSG_ID.FUNDAMENTAL_DATA:
return this.decodeMsg_FUNDAMENTAL_DATA();
case in_msg_id_1.IN_MSG_ID.CONTRACT_DATA_END:
return this.decodeMsg_CONTRACT_DATA_END();
case in_msg_id_1.IN_MSG_ID.OPEN_ORDER_END:
return this.decodeMsg_OPEN_ORDER_END();
case in_msg_id_1.IN_MSG_ID.ACCT_DOWNLOAD_END:
return this.decodeMsg_ACCT_DOWNLOAD_END();
case in_msg_id_1.IN_MSG_ID.EXECUTION_DATA_END:
return this.decodeMsg_EXECUTION_DATA_END();
case in_msg_id_1.IN_MSG_ID.DELTA_NEUTRAL_VALIDATION:
return this.decodeMsg_DELTA_NEUTRAL_VALIDATION();
case in_msg_id_1.IN_MSG_ID.TICK_SNAPSHOT_END:
return this.decodeMsg_TICK_SNAPSHOT_END();
case in_msg_id_1.IN_MSG_ID.MARKET_DATA_TYPE:
return this.decodeMsg_MARKET_DATA_TYPE();
case in_msg_id_1.IN_MSG_ID.COMMISSION_REPORT:
return this.decodeMsg_COMMISSION_REPORT();
case in_msg_id_1.IN_MSG_ID.POSITION:
return this.decodeMsg_POSITION();
case in_msg_id_1.IN_MSG_ID.POSITION_END:
return this.decodeMsg_POSITION_END();
case in_msg_id_1.IN_MSG_ID.ACCOUNT_SUMMARY:
return this.decodeMsg_ACCOUNT_SUMMARY();
case in_msg_id_1.IN_MSG_ID.ACCOUNT_SUMMARY_END:
return this.decodeMsg_ACCOUNT_SUMMARY_END();
/* For IB's internal purpose - not implement:
case IN_MSG_ID.VERIFY_MESSAGE_API:
case IN_MSG_ID.VERIFY_COMPLETED:
*/
case in_msg_id_1.IN_MSG_ID.DISPLAY_GROUP_LIST:
return this.decodeMsg_DISPLAY_GROUP_LIST();
case in_msg_id_1.IN_MSG_ID.DISPLAY_GROUP_UPDATED:
return this.decodeMsg_DISPLAY_GROUP_UPDATED();
/* For IB's internal purpose - not implement:
case IN_MSG_ID.VERIFY_AND_AUTH_MESSAGE_API:
case IN_MSG_ID.VERIFY_AND_AUTH_COMPLETED
*/
case in_msg_id_1.IN_MSG_ID.POSITION_MULTI:
return this.decodeMsg_POSITION_MULTI();
case in_msg_id_1.IN_MSG_ID.POSITION_MULTI_END:
return this.decodeMsg_POSITION_MULTI_END();
case in_msg_id_1.IN_MSG_ID.ACCOUNT_UPDATE_MULTI:
return this.decodeMsg_ACCOUNT_UPDATE_MULTI();
case in_msg_id_1.IN_MSG_ID.ACCOUNT_UPDATE_MULTI_END:
return this.decodeMsg_ACCOUNT_UPDATE_MULTI_END();
case in_msg_id_1.IN_MSG_ID.SECURITY_DEFINITION_OPTION_PARAMETER:
return this.decodeMsg_SECURITY_DEFINITION_OPTION_PARAMETER();
case in_msg_id_1.IN_MSG_ID.SECURITY_DEFINITION_OPTION_PARAMETER_END:
return this.decodeMsg_SECURITY_DEFINITION_OPTION_PARAMETER_END();
case in_msg_id_1.IN_MSG_ID.SOFT_DOLLAR_TIERS:
return this.decodeMsg_SOFT_DOLLAR_TIERS();
case in_msg_id_1.IN_MSG_ID.FAMILY_CODES:
return this.decodeMsg_FAMILY_CODES();
case in_msg_id_1.IN_MSG_ID.SYMBOL_SAMPLES:
return this.decodeMsg_SYMBOL_SAMPLES();
case in_msg_id_1.IN_MSG_ID.MKT_DEPTH_EXCHANGES:
return this.decodeMsg_MKT_DEPTH_EXCHANGES();
case in_msg_id_1.IN_MSG_ID.TICK_REQ_PARAMS:
return this.decodeMsg_TICK_REQ_PARAMS();
case in_msg_id_1.IN_MSG_ID.SMART_COMPONENTS:
return this.decodeMsg_SMART_COMPONENTS();
case in_msg_id_1.IN_MSG_ID.NEWS_ARTICLE:
return this.decodeMsg_NEWS_ARTICLE();
case in_msg_id_1.IN_MSG_ID.TICK_NEWS:
return this.decodeMsg_TICK_NEWS();
case in_msg_id_1.IN_MSG_ID.NEWS_PROVIDERS:
return this.decodeMsg_NEWS_PROVIDERS();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_NEWS:
return this.decodeMsg_HISTORICAL_NEWS();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_NEWS_END:
return this.decodeMsg_HISTORICAL_NEWS_END();
case in_msg_id_1.IN_MSG_ID.HEAD_TIMESTAMP:
return this.decodeMsg_HEAD_TIMESTAMP();
case in_msg_id_1.IN_MSG_ID.HISTOGRAM_DATA:
return this.decodeMsg_HISTOGRAM_DATA();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_DATA_UPDATE:
return this.decodeMsg_HISTORICAL_DATA_UPDATE();
case in_msg_id_1.IN_MSG_ID.REROUTE_MKT_DATA:
return this.decodeMsg_REROUTE_MKT_DATA();
case in_msg_id_1.IN_MSG_ID.REROUTE_MKT_DEPTH:
return this.decodeMsg_REROUTE_MKT_DEPTH();
case in_msg_id_1.IN_MSG_ID.MARKET_RULE:
return this.decodeMsg_MARKET_RULE();
case in_msg_id_1.IN_MSG_ID.PNL:
return this.decodeMsg_PNL();
case in_msg_id_1.IN_MSG_ID.PNL_SINGLE:
return this.decodeMsg_PNL_SINGLE();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_TICKS:
return this.decodeMsg_HISTORICAL_TICKS();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_TICKS_BID_ASK:
return this.decodeMsg_HISTORICAL_TICKS_BID_ASK();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_TICKS_LAST:
return this.decodeMsg_HISTORICAL_TICKS_LAST();
case in_msg_id_1.IN_MSG_ID.TICK_BY_TICK:
return this.decodeMsg_TICK_BY_TICK();
case in_msg_id_1.IN_MSG_ID.ORDER_BOUND:
return this.decodeMsg_ORDER_BOUND();
case in_msg_id_1.IN_MSG_ID.COMPLETED_ORDER:
return this.decodeMsg_COMPLETED_ORDER();
case in_msg_id_1.IN_MSG_ID.COMPLETED_ORDERS_END:
return this.decodeMsg_COMPLETED_ORDERS_END();
case in_msg_id_1.IN_MSG_ID.REPLACE_FA_END:
return this.decodeMsg_REPLACE_FA_END();
case in_msg_id_1.IN_MSG_ID.WSH_META_DATA:
return this.decodeMsg_WSH_META_DATA();
case in_msg_id_1.IN_MSG_ID.WSH_EVENT_DATA:
return this.decodeMsg_WSH_EVENT_DATA();
case in_msg_id_1.IN_MSG_ID.HISTORICAL_SCHEDULE:
return this.decodeMsg_HISTORICAL_SCHEDULE();
case in_msg_id_1.IN_MSG_ID.USER_INFO:
return this.decodeMsg_USER_INFO();
default:
this.callback.emitError(`No parser implementation found for token: ${in_msg_id_1.IN_MSG_ID[msgId]} (${msgId}).`, errorCode_1.ErrorCode.UNKNOWN_ID);
}
}
/**
* Process the data queue and emit events.
*/
process() {
while (true) {
// verify there is data to process
if (!this.dataQueue.length) {
break;
}
// clear event queue
this.emitQueue = [];
// check if there is a message boundary marker
let verifyMessageBoundary = false;
if (this.dataQueue[0] === undefined) {
verifyMessageBoundary = true;
this.dataQueue.shift();
}
let msgId = in_msg_id_1.IN_MSG_ID.UNDEFINED;
try {
// process message (invoke decoder function)
msgId = this.readInt();
this.processMsg(msgId);
// check if all of the message data was processed and drain any remaining tokens
if (verifyMessageBoundary) {
if (this.dataQueue[0] !== undefined) {
this.callback.emitError(`Decoding error on ${in_msg_id_1.IN_MSG_ID[msgId]}: unprocessed data left on queue (${JSON.stringify(this.dataQueue)}). Please report to https://github.com/stoqey/ib`, errorCode_1.ErrorCode.UNKNOWN_ID);
}
this.drainQueue();
}
}
catch (e) {
if (e.name !== "UnderrunError") {
throw e;
}
if (verifyMessageBoundary) {
this.callback.emitError(`Underrun error on ${in_msg_id_1.IN_MSG_ID[msgId]}: ${e.message} Please report to https://github.com/stoqey/ib`, errorCode_1.ErrorCode.UNKNOWN_ID);
}
this.drainQueue();
}
// Emit events
const toEmit = this.emitQueue;
this.emitQueue = [];
toEmit.forEach((item) => this.callback.emitEvent(item.name, ...item.args));
}
}
/**
* Get the API server version.
*/
get serverVersion() {
return this.callback.serverVersion;
}
decodeUnicodeEscapedString(str) {
let v = str;
try {
while (true) {
const escapeIndex = v.indexOf("\\u");
if (escapeIndex == -1 || v.length - escapeIndex < 6) {
break;
}
const escapeString = v.substring(escapeIndex, escapeIndex + 6);
const hexVal = parseInt(escapeString.replace("\\u", ""), 16);
v = v.replace(escapeString, String.fromCharCode(hexVal));
}
}
catch (_e) {
/* TODO: handle error? */
}
return v;
}
/**
* Read a string token from queue.
*/
readStr() {
if (this.dataQueue.length === 0) {
throw new UnderrunError();
}
const val = this.dataQueue.shift();
if (val === undefined) {
throw new UnderrunError("End of message reached.");
}
return val;
}
/**
* Read a token from queue and return it as boolean value.
*/
readBool() {
return !!parseInt(this.readStr());
}
/**
* Read a token from queue and return it as floating point value.
*
* Returns 0 if the token is empty.
* Returns undefined is the token is Number.MAX_VALUE.
*/
readDouble() {
const token = this.readStr();
if (token === "") {
return 0;
}
const val = parseFloat(token);
return val === Number.MAX_VALUE ? undefined : val;
}
/**
* Read a token from queue and return it as floating point value.
*
* Returns undefined if the token is empty or is Number.MAX_VALUE.
*/
readDecimal() {
const token = this.readStr();
if (token === "") {
return undefined;
}
const val = parseFloat(token.replaceAll(",", ""));
return val === Number.MAX_VALUE || val === Infinity ? undefined : val;
}
/**
* Read a token from queue and return it as floating point value.
*
* Returns undefined if the token is empty or Number.MAX_VALUE.
*/
readDoubleOrUndefined() {
const token = this.readStr();
if (token === "") {
return undefined;
}
const val = parseFloat(token);
return val === Number.MAX_VALUE ? undefined : val;
}
/**
* Read a token from queue and return it as integer value.
*
* Returns 0 if the token is empty.
*/
readInt() {
const token = this.readStr();
if (token === "") {
return 0;
}
const val = parseInt(token, 10);
return val;
}
/**
* Read a token from queue and return it as integer value.
*
* Returns undefined if the token is empty or `2147483647`.
*/
readIntOrUndefined() {
const token = this.readStr();
if (token === "") {
return undefined;
}
const val = parseInt(token, 10);
return val === 2147483647 ? undefined : val;
}
/**
* Drain all tokens on queue until the start marker of a new message or until queue is empty.
*/
drainQueue() {
// drain data up to message end marker or until queue is empty
while (this.dataQueue.length && this.dataQueue[0] !== undefined) {
this.dataQueue.shift();
}
if (this.dataQueue.length) {
// drain the end marker
this.dataQueue.shift();
}
}
/**
* Add tokens to the emit queue.
*/
emit(eventName, ...args) {
this.emitQueue.push({ name: eventName, args: args });
}
/**
* Decode a TICK_PRICE message from data queue and emit a tickPrice and tickSize event.
*/
decodeMsg_TICK_PRICE() {
// read from input queue
const version = this.readInt();
const tickerId = this.readInt();
const tickType = this.readInt();
const price = this.readDouble();
let size = undefined;
if (version >= 2) {
size = this.readDecimal();
}
let canAutoExecute = undefined;
if (version >= 3) {
canAutoExecute = this.readBool();
}
// emit events
this.emit(event_name_1.EventName.tickPrice, tickerId, tickType, price, canAutoExecute);
let sizeTickType = undefined;
if (version >= 2) {
switch (tickType) {
case tickType_1.TickType.BID:
sizeTickType = tickType_1.TickType.BID_SIZE;
break;
case tickType_1.TickType.ASK:
sizeTickType = tickType_1.TickType.ASK_SIZE;
break;
case tickType_1.TickType.LAST:
sizeTickType = tickType_1.TickType.LAST_SIZE;
break;
case tickType_1.TickType.DELAYED_BID:
sizeTickType = tickType_1.TickType.DELAYED_BID_SIZE;
break;
case tickType_1.TickType.DELAYED_ASK:
sizeTickType = tickType_1.TickType.DELAYED_ASK_SIZE;
break;
case tickType_1.TickType.DELAYED_LAST:
sizeTickType = tickType_1.TickType.DELAYED_LAST_SIZE;
break;
}
}
if (sizeTickType) {
this.emit(event_name_1.EventName.tickSize, tickerId, sizeTickType, size);
}
}
/**
* Decode a TICK_SIZE message from data queue and emit an tickSize event.
*/
decodeMsg_TICK_SIZE() {
this.readInt(); // version
const tickerId = this.readInt();
const tickType = this.readInt();
const size = this.readDecimal();
this.emit(event_name_1.EventName.tickSize, tickerId, tickType, size);
}
/**
* Decode a ORDER_STATUS message from data queue and emit an orderStatus event.
*/
decodeMsg_ORDER_STATUS() {
const version = this.serverVersion >= min_server_version_1.default.MARKET_CAP_PRICE
? Number.MAX_SAFE_INTEGER
: this.readInt();
const id = this.readInt();
const status = this.readStr();
const filled = this.readDecimal();
const remaining = this.readDecimal();
const avgFillPrice = this.readDouble();
let permId = undefined;
if (version >= 2) {
permId = this.readInt();
}
let parentId = undefined;
if (version >= 3) {
parentId = this.readInt();
}
let lastFillPrice = undefined;
if (version >= 4) {
lastFillPrice = this.readDouble();
}
let clientId = undefined;
if (version >= 5) {
clientId = this.readInt();
}
let whyHeld = undefined;
if (version >= 6) {
whyHeld = this.readStr();
}
let mktCapPrice = undefined;
if (this.serverVersion >= min_server_version_1.default.MARKET_CAP_PRICE) {
mktCapPrice = this.readDouble();
}
this.emit(event_name_1.EventName.orderStatus, id, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice);
}
/**
* Decode a ERR_MSG message from data queue and emit and error event.
*/
decodeMsg_ERR_MSG() {
const version = this.readInt();
if (version < 2) {
const errorMsg = this.readStr();
this.callback.emitError(errorMsg, errorCode_1.ErrorCode.UNKNOWN_ID);
}
else {
const id = this.readInt();
const code = this.readInt();
let msg = this.readStr();
if (this.serverVersion >= min_server_version_1.default.ENCODE_MSG_ASCII7) {
msg = this.decodeUnicodeEscapedString(msg);
}
let advancedOrderReject;
if (this.serverVersion >= min_server_version_1.default.ADVANCED_ORDER_REJECT) {
const advancedOrderRejectJson = this.readStr();
if (advancedOrderRejectJson?.length > 0) {
advancedOrderReject = JSON.parse(this.decodeUnicodeEscapedString(advancedOrderRejectJson));
}
}
if (id === errorCode_1.ErrorCode.NO_VALID_ID) {
this.callback.emitInfo(msg, code);
}
else {
this.callback.emitError(msg, code, id, advancedOrderReject);
}
}
}
/**
* Decode a OPEN_ORDER message from data queue and emit a openOrder event.
*/
decodeMsg_OPEN_ORDER() {
// read version
const version = this.serverVersion < min_server_version_1.default.ORDER_CONTAINER
? this.readInt()
: this.serverVersion;
const contract = {};
const order = {};
const orderState = {};
const orderDecoder = new OrderDecoder(this, contract, order, orderState, version, this.serverVersion);
// read order id
orderDecoder.readOrderId();
// read contract fields
orderDecoder.readContractFields();
// read order fields
orderDecoder.readAction();
orderDecoder.readTotalQuantity();
orderDecoder.readOrderType();
orderDecoder.readLmtPrice();
orderDecoder.readAuxPrice();
orderDecoder.readTIF();
orderDecoder.readOcaGroup();
orderDecoder.readAccount();
orderDecoder.readOpenClose();
orderDecoder.readOrigin();
orderDecoder.readOrderRef();
orderDecoder.readClientId();
orderDecoder.readPermId();
orderDecoder.readOutsideRth();
orderDecoder.readHidden();
orderDecoder.readDiscretionaryAmount();
orderDecoder.readGoodAfterTime();
orderDecoder.skipSharesAllocation();
orderDecoder.readFAParams();
orderDecoder.readModelCode();
orderDecoder.readGoodTillDate();
orderDecoder.readRule80A();
orderDecoder.readPercentOffset();
orderDecoder.readSettlingFirm();
orderDecoder.readShortSaleParams();
orderDecoder.readAuctionStrategy();
orderDecoder.readBoxOrderParams();
orderDecoder.readPegToStkOrVolOrderParams();
orderDecoder.readDisplaySize();
orderDecoder.readOldStyleOutsideRth();
orderDecoder.readBlockOrder();
orderDecoder.readSweepToFill();
orderDecoder.readAllOrNone();
orderDecoder.readMinQty();
orderDecoder.readOcaType();
orderDecoder.readETradeOnly();
orderDecoder.readFirmQuoteOnly();
orderDecoder.readNbboPriceCap();
orderDecoder.readParentId();
orderDecoder.readTriggerMethod();
orderDecoder.readVolOrderParams(true);
orderDecoder.readTrailParams();
orderDecoder.readBasisPoints();
orderDecoder.readComboLegs();
orderDecoder.readSmartComboRoutingParams();
orderDecoder.readScaleOrderParams();
orderDecoder.readHedgeParams();
orderDecoder.readOptOutSmartRouting();
orderDecoder.readClearingParams();
orderDecoder.readNotHeld();
orderDecoder.readDeltaNeutral();
orderDecoder.readAlgoParams();
orderDecoder.readSolicited();
orderDecoder.readWhatIfInfoAndCommission();
orderDecoder.readVolRandomizeFlags();
orderDecoder.readPegToBenchParams();
orderDecoder.readConditions();
orderDecoder.readAdjustedOrderParams();
orderDecoder.readSoftDollarTier();
orderDecoder.readCashQty();
orderDecoder.readDontUseAutoPriceForHedge();
orderDecoder.readIsOmsContainer();
orderDecoder.readDiscretionaryUpToLimitPrice();
orderDecoder.readUsePriceMgmtAlgo();
orderDecoder.readDuration();
orderDecoder.readPostToAts();
orderDecoder.readAutoCancelParent(min_server_version_1.default.AUTO_CANCEL_PARENT);
orderDecoder.readPegBestPegMidOrderAttributes();
orderDecoder.readCustomerAccount();
orderDecoder.readProfessionalCustomer();
orderDecoder.readBondAccruedInterest();
orderDecoder.readIncludeOvernight();
orderDecoder.readCMETaggingFields();
this.emit(event_name_1.EventName.openOrder, order.orderId, contract, order, orderState);
}
/**
* Decode a OPEN_ORDER message from data queue and emit a updateAccountValue event.
*/
decodeMsg_ACCT_VALUE() {
this.readInt(); // version
const key = this.readStr();
const value = this.readStr();
const currency = this.readStr();
const accountName = this.readStr();
this.emit(event_name_1.EventName.updateAccountValue, key, value, currency, accountName);
}
/**
* Decode a PORTFOLIO_VALUE message from data queue and emit a updatePortfolio (PortfolioValue) event.
*/
decodeMsg_PORTFOLIO_VALUE() {
const version = this.readInt();
const contract = {};
if (version >= 6) {
contract.conId = this.readInt();
}
contract.symbol = this.readStr();
contract.secType = this.readStr();
contract.lastTradeDateOrContractMonth = this.readStr();
contract.strike = this.readDouble();
contract.right = validateOptionType(this.readStr());
if (version >= 7) {
contract.multiplier = this.readDouble();
contract.primaryExch = this.readStr();
}
contract.currency = this.readStr();
if (version >= 2) {
contract.localSymbol = this.readStr();
}
if (version >= 8) {
contract.tradingClass = this.readStr();
}
const position = this.readDecimal();
const marketPrice = this.readDouble();
const marketValue = this.readDouble();
let averageCost = undefined;
let unrealizedPNL = undefined;
let realizedPNL = undefined;
if (version >= 3) {
averageCost = this.readDouble();
unrealizedPNL = this.readDouble();
realizedPNL = this.readDouble();
}
let accountName = undefined;
if (version >= 4) {
accountName = this.readStr();
}
if (version === 6 && this.serverVersion === 39) {
contract.primaryExch = this.readStr();
}
this.emit(event_name_1.EventName.updatePortfolio, contract, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName);
}
/**
* Decode a ACCT_UPDATE_TIME message from data queue and emit a updateAccountTime event.
*/
decodeMsg_ACCT_UPDATE_TIME() {
this.readInt(); // version
const timeStamp = this.readStr();
this.emit(event_name_1.EventName.updateAccountTime, timeStamp);
}
/**
* Decode a NEXT_VALID_ID message from data queue and emit a nextValidId event.
*/
decodeMsg_NEXT_VALID_ID() {
this.readInt(); // version
const orderId = this.readInt();
this.emit(event_name_1.EventName.nextValidId, orderId);
}
/**
* Decode a CONTRACT_DATA message from data queue and emit a contractDetails event.
*/
decodeMsg_CONTRACT_DATA() {
let version = 8;
if (this.serverVersion < min_server_version_1.default.SIZE_RULES) {
version = this.readInt();
}
let reqId = -1;
if (version >= 3) {
reqId = this.readInt();
}
const contract = {
contract: {},
};
contract.contract.symbol = this.readStr();
contract.contract.secType = this.readStr();
this.readLastTradeDate(contract, false);
if (this.serverVersion >= min_server_version_1.default.LAST_TRADE_DATE) {
contract.contract.lastTradeDate = this.readStr();
}
contract.contract.strike = this.readDouble();
contract.contract.right = validateOptionType(this.readStr());
contract.contract.exchange = this.readStr();
contract.contract.currency = this.readStr();
contract.contract.localSymbol = this.readStr();
contract.marketName = this.readStr();
contract.contract.tradingClass = this.readStr();
contract.contract.conId = this.readInt();
contract.minTick = this.readDouble();
if (this.serverVersion >= min_server_version_1.default.MD_SIZE_MULTIPLIER &&
this.serverVersion < min_server_version_1.default.SIZE_RULES) {
this.readInt(); // mdSizeMultiplier - not used anymore
}
contract.contract.multiplier = this.readDouble();
contract.orderTypes = this.readStr();
contract.validExchanges = this.readStr();
if (version >= 2) {
contract.priceMagnifier = this.readInt();
}
if (version >= 4) {
contract.underConId = this.readInt();
}
if (version >= 5) {
contract.longName = this.readStr();
contract.contract.primaryExch = this.readStr();
if (this.serverVersion >= min_server_version_1.default.ENCODE_MSG_ASCII7) {
contract.longName = this.decodeUnicodeEscapedString(contract.longName);
}
}
if (version >= 6) {
contract.contractMonth = this.readStr();
contract.industry = this.readStr();
contract.category = this.readStr();
contract.subcategory = this.readStr();
contract.timeZoneId = this.readStr();
contract.tradingHours = this.readStr();
contract.liquidHours = this.readStr();
}
if (version >= 8) {
contract.evRule = this.readStr();
contract.evMultiplier = this.readDouble();
}
if (version >= 7) {
const secIdListCount = this.readInt();
if (secIdListCount > 0) {
contract.secIdList = [];
for (let i = 0; i < secIdListCount; ++i) {
const tagValue = {
tag: this.readStr(),
value: this.readStr(),
};
contract.secIdList.push(tagValue);
}
}
}
if (this.serverVersion >= min_server_version_1.default.AGG_GROUP) {
contract.aggGroup = this.readInt();
}
if (this.serverVersion >= min_server_version_1.default.UNDERLYING_INFO) {
contract.underSymbol = this.readStr();
contract.underSecType = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.MARKET_RULES) {
contract.marketRuleIds = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.REAL_EXPIRATION_DATE) {
contract.realExpirationDate = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.STOCK_TYPE) {
contract.stockType = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.FRACTIONAL_SIZE_SUPPORT &&
this.serverVersion < min_server_version_1.default.SIZE_RULES) {
this.readDecimal(); // sizeMinTick - not used anymore
}
if (this.serverVersion >= min_server_version_1.default.SIZE_RULES) {
contract.minSize = this.readDecimal();
contract.sizeIncrement = this.readDecimal();
contract.suggestedSizeIncrement = this.readDecimal();
}
if (this.serverVersion >= min_server_version_1.default.FUND_DATA_FIELDS &&
contract.contract.secType == sec_type_1.default.FUND) {
contract.fundName = this.readStr();
contract.fundFamily = this.readStr();
contract.fundType = this.readStr();
contract.fundFrontLoad = this.readStr();
contract.fundBackLoad = this.readStr();
contract.fundBackLoadTimeInterval = this.readStr();
contract.fundManagementFee = this.readStr();
contract.fundClosed = this.readBool();
contract.fundClosedForNewInvestors = this.readBool();
contract.fundClosedForNewMoney = this.readBool();
contract.fundNotifyAmount = this.readStr();
contract.fundMinimumInitialPurchase = this.readStr();
contract.fundSubsequentMinimumPurchase = this.readStr();
contract.fundBlueSkyStates = this.readStr();
contract.fundBlueSkyTerritories = this.readStr();
contract.fundDistributionPolicyIndicator =
this.readStr();
contract.fundAssetType = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.INELIGIBILITY_REASONS) {
const ineligibilityReasonCount = this.readInt();
const ineligibilityReasonList = new Array();
for (let i = 0; i < ineligibilityReasonCount; i++) {
const id = this.readStr();
const description = this.readStr();
ineligibilityReasonList.push({ id, description });
}
contract.ineligibilityReasonList = ineligibilityReasonList;
}
this.emit(event_name_1.EventName.contractDetails, reqId, contract);
}
/**
* Decode a EXECUTION_DATA message from data queue and emit a execDetails event.
*/
decodeMsg_EXECUTION_DATA() {
let version = this.serverVersion;
if (version < min_server_version_1.default.LAST_LIQUIDITY) {
version = this.readInt();
}
let reqId = -1;
if (version >= 7) {
reqId = this.readInt();
}
const orderId = this.readInt();
// read contract fields
const contract = {};
if (version >= 5) {
contract.conId = this.readInt();
}
contract.symbol = this.readStr();
contract.secType = this.readStr();
contract.lastTradeDateOrContractMonth = this.readStr();
contract.strike = this.readDouble();
contract.right = validateOptionType(this.readStr());
if (version >= 9) {
contract.multiplier = this.readDouble();
}
contract.exchange = this.readStr();
contract.currency = this.readStr();
contract.localSymbol = this.readStr();
if (version >= 10) {
contract.tradingClass = this.readStr();
}
const exec = {};
exec.orderId = orderId;
exec.execId = this.readStr();
exec.time = this.readStr();
exec.acctNumber = this.readStr();
exec.exchange = this.readStr();
exec.side = this.readStr();
exec.shares = this.readDecimal();
exec.price = this.readDouble();
if (version >= 2) {
exec.permId = this.readInt();
}
if (version >= 3) {
exec.clientId = this.readInt();
}
if (version >= 4) {
exec.liquidation = this.readInt();
}
if (version >= 6) {
exec.cumQty = this.readDecimal();
exec.avgPrice = this.readDouble();
}
if (version >= 8) {
exec.orderRef = this.readStr();
}
if (version >= 9) {
exec.evRule = this.readStr();
exec.evMultiplier = this.readDouble();
}
if (this.serverVersion >= min_server_version_1.default.MODELS_SUPPORT) {
exec.modelCode = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.LAST_LIQUIDITY) {
exec.lastLiquidity = this.readInt();
}
if (this.serverVersion >= min_server_version_1.default.PENDING_PRICE_REVISION) {
exec.pendingPriceRevision = this.readBool();
}
this.emit(event_name_1.EventName.execDetails, reqId, contract, exec);
}
/**
* Decode a MARKET_DEPTH message from data queue and emit a MarketDepth event.
*/
decodeMsg_MARKET_DEPTH() {
this.readInt(); // version
const id = this.readInt();
const position = this.readInt();
const operation = this.readInt();
const side = this.readInt();
const price = this.readDouble();
const size = this.readDecimal();
this.emit(event_name_1.EventName.updateMktDepth, id, position, operation, side, price, size);
}
/**
* Decode a MARKET_DEPTH_L2 message from data queue and emit a MarketDepthL2 event.
*/
decodeMsg_MARKET_DEPTH_L2() {
this.readInt(); // version
const id = this.readInt();
const position = this.readInt();
const marketMaker = this.readStr();
const operation = this.readInt();
const side = this.readInt();
const price = this.readDouble();
const size = this.readDecimal();
let isSmartDepth = undefined;
if (this.serverVersion >= min_server_version_1.default.SMART_DEPTH) {
isSmartDepth = this.readBool();
}
this.emit(event_name_1.EventName.updateMktDepthL2, id, position, marketMaker, operation, side, price, size, isSmartDepth);
}
/**
* Decode a NEWS_BULLETINS message from data queue and emit a updateNewsBulletin event.
*/
decodeMsg_NEWS_BULLETINS() {
this.readInt(); // version
const newsMsgId = this.readInt();
const newsMsgType = this.readInt();
const newsMessage = this.readStr();
const originatingExch = this.readStr();
this.emit(event_name_1.EventName.updateNewsBulletin, newsMsgId, newsMsgType, newsMessage, originatingExch);
}
/**
* Decode a MANAGED_ACCTS message from data queue and emit a managedAccounts event.
*/
decodeMsg_MANAGED_ACCTS() {
this.readInt(); // version
const accountsList = this.readStr();
this.emit(event_name_1.EventName.managedAccounts, accountsList);
}
/**
* Decode a RECEIVE_FA message from data queue and emit a receiveFA event.
*/
decodeMsg_RECEIVE_FA() {
this.readInt(); // version
const faDataType = this.readInt();
const xml = this.readStr();
this.emit(event_name_1.EventName.receiveFA, faDataType, xml);
}
/**
* Decode a HISTORICAL_DATA message from data queue and emit historicalData events.
*/
decodeMsg_HISTORICAL_DATA() {
let version = Number.MAX_SAFE_INTEGER;
if (this.serverVersion < min_server_version_1.default.SYNT_REALTIME_BARS) {
version = this.readInt();
}
const reqId = this.readInt();
let completedIndicator = "finished";
let startDateStr = "";
let endDateStr = "";
if (version >= 2) {
startDateStr = this.readStr();
endDateStr = this.readStr();
completedIndicator += "-" + startDateStr + "-" + endDateStr;
}
let itemCount = this.readInt();
while (itemCount--) {
const date = this.readStr();
const open = this.readDouble();
const high = this.readDouble();
const low = this.readDouble();
const close = this.readDouble();
const volume = this.readDecimal();
const WAP = this.readDecimal();
// TODO: hasGap is deprecated, we should readStr and ignore result
let hasGaps = undefined;
if (this.serverVersion < min_server_version_1.default.SYNT_REALTIME_BARS) {
hasGaps = this.readBool();
}
let barCount = undefined;
if (version >= 3) {
barCount = this.readInt();
}
this.emit(event_name_1.EventName.historicalData, reqId, date, open, high, low, close, volume, barCount, WAP, hasGaps);
}
// send end of dataset marker
this.emit(event_name_1.EventName.historicalData, reqId, completedIndicator, -1, -1, -1, -1, -1, -1, -1, false);
}
/**
* Decode a HISTORICAL_DATA_UPDATE message from data queue and emit historicalDataUpdate events.
*/
decodeMsg_HISTORICAL_DATA_UPDATE() {
const reqId = this.readInt();
const barCount = this.readInt();
const date = this.readStr();
const open = this.readDouble();
const close = this.readDouble();
const high = this.readDouble();
const low = this.readDouble();
const WAP = this.readDecimal();
const volume = this.readDecimal();
this.emit(event_name_1.EventName.historicalDataUpdate, reqId, date, open, high, low, close, volume, barCount, WAP);
}
/**
* Decode a REROUTE_MKT_DATA message from data queue and emit a rerouteMktDataReq event.
*/
decodeMsg_REROUTE_MKT_DATA() {
const reqId = this.readInt();
const conId = this.readInt();
const exchange = this.readStr();
this.emit(event_name_1.EventName.rerouteMktDataReq, reqId, conId, exchange);
}
/**
* Decode a REROUTE_MKT_DEPTH message from data queue and emit a rerouteMktDepthReq event.
*/
decodeMsg_REROUTE_MKT_DEPTH() {
const reqId = this.readInt();
const conId = this.readInt();
const exchange = this.readStr();
this.emit(event_name_1.EventName.rerouteMktDepthReq, reqId, conId, exchange);
}
/**
* Decode a MARKET_RULE message from data queue and emit a marketRule event.
*/
decodeMsg_MARKET_RULE() {
const marketRuleId = this.readInt();
const nPriceIncrements = this.readInt();
const priceIncrements = new Array(nPriceIncrements);
for (let i = 0; i < nPriceIncrements; i++) {
priceIncrements[i] = {
lowEdge: this.readDouble(),
increment: this.readDouble(),
};
}
this.emit(event_name_1.EventName.marketRule, marketRuleId, priceIncrements);
}
/**
* Decode a BOND_CONTRACT_DATA message from data queue and emit a BondContractData event.
*/
decodeMsg_BOND_CONTRACT_DATA() {
let version = 6;
if (this.serverVersion < min_server_version_1.default.SIZE_RULES) {
version = this.readInt();
}
let reqId = -1;
if (version >= 3) {
reqId = this.readInt();
}
const contract = {
contract: {},
};
contract.contract.symbol = this.readStr();
contract.contract.secType = this.readStr();
contract.cusip = this.readStr();
contract.coupon = this.readDouble();
this.readLastTradeDate(contract, true);
contract.issueDate = this.readStr();
contract.ratings = this.readStr();
contract.bondType = this.readStr();
contract.couponType = this.readStr();
contract.convertible = this.readBool();
contract.callable = this.readBool();
contract.putable = this.readBool();
contract.descAppend = this.readStr();
contract.contract.exchange = this.readStr();
contract.contract.currency = this.readStr();
contract.marketName = this.readStr();
contract.contract.tradingClass = this.readStr();
contract.contract.conId = this.readInt();
contract.minTick = this.readDouble();
if (this.serverVersion >= min_server_version_1.default.MD_SIZE_MULTIPLIER &&
this.serverVersion < min_server_version_1.default.SIZE_RULES) {
this.readInt(); // mdSizeMultiplier - not used anymore
}
contract.orderTypes = this.readStr();
contract.validExchanges = this.readStr();
if (version >= 2) {
contract.nextOptionDate = this.readStr();
contract.nextOptionType = this.readStr();
contract.nextOptionPartial = this.readBool();
contract.notes = this.readStr();
}
if (version >= 4) {
contract.longName = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.BOND_TRADING_HOURS) {
contract.timeZoneId = this.readStr();
contract.tradingHours = this.readStr();
contract.liquidHours = this.readStr();
}
if (version >= 6) {
contract.evRule = this.readStr();
contract.evMultiplier = this.readDouble();
}
if (version >= 5) {
let secIdListCount = this.readInt();
if (secIdListCount > 0) {
contract.secIdList = [];
while (secIdListCount--) {
const tagValue = {
tag: this.readStr(),
value: this.readStr(),
};
contract.secIdList.push(tagValue);
}
}
}
if (this.serverVersion >= min_server_version_1.default.AGG_GROUP) {
contract.aggGroup = this.readInt();
}
if (this.serverVersion >= min_server_version_1.default.MARKET_RULES) {
contract.marketRuleIds = this.readStr();
}
if (this.serverVersion >= min_server_version_1.default.SIZE_RULES) {
contract.minSize = this.readDecimal();
contract.sizeIncrement = this.readDecimal();
contract.suggestedSizeIncrement = this.readDecimal();
}
this.emit(event_name_1.EventName.bondContractDetails, reqId, contract);
}
/**
* Decode a SCANNER_PARAMETERS message from data queue and emit a scannerParameters event.
*/
decodeMsg_SCANNER_PARAMETERS() {
const _version = this.readInt();
const xml = this.readStr();
this.emit(event_name_1.EventName.scannerParameters, xml);
}
/**
* Decode a SCANNER_DATA message from data queue and emit a scannerData and scannerDataEnd event.
*/
decodeMsg_SCANNER_DATA() {
const version = this.readInt();
const reqId = this.readInt();
let numberOfElements = this.readInt();
while (numberOfElements--) {
const contract = {
contract: {},
};
const rank = this.readInt();
if (version >= 3) {
contract.contract.conId = this.readInt();
}
contract.contract.symbol = this.readStr();
contract.contract.secType = this.readStr();
this.readLastTradeDate(contract, false);
contract.contract.strike = this.readDouble();
contract.contract.right = validateOptionType(this.readStr());
contract.contract.exchange = this.readStr();
contract.contr