UNPKG

@stoqey/ib

Version:

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

1,201 lines 114 kB
"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