From ce0d9488e2092762c44377aa874d2d6224caa423 Mon Sep 17 00:00:00 2001 From: Ronan-Yann Lorin Date: Thu, 13 Jun 2024 18:25:48 +0200 Subject: [PATCH 1/3] readIntOrUndefined bug fix --- src/core/io/decoder.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/core/io/decoder.ts b/src/core/io/decoder.ts index 77b3be0e..0c841a27 100644 --- a/src/core/io/decoder.ts +++ b/src/core/io/decoder.ts @@ -460,7 +460,7 @@ export class Decoder { * Read a token from queue and return it as boolean value. */ readBool(): boolean { - return parseInt(this.readStr()) != 0; + return parseInt(this.readStr(), 10) != 0; } /** @@ -510,15 +510,14 @@ export class Decoder { * Read a token from queue and return it as integer value. * * Returns 0 if the token is empty. - * Returns undefined is the token is Number.MAX_VALUE. */ - readInt(): number | undefined { + readInt(): number { const token = this.readStr(); if (!token || token === "") { return 0; } const val = parseInt(token, 10); - return val === Number.MAX_VALUE ? undefined : val; + return val; } /** @@ -527,18 +526,12 @@ export class Decoder { * Returns Number.MAX_VALUE if the token is empty. * @deprecated readIntOrUndefined is probably what you are looking for */ - readIntMax(): number { - const token = this.readStr(); - if (!token || token === "") { - return Number.MAX_VALUE; - } - return parseInt(token, 10); - } + readIntMax = this.readIntOrUndefined; /** * Read a token from queue and return it as integer value. * - * Returns undefined if the token is empty or Number.MAX_VALUE. + * Returns undefined if the token is empty or `2147483647`. */ readIntOrUndefined(): number | undefined { const token = this.readStr(); @@ -546,7 +539,7 @@ export class Decoder { return undefined; } const val = parseInt(token, 10); - return val === Number.MAX_VALUE ? undefined : val; + return val === 2147483647 ? undefined : val; } /** From d7d2400156fe145b75aa9be86c1c6fb827b0b90e Mon Sep 17 00:00:00 2001 From: Ronan-Yann Lorin Date: Sun, 16 Jun 2024 20:41:28 +0200 Subject: [PATCH 2/3] API 10.29.01 upgrade --- package.json | 8 +- ref/client/Builder.java | 4 +- ref/client/Contract.java | 13 +- ref/client/ContractCondition.java | 32 ++- ref/client/ContractDetails.java | 116 +++++--- ref/client/EClient.java | 149 ++++++---- ref/client/EClientErrors.java | 35 +-- ref/client/EDecoder.java | 36 ++- ref/client/EJavaSignal.java | 2 +- ref/client/EOrderDecoder.java | 20 +- ref/client/EWrapperMsgGenerator.java | 51 +++- ref/client/Execution.java | 10 +- ref/client/ExecutionCondition.java | 26 +- ref/client/MarginCondition.java | 13 +- ref/client/OperatorCondition.java | 34 ++- ref/client/Order.java | 16 +- ref/client/OrderCondition.java | 14 +- ref/client/OrderType.java | 99 +++---- ref/client/PriceCondition.java | 21 +- ref/client/TickType.java | 2 + ref/client/TimeCondition.java | 12 +- ref/client/Types.java | 99 ++++++- ref/client/Util.java | 19 +- ref/controller/Account.java | 26 ++ ref/controller/AdvisorUtil.java | 148 ++-------- ref/controller/ApiController.java | 40 +-- ref/controller/Group.java | 64 +++-- ref/controller/MarketValueTag.java | 1 + ref/controller/Profile.java | 65 ----- src/api/account/account.ts | 7 + src/api/account/market-value.ts | 28 ++ src/api/api.ts | 7 +- src/api/contract/contract.ts | 3 + src/api/contract/contractDetails.ts | 20 ++ src/api/contract/fund.ts | 14 + .../{fad-data-type.ts => fa-data-type.ts} | 0 src/api/data/enum/min-server-version.ts | 6 + src/api/historical/what-to-show.ts | 1 + src/api/order/enum/orderType.ts | 2 + src/api/order/order.ts | 7 + src/common/errorCode.ts | 67 +++-- src/core/io/decoder.ts | 260 +++++------------- src/core/io/encoder.ts | 136 ++++++--- src/index.ts | 2 +- .../subscription-registry.test.ts | 9 +- src/tests/unit/api/order/placeOrder.test.ts | 64 +++++ yarn.lock | 193 +++++++------ 47 files changed, 1210 insertions(+), 791 deletions(-) create mode 100644 ref/controller/Account.java delete mode 100644 ref/controller/Profile.java create mode 100644 src/api/account/account.ts create mode 100644 src/api/account/market-value.ts create mode 100644 src/api/contract/fund.ts rename src/api/data/enum/{fad-data-type.ts => fa-data-type.ts} (100%) diff --git a/package.json b/package.json index 844c128f..a858ece9 100644 --- a/package.json +++ b/package.json @@ -77,16 +77,16 @@ "@types/jest": "^29.5.12", "@types/node": "^18.19.34", "@types/source-map-support": "^0.5.10", - "@typescript-eslint/eslint-plugin": "^7.1.1", - "@typescript-eslint/parser": "^7.1.1", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "ajv": "^8.16.0", "eslint": "^8.57.0", - "eslint-plugin-jest": "^27.9.0", + "eslint-plugin-jest": "^28.6.0", "eslint-plugin-rxjs": "^5.0.3", "jest": "^29.7.0", "jest-environment-node": "^29.7.0", "jest-junit": "^16.0.0", - "ts-jest": "^29.1.4", + "ts-jest": "^29.1.5", "typedoc": "^0.25.13", "typescript": "^5.4.5" }, diff --git a/ref/client/Builder.java b/ref/client/Builder.java index 27c0a6c1..519080e9 100644 --- a/ref/client/Builder.java +++ b/ref/client/Builder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -124,7 +124,7 @@ private static boolean isAsciiPrintable(String str) { } private static boolean isAsciiPrintable(char ch) { - return ch >= 32 && ch < 127; + return ch >= 32 && ch < 127 || ch == 9 || ch == 10 || ch == 13; } /** inner class: ByteBuffer - storage for bytes and direct access to buffer. */ diff --git a/ref/client/Contract.java b/ref/client/Contract.java index 9e60e097..3c16fdd7 100644 --- a/ref/client/Contract.java +++ b/ref/client/Contract.java @@ -15,6 +15,7 @@ public class Contract implements Cloneable { private String m_symbol; private String m_secType; private String m_lastTradeDateOrContractMonth; + private String m_lastTradeDate; private double m_strike; private String m_right; private String m_multiplier; // should be double @@ -44,7 +45,8 @@ public class Contract implements Cloneable { public String currency() { return m_currency; } public String exchange() { return m_exchange; } public String primaryExch() { return m_primaryExch; } - public String lastTradeDateOrContractMonth() { return m_lastTradeDateOrContractMonth; } + public String lastTradeDateOrContractMonth() { return m_lastTradeDateOrContractMonth; } + public String lastTradeDate() { return m_lastTradeDate; } public String localSymbol() { return m_localSymbol; } public String tradingClass() { return m_tradingClass; } public String multiplier() { return m_multiplier; } @@ -63,7 +65,8 @@ public class Contract implements Cloneable { public void conid(int v) { m_conid = v; } public void currency(String v) { m_currency = v; } public void exchange(String v) { m_exchange = v; } - public void lastTradeDateOrContractMonth(String v) { m_lastTradeDateOrContractMonth = v; } + public void lastTradeDateOrContractMonth(String v) { m_lastTradeDateOrContractMonth = v; } + public void lastTradeDate(String v) { m_lastTradeDate = v; } public void localSymbol(String v) { m_localSymbol = v; } public void tradingClass(String v) { m_tradingClass = v; } public void multiplier(String v) { m_multiplier = v; } @@ -107,7 +110,7 @@ public Contract() { } } - public Contract(int p_conId, String p_symbol, String p_secType, String p_lastTradeDateOrContractMonth, + public Contract(int p_conId, String p_symbol, String p_secType, String p_lastTradeDateOrContractMonth, String p_lastTradeDate, double p_strike, String p_right, String p_multiplier, String p_exchange, String p_currency, String p_localSymbol, String p_tradingClass, List p_comboLegs, String p_primaryExch, boolean p_includeExpired, @@ -116,6 +119,7 @@ public Contract(int p_conId, String p_symbol, String p_secType, String p_lastTra m_symbol = p_symbol; m_secType = p_secType; m_lastTradeDateOrContractMonth = p_lastTradeDateOrContractMonth; + m_lastTradeDate = p_lastTradeDate; m_strike = p_strike; m_right = p_right; m_multiplier = p_multiplier; @@ -166,6 +170,7 @@ public boolean equals(Object p_other) { } if (Util.StringCompare(m_lastTradeDateOrContractMonth, l_theOther.m_lastTradeDateOrContractMonth) != 0 || + Util.StringCompare(m_lastTradeDate, l_theOther.m_lastTradeDate) != 0 || Util.StringCompare(m_right, l_theOther.m_right) != 0 || Util.StringCompare(m_multiplier, l_theOther.m_multiplier) != 0 || Util.StringCompare(m_localSymbol, l_theOther.m_localSymbol) != 0 || @@ -239,6 +244,7 @@ public String textDescription() { } app( sb, m_lastTradeDateOrContractMonth); + app( sb, m_lastTradeDate); if (m_strike != 0) { app( sb, m_strike); @@ -270,6 +276,7 @@ public boolean isCombo() { add( sb, "symbol", m_symbol); add( sb, "secType", m_secType); add( sb, "lastTradeDateOrContractMonth", m_lastTradeDateOrContractMonth); + add( sb, "lastTradeDate", m_lastTradeDate); add( sb, "strike", m_strike); add( sb, "right", m_right); add( sb, "multiplier", m_multiplier); diff --git a/ref/client/ContractCondition.java b/ref/client/ContractCondition.java index 39ae754b..73263df1 100644 --- a/ref/client/ContractCondition.java +++ b/ref/client/ContractCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -10,6 +10,11 @@ public abstract class ContractCondition extends OperatorCondition { + private static final String OF = SPACE + "of" + SPACE; + private static final String ON = SPACE + "on" + SPACE; + private static final String LEFT_PARENTHESIS = "("; + private static final String RIGHT_PARENTHESIS = ")"; + @Override public String toString() { return toString(null); @@ -23,10 +28,10 @@ public String toString(ContractLookuper lookuper) { List list = lookuper == null ? null : lookuper.lookupContract(c); String strContract = list != null && !list.isEmpty() ? - list.get(0).contract().symbol() + " " + list.get(0).contract().secType() + " on " + list.get(0).contract().exchange() : - conId() + ""; + list.get(0).contract().symbol() + SPACE + list.get(0).contract().secType() + ON + list.get(0).contract().exchange() : + conId() + LEFT_PARENTHESIS + exchange() + RIGHT_PARENTHESIS; - return type() + " of " + strContract + super.toString(); + return type() + OF + strContract + super.toString(); } private int m_conId; @@ -62,4 +67,23 @@ public String exchange() { public void exchange(String exchange) { this.m_exchange = exchange; } + + @Override public boolean tryToParse(String conditionStr) { + try + { + if (!conditionStr.substring(0, conditionStr.indexOf(OF)).equals(type().name())) { + return false; + } + conditionStr = conditionStr.substring(conditionStr.indexOf(OF) + OF.length()); + m_conId = Integer.parseInt(conditionStr.substring(0, conditionStr.indexOf(LEFT_PARENTHESIS))); + conditionStr = conditionStr.substring(conditionStr.indexOf(LEFT_PARENTHESIS) + 1); + m_exchange = conditionStr.substring(0, conditionStr.indexOf(RIGHT_PARENTHESIS)); + conditionStr = conditionStr.substring(conditionStr.indexOf(RIGHT_PARENTHESIS) + 1); + return super.tryToParse(conditionStr); + } + catch (Exception ex) + { + return false; + } + } } \ No newline at end of file diff --git a/ref/client/ContractDetails.java b/ref/client/ContractDetails.java index f269677a..e8d18e0c 100644 --- a/ref/client/ContractDetails.java +++ b/ref/client/ContractDetails.java @@ -1,10 +1,14 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; import java.util.List; +import com.ib.client.Types.FundAssetType; +import com.ib.client.Types.FundDistributionPolicyIndicator; +import com.ib.client.Types.SecType; + public class ContractDetails { private Contract m_contract; private String m_marketName; @@ -51,6 +55,25 @@ public class ContractDetails { private String m_nextOptionType; private boolean m_nextOptionPartial = false; private String m_notes; + + // FUND values + private String m_fundName; + private String m_fundFamily; + private String m_fundType; + private String m_fundFrontLoad; + private String m_fundBackLoad; + private String m_fundBackLoadTimeInterval; + private String m_fundManagementFee; + private boolean m_fundClosed = false; + private boolean m_fundClosedForNewInvestors = false; + private boolean m_fundClosedForNewMoney = false; + private String m_fundNotifyAmount; + private String m_fundMinimumInitialPurchase; + private String m_fundSubsequentMinimumPurchase; + private String m_fundBlueSkyStates; + private String m_fundBlueSkyTerritories; + private FundDistributionPolicyIndicator m_fundDistributionPolicyIndicator; + private FundAssetType m_fundAssetType; // Get public int conid() { return m_contract.conid(); } @@ -99,6 +122,24 @@ public class ContractDetails { public boolean nextOptionPartial() { return m_nextOptionPartial; } public String notes() { return m_notes; } + public String fundName() { return m_fundName; } + public String fundFamily() { return m_fundFamily; } + public String fundType() { return m_fundType; } + public String fundFrontLoad() { return m_fundFrontLoad; } + public String fundBackLoad() { return m_fundBackLoad; } + public String fundBackLoadTimeInterval() { return m_fundBackLoadTimeInterval; } + public String fundManagementFee() { return m_fundManagementFee; } + public boolean fundClosed() { return m_fundClosed; } + public boolean fundClosedForNewInvestors() { return m_fundClosedForNewInvestors; } + public boolean fundClosedForNewMoney() { return m_fundClosedForNewMoney; } + public String fundNotifyAmount() { return m_fundNotifyAmount; } + public String fundMinimumInitialPurchase() { return m_fundMinimumInitialPurchase; } + public String fundSubsequentMinimumPurchase() { return m_fundSubsequentMinimumPurchase; } + public String fundBlueSkyStates() { return m_fundBlueSkyStates; } + public String fundBlueSkyTerritories() { return m_fundBlueSkyTerritories; } + public FundDistributionPolicyIndicator fundDistributionPolicyIndicator() { return m_fundDistributionPolicyIndicator; } + public FundAssetType fundAssetType() { return m_fundAssetType; } + // Set public void contract(Contract contract) { m_contract = contract; } public void marketName(String marketName) { m_marketName = marketName; } @@ -145,6 +186,24 @@ public class ContractDetails { public void nextOptionPartial(boolean nextOptionPartial) { m_nextOptionPartial = nextOptionPartial; } public void notes(String notes) { m_notes = notes; } + public void fundName(String fundName) { m_fundName = fundName; } + public void fundFamily(String fundFamily) { m_fundFamily = fundFamily; } + public void fundType(String fundType) { m_fundType = fundType; } + public void fundFrontLoad(String fundFrontLoad) { m_fundFrontLoad = fundFrontLoad; } + public void fundBackLoad(String fundBackLoad) { m_fundBackLoad = fundBackLoad; } + public void fundBackLoadTimeInterval(String fundBackLoadTimeInterval) { m_fundBackLoadTimeInterval = fundBackLoadTimeInterval; } + public void fundManagementFee(String fundManagementFee) { m_fundManagementFee = fundManagementFee; } + public void fundClosed(boolean fundClosed) { m_fundClosed = fundClosed; } + public void fundClosedForNewInvestors(boolean fundClosedForNewInvestors) { m_fundClosedForNewInvestors = fundClosedForNewInvestors; } + public void fundClosedForNewMoney(boolean fundClosedForNewMoney) { m_fundClosedForNewMoney = fundClosedForNewMoney; } + public void fundNotifyAmount(String fundNotifyAmount) { m_fundNotifyAmount = fundNotifyAmount; } + public void fundMinimumInitialPurchase(String fundMinimumInitialPurchase) { m_fundMinimumInitialPurchase = fundMinimumInitialPurchase; } + public void fundSubsequentMinimumPurchase(String fundSubsequentMinimumPurchase) { m_fundSubsequentMinimumPurchase = fundSubsequentMinimumPurchase; } + public void fundBlueSkyStates(String fundBlueSkyStates) { m_fundBlueSkyStates = fundBlueSkyStates; } + public void fundBlueSkyTerritories(String fundBlueSkyTerritories) { m_fundBlueSkyTerritories = fundBlueSkyTerritories; } + public void fundDistributionPolicyIndicator(FundDistributionPolicyIndicator fundDistributionPolicyIndicator) { m_fundDistributionPolicyIndicator = fundDistributionPolicyIndicator; } + public void fundAssetType(FundAssetType fundAssetType) { m_fundAssetType = fundAssetType; } + public ContractDetails() { m_contract = new Contract(); m_minTick = 0; @@ -152,41 +211,6 @@ public ContractDetails() { m_evMultiplier = 0; } - public ContractDetails( Contract p_contract, String p_marketName, - double p_minTick, String p_orderTypes, String p_validExchanges, int p_underConId, String p_longName, - String p_contractMonth, String p_industry, String p_category, String p_subcategory, - String p_timeZoneId, String p_tradingHours, String p_liquidHours, - String p_evRule, double p_evMultiplier, int p_aggGroup, - String p_underSymbol, String p_underSecType, String p_marketRuleIds, String p_realExpirationDate, String p_lastTradeTime, - String p_stockType, Decimal p_minSize, Decimal p_sizeIncrement, Decimal p_suggestedSizeIncrement) { - m_contract = p_contract; - m_marketName = p_marketName; - m_minTick = p_minTick; - m_orderTypes = p_orderTypes; - m_validExchanges = p_validExchanges; - m_underConid = p_underConId; - m_longName = p_longName; - m_contractMonth = p_contractMonth; - m_industry = p_industry; - m_category = p_category; - m_subcategory = p_subcategory; - m_timeZoneId = p_timeZoneId; - m_tradingHours = p_tradingHours; - m_liquidHours = p_liquidHours; - m_evRule = p_evRule; - m_evMultiplier = p_evMultiplier; - m_aggGroup = p_aggGroup; - m_underSymbol = p_underSymbol; - m_underSecType = p_underSecType; - m_marketRuleIds = p_marketRuleIds; - m_realExpirationDate = p_realExpirationDate; - m_lastTradeTime = p_lastTradeTime; - m_stockType = p_stockType; - m_minSize = p_minSize; - m_sizeIncrement = p_sizeIncrement; - m_suggestedSizeIncrement = p_suggestedSizeIncrement; - } - @Override public String toString() { StringBuilder sb = new StringBuilder( m_contract.toString() ); @@ -233,6 +257,26 @@ public ContractDetails( Contract p_contract, String p_marketName, add( sb, "nextOptionPartial", m_nextOptionPartial); add( sb, "notes", m_notes); + if (m_contract.secType() == SecType.FUND) { + add( sb, "fundName", m_fundName); + add( sb, "fundFamily", m_fundFamily); + add( sb, "fundType", m_fundType); + add( sb, "fundFrontLoad", m_fundFrontLoad); + add( sb, "fundBackLoad", m_fundBackLoad); + add( sb, "fundBackLoadTimeInterval", m_fundBackLoadTimeInterval); + add( sb, "fundManagementFee", m_fundManagementFee); + add( sb, "fundClosed", m_fundClosed); + add( sb, "fundClosedForNewInvestors", m_fundClosedForNewInvestors); + add( sb, "fundClosedForNewMoney", m_fundClosedForNewMoney); + add( sb, "fundNotifyAmount", m_fundNotifyAmount); + add( sb, "fundMinimumInitialPurchase", m_fundMinimumInitialPurchase); + add( sb, "fundSubsequentMinimumPurchase", m_fundSubsequentMinimumPurchase); + add( sb, "fundBlueSkyStates", m_fundBlueSkyStates); + add( sb, "fundBlueSkyTerritories", m_fundBlueSkyTerritories); + add( sb, "fundDistributionPolicyIndicator", m_fundDistributionPolicyIndicator != null ? m_fundDistributionPolicyIndicator.name() : ""); + add( sb, "fundAssetType", m_fundAssetType != null ? m_fundAssetType.name() : ""); + } + return sb.toString(); } diff --git a/ref/client/EClient.java b/ref/client/EClient.java index c3f574fc..570f4ebb 100644 --- a/ref/client/EClient.java +++ b/ref/client/EClient.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -101,23 +101,6 @@ public abstract class EClient { protected static final int CLIENT_VERSION = 66; protected static final int MIN_SERVER_VER_SUPPORTED = 38; //all supported server versions are listed below - // FA msg data types - public static final int GROUPS = 1; - public static final int PROFILES = 2; - public static final int ALIASES = 3; - - public static String faMsgTypeName(int faDataType) { - switch (faDataType) { - case GROUPS: - return "GROUPS"; - case PROFILES: - return "PROFILES"; - case ALIASES: - return "ALIASES"; - } - return null; - } - // outgoing msg id's private static final int REQ_MKT_DATA = 1; private static final int CANCEL_MKT_DATA = 2; @@ -318,9 +301,17 @@ public static String faMsgTypeName(int faDataType) { protected static final int MIN_SERVER_VER_INSTRUMENT_TIMEZONE = 174; protected static final int MIN_SERVER_VER_HMDS_MARKET_DATA_IN_SHARES = 175; protected static final int MIN_SERVER_VER_BOND_ISSUERID = 176; + protected static final int MIN_SERVER_VER_FA_PROFILE_DESUPPORT = 177; + protected static final int MIN_SERVER_VER_PENDING_PRICE_REVISION = 178; + protected static final int MIN_SERVER_VER_FUND_DATA_FIELDS = 179; + protected static final int MIN_SERVER_VER_MANUAL_ORDER_TIME_EXERCISE_OPTIONS = 180; + protected static final int MIN_SERVER_VER_OPEN_ORDER_AD_STRATEGY = 181; + protected static final int MIN_SERVER_VER_LAST_TRADE_DATE = 182; + protected static final int MIN_SERVER_VER_CUSTOMER_ACCOUNT = 183; + protected static final int MIN_SERVER_VER_PROFESSIONAL_CUSTOMER = 184; public static final int MIN_VERSION = 100; // envelope encoding, applicable to useV100Plus mode only - public static final int MAX_VERSION = MIN_SERVER_VER_BOND_ISSUERID; // ditto + public static final int MAX_VERSION = MIN_SERVER_VER_PROFESSIONAL_CUSTOMER; // ditto protected EReaderSignal m_signal; protected EWrapper m_eWrapper; // msg handler @@ -975,7 +966,7 @@ public synchronized void cancelHeadTimestamp(int tickerId) { closeAndSend(b); } catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_CANHEADTIMESTAMP, e.toString()); + error(tickerId, EClientErrors.FAIL_SEND_CANCELHEADTIMESTAMP, e.toString()); close(); } } @@ -1328,7 +1319,8 @@ public synchronized void cancelMktDepth( int tickerId, boolean isSmartDepth) { public synchronized void exerciseOptions( int tickerId, Contract contract, int exerciseAction, int exerciseQuantity, - String account, int override) { + String account, int override, String manualOrderTime, + String customerAccount, boolean professionalCustomer) { // not connected? if( !isConnected()) { notConnected(); @@ -1352,6 +1344,26 @@ public synchronized void exerciseOptions( int tickerId, Contract contract, } } + if (m_serverVersion < MIN_SERVER_VER_MANUAL_ORDER_TIME_EXERCISE_OPTIONS && !IsEmpty(manualOrderTime)) { + error(tickerId, EClientErrors.UPDATE_TWS, + " It does not support manual order time parameter in exerciseOptions."); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_CUSTOMER_ACCOUNT) { + if (!IsEmpty(customerAccount)) { + error(tickerId, EClientErrors.UPDATE_TWS, " It does not support customer account parameter in exerciseOptions."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_PROFESSIONAL_CUSTOMER) { + if (professionalCustomer) { + error(tickerId, EClientErrors.UPDATE_TWS, " It does not support professional customer parameter in exerciseOptions."); + return; + } + } + Builder b = prepareBuffer(); b.send(EXERCISE_OPTIONS); @@ -1378,6 +1390,15 @@ public synchronized void exerciseOptions( int tickerId, Contract contract, b.send(exerciseQuantity); b.send(account); b.send(override); + if (m_serverVersion >= MIN_SERVER_VER_MANUAL_ORDER_TIME_EXERCISE_OPTIONS) { + b.send(manualOrderTime); + } + if (m_serverVersion >= MIN_SERVER_VER_CUSTOMER_ACCOUNT) { + b.send(customerAccount); + } + if (m_serverVersion >= MIN_SERVER_VER_PROFESSIONAL_CUSTOMER) { + b.send(professionalCustomer); + } closeAndSend(b); } @@ -1713,7 +1734,21 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { return; } } - + + if (m_serverVersion < MIN_SERVER_VER_CUSTOMER_ACCOUNT) { + if (!IsEmpty(order.customerAccount())) { + error(id, EClientErrors.UPDATE_TWS, " It does not support customer account parameter"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_PROFESSIONAL_CUSTOMER) { + if (order.professionalCustomer()) { + error(id, EClientErrors.UPDATE_TWS, " It does not support professional customer parameter"); + return; + } + } + int VERSION = (m_serverVersion < MIN_SERVER_VER_NOT_HELD) ? 27 : 45; // send place order msg @@ -1881,7 +1916,9 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.send( order.faGroup()); b.send( order.getFaMethod()); b.send( order.faPercentage()); - b.send( order.faProfile()); + if ( m_serverVersion < MIN_SERVER_VER_FA_PROFILE_DESUPPORT ) { + b.send( ""); // send deprecated faProfile field + } } if ( m_serverVersion >= MIN_SERVER_VER_MODELS_SUPPORT ) { @@ -1914,10 +1951,10 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.sendMax( order.stockRefPrice()); b.sendMax( order.delta()); // Volatility orders had specific watermark price attribs in server version 26 - double lower = (m_serverVersion == 26 && order.getOrderType().equals("VOL")) + double lower = (m_serverVersion == 26 && Util.IsVolOrder(order.orderType())) ? Double.MAX_VALUE : order.stockRangeLower(); - double upper = (m_serverVersion == 26 && order.getOrderType().equals("VOL")) + double upper = (m_serverVersion == 26 && Util.IsVolOrder(order.orderType())) ? Double.MAX_VALUE : order.stockRangeUpper(); b.sendMax( lower); @@ -1954,8 +1991,8 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.send( order.continuousUpdate()); if (m_serverVersion == 26) { // Volatility orders had specific watermark price attribs in server version 26 - double lower = order.getOrderType().equals("VOL") ? order.stockRangeLower() : Double.MAX_VALUE; - double upper = order.getOrderType().equals("VOL") ? order.stockRangeUpper() : Double.MAX_VALUE; + double lower = Util.IsVolOrder(order.orderType()) ? order.stockRangeLower() : Double.MAX_VALUE; + double upper = Util.IsVolOrder(order.orderType()) ? order.stockRangeUpper() : Double.MAX_VALUE; b.sendMax( lower); b.sendMax( upper); } @@ -2068,7 +2105,7 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { } if (m_serverVersion >= MIN_SERVER_VER_PEGGED_TO_BENCHMARK) { - if (order.orderType() == OrderType.PEG_BENCH) { + if (Util.IsPegBenchOrder(order.orderType())) { b.send(order.referenceContractId()); b.send(order.isPeggedChangeAmountDecrease()); b.send(order.peggedChangeAmount()); @@ -2163,13 +2200,13 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.sendMax(order.minTradeQty()); } boolean sendMidOffsets = false; - if (order.orderType().equals(OrderType.PEG_BEST)) { + if (Util.IsPegBestOrder(order.orderType())) { b.sendMax(order.minCompeteSize()); b.sendMax(order.competeAgainstBestOffset()); if (order.isCompeteAgainstBestOffsetUpToMid()) { sendMidOffsets = true; } - } else if (order.orderType().equals(OrderType.PEG_MID)) { + } else if (Util.IsPegMidOrder(order.orderType())) { sendMidOffsets = true; } if (sendMidOffsets) { @@ -2178,6 +2215,14 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { } } + if (m_serverVersion >= MIN_SERVER_VER_CUSTOMER_ACCOUNT) { + b.send(order.customerAccount()); + } + + if (m_serverVersion >= MIN_SERVER_VER_PROFESSIONAL_CUSTOMER) { + b.send(order.professionalCustomer()); + } + closeAndSend(b); } catch(EClientException e) { @@ -2494,6 +2539,10 @@ public synchronized void reqManagedAccts() { } } + public void requestFA( Types.FADataType faDataType ) { + requestFA(faDataType.id()); + } + public synchronized void requestFA( int faDataType ) { // not connected? if( !isConnected()) { @@ -2501,10 +2550,9 @@ public synchronized void requestFA( int faDataType ) { return; } - // This feature is only available for versions of TWS >= 13 - if( m_serverVersion < 13) { - error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), - EClientErrors.UPDATE_TWS.msg()); + if (m_serverVersion >= MIN_SERVER_VER_FA_PROFILE_DESUPPORT && faDataType == 2) { + error(EClientErrors.NO_VALID_ID, EClientErrors.FA_PROFILE_NOT_SUPPORTED.code(), + EClientErrors.FA_PROFILE_NOT_SUPPORTED.msg()); return; } @@ -2525,6 +2573,10 @@ public synchronized void requestFA( int faDataType ) { } } + public void replaceFA ( int reqId, Types.FADataType faDataType, String xml) { + replaceFA (reqId, faDataType.id(), xml); + } + public synchronized void replaceFA( int reqId, int faDataType, String xml ) { // not connected? if( !isConnected()) { @@ -2532,10 +2584,9 @@ public synchronized void replaceFA( int reqId, int faDataType, String xml ) { return; } - // This feature is only available for versions of TWS >= 13 - if( m_serverVersion < 13) { - error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), - EClientErrors.UPDATE_TWS.msg()); + if (m_serverVersion >= MIN_SERVER_VER_FA_PROFILE_DESUPPORT && faDataType == 2) { + error(reqId, EClientErrors.FA_PROFILE_NOT_SUPPORTED.code(), + EClientErrors.FA_PROFILE_NOT_SUPPORTED.msg()); return; } @@ -3750,7 +3801,7 @@ public synchronized void reqHistogramData(int tickerId, Contract contract, error(tickerId, e.error(), e.text()); } catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, e.toString()); + error(tickerId, EClientErrors.FAIL_SEND_REQHISTOGRAMDATA, e.toString()); close(); } } @@ -3778,7 +3829,7 @@ public synchronized void cancelHistogramData( int tickerId ) { closeAndSend(b); } catch( Exception e) { - error( tickerId, EClientErrors.FAIL_SEND_CANHISTDATA, e.toString()); + error( tickerId, EClientErrors.FAIL_SEND_CANCELHISTOGRAMDATA, e.toString()); close(); } } @@ -3863,7 +3914,7 @@ public synchronized void cancelPnL(int reqId) { closeAndSend(b); } catch(Exception e) { - error(reqId, EClientErrors.FAIL_SEND_CANPNL, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_CANCELPNL, e.toString()); close(); } } @@ -3895,7 +3946,7 @@ public synchronized void reqPnLSingle(int reqId, String account, String modelCod error(reqId, e.error(), e.text()); } catch(Exception e) { - error(reqId, EClientErrors.FAIL_SEND_REQPNL_SINGLE, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQPNLSINGLE, e.toString()); close(); } } @@ -3920,7 +3971,7 @@ public synchronized void cancelPnLSingle(int reqId) { closeAndSend(b); } catch(Exception e) { - error(reqId, EClientErrors.FAIL_SEND_CANPNL_SINGLE, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_CANCELPNLSINGLE, e.toString()); close(); } } @@ -3959,7 +4010,7 @@ public synchronized void reqHistoricalTicks(int reqId, Contract contract, String error(reqId, e.error(), e.text()); } catch(Exception e) { - error(reqId, EClientErrors.FAIL_SEND_HISTORICAL_TICK, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQHISTORICALTICKS, e.toString()); close(); } } @@ -4014,7 +4065,7 @@ public synchronized void reqTickByTickData(int reqId, Contract contract, String error(reqId, e.error(), e.text()); } catch(Exception e) { - error(reqId, EClientErrors.FAIL_SEND_REQTICKBYTICK, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQTICKBYTICKDATA, e.toString()); close(); } } @@ -4042,7 +4093,7 @@ public synchronized void cancelTickByTickData(int reqId) { } catch( Exception e) { error( EClientErrors.NO_VALID_ID, - EClientErrors.FAIL_SEND_CANTICKBYTICK, e.toString()); + EClientErrors.FAIL_SEND_CANCELTICKBYTICKDATA, e.toString()); close(); } } @@ -4070,7 +4121,7 @@ public synchronized void reqCompletedOrders(boolean apiOnly) { } catch( Exception e) { error( EClientErrors.NO_VALID_ID, - EClientErrors.FAIL_SEND_REQ_COMPLETED_ORDERS, e.toString()); + EClientErrors.FAIL_SEND_REQCOMPLETEDORDERS, e.toString()); close(); } } @@ -4182,7 +4233,7 @@ public synchronized void reqWshEventData(int reqId, WshEventData wshEventData) { } catch( Exception e) { error( EClientErrors.NO_VALID_ID, - EClientErrors.FAIL_SEND_REQ_WSH_META_DATA, e.toString()); + EClientErrors.FAIL_SEND_REQ_WSH_EVENT_DATA, e.toString()); close(); } } @@ -4237,7 +4288,7 @@ public synchronized void reqUserInfo(int reqId) { closeAndSend(b); } catch( Exception e) { - error(reqId, EClientErrors.FAIL_SEND_REQUSERINFO, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQ_USER_INFO, e.toString()); close(); } } diff --git a/ref/client/EClientErrors.java b/ref/client/EClientErrors.java index fee2816c..ab4e04ca 100644 --- a/ref/client/EClientErrors.java +++ b/ref/client/EClientErrors.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -75,22 +75,25 @@ public class EClientErrors { static final CodeMsgPair FAIL_SEND_REQNEWSARTICLE = new CodeMsgPair(564, "Request News Article Sending Error - "); static final CodeMsgPair FAIL_SEND_REQHISTORICALNEWS = new CodeMsgPair(565, "Request Historical News Sending Error - "); static final CodeMsgPair FAIL_SEND_REQHEADTIMESTAMP = new CodeMsgPair(566, "Request Head Time Stamp Sending Error - "); - static final CodeMsgPair FAIL_SEND_CANHEADTIMESTAMP = new CodeMsgPair(567, "Cancel Head Time Stamp Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQMARKETRULE = new CodeMsgPair(568, "Request Market Rule Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQPNL = new CodeMsgPair(566, "Request PnL Sending Error - "); - static final CodeMsgPair FAIL_SEND_CANPNL = new CodeMsgPair(567, "Cancel PnL Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQPNL_SINGLE = new CodeMsgPair(568, "Request PnL Single Sending Error - "); - static final CodeMsgPair FAIL_SEND_CANPNL_SINGLE = new CodeMsgPair(569, "Cancel PnL Single Sending Error - "); - static final CodeMsgPair FAIL_SEND_HISTORICAL_TICK = new CodeMsgPair(569, "Request Historical Ticks Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQTICKBYTICK = new CodeMsgPair(570, "Request Tick-By-Tick Sending Error - "); - static final CodeMsgPair FAIL_SEND_CANTICKBYTICK = new CodeMsgPair(571, "Cancel Tick-By-Tick Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQ_COMPLETED_ORDERS = new CodeMsgPair(572, "Request Completed Orders Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQ_WSH_META_DATA = new CodeMsgPair(573, "Request WSH Meta Data Sending Error - "); - static final CodeMsgPair FAIL_SEND_CAN_WSH_META_DATA = new CodeMsgPair(574, "Cancel WSH Meta Data Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQ_WSH_EVENT_DATA = new CodeMsgPair(575, "Request WSH Event Data Sending Error - "); - static final CodeMsgPair FAIL_SEND_CAN_WSH_EVENT_DATA = new CodeMsgPair(576, "Cancel WSH Event Data Sending Error - "); - static final CodeMsgPair FAIL_SEND_REQUSERINFO = new CodeMsgPair(577, "Request User Info Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQHISTOGRAMDATA = new CodeMsgPair(567, "Request Histogram Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_CANCELHISTOGRAMDATA = new CodeMsgPair(568, "Cancel Request Histogram Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_CANCELHEADTIMESTAMP = new CodeMsgPair(569, "Cancel Head Time Stamp Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQMARKETRULE = new CodeMsgPair(570, "Request Market Rule Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQPNL = new CodeMsgPair(571, "Request PnL Sending Error - "); + static final CodeMsgPair FAIL_SEND_CANCELPNL = new CodeMsgPair(572, "Cancel PnL Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQPNLSINGLE = new CodeMsgPair(573, "Request PnL Single Error - "); + static final CodeMsgPair FAIL_SEND_CANCELPNLSINGLE = new CodeMsgPair(574, "Cancel PnL Single Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQHISTORICALTICKS = new CodeMsgPair(575, "Request Historical Ticks Error - "); + static final CodeMsgPair FAIL_SEND_REQTICKBYTICKDATA = new CodeMsgPair(576, "Request Tick-By-Tick Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_CANCELTICKBYTICKDATA = new CodeMsgPair(577, "Cancel Tick-By-Tick Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQCOMPLETEDORDERS = new CodeMsgPair(578, "Request Completed Orders Sending Error - "); static final CodeMsgPair INVALID_SYMBOL = new CodeMsgPair(579, "Invalid symbol in string - "); + static final CodeMsgPair FAIL_SEND_REQ_WSH_META_DATA = new CodeMsgPair(580, "Request WSH Meta Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_CAN_WSH_META_DATA = new CodeMsgPair(581, "Cancel WSH Meta Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQ_WSH_EVENT_DATA = new CodeMsgPair(582, "Request WSH Event Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_CAN_WSH_EVENT_DATA = new CodeMsgPair(583, "Cancel WSH Event Data Sending Error - "); + static final CodeMsgPair FAIL_SEND_REQ_USER_INFO = new CodeMsgPair(584, "Request User Info Sending Error - "); + static final CodeMsgPair FA_PROFILE_NOT_SUPPORTED = new CodeMsgPair(585, "FA Profile is not supported anymore, use FA Group instead - "); public EClientErrors() { } diff --git a/ref/client/EDecoder.java b/ref/client/EDecoder.java index 718b2761..a0a6125d 100644 --- a/ref/client/EDecoder.java +++ b/ref/client/EDecoder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -17,6 +17,10 @@ import java.util.Map.Entry; import java.util.Set; +import com.ib.client.Types.FundAssetType; +import com.ib.client.Types.FundDistributionPolicyIndicator; +import com.ib.client.Types.SecType; + class EDecoder implements ObjectInput { // incoming msg id's private static final int END_CONN = -1; @@ -1171,6 +1175,10 @@ private void processExecutionDataMsg() throws IOException { if (m_serverVersion >= EClient.MIN_SERVER_VER_LAST_LIQUIDITY) { exec.lastLiquidity(readInt()); } + + if (m_serverVersion >= EClient.MIN_SERVER_VER_PENDING_PRICE_REVISION) { + exec.pendingPriceRevision(readBoolFromInt()); + } m_EWrapper.execDetails( reqId, contract, exec); @@ -1268,6 +1276,9 @@ private void processContractDataMsg() throws IOException { contract.contract().symbol(readStr()); contract.contract().secType(readStr()); readLastTradeDate(contract, false); + if (m_serverVersion >= EClient.MIN_SERVER_VER_LAST_TRADE_DATE) { + contract.contract().lastTradeDate(readStr()); + } contract.contract().strike(readDouble()); contract.contract().right(readStr()); contract.contract().exchange(readStr()); @@ -1342,6 +1353,25 @@ private void processContractDataMsg() throws IOException { contract.sizeIncrement(readDecimal()); contract.suggestedSizeIncrement(readDecimal()); } + if (m_serverVersion >= EClient.MIN_SERVER_VER_FUND_DATA_FIELDS && contract.contract().secType() == SecType.FUND) { + contract.fundName(readStr()); + contract.fundFamily(readStr()); + contract.fundType(readStr()); + contract.fundFrontLoad(readStr()); + contract.fundBackLoad(readStr()); + contract.fundBackLoadTimeInterval(readStr()); + contract.fundManagementFee(readStr()); + contract.fundClosed(readBoolFromInt()); + contract.fundClosedForNewInvestors(readBoolFromInt()); + contract.fundClosedForNewMoney(readBoolFromInt()); + contract.fundNotifyAmount(readStr()); + contract.fundMinimumInitialPurchase(readStr()); + contract.fundSubsequentMinimumPurchase(readStr()); + contract.fundBlueSkyStates(readStr()); + contract.fundBlueSkyTerritories(readStr()); + contract.fundDistributionPolicyIndicator(FundDistributionPolicyIndicator.get(readStr())); + contract.fundAssetType(FundAssetType.get(readStr())); + } m_EWrapper.contractDetails( reqId, contract); } @@ -1470,6 +1500,8 @@ private void processOpenOrderMsg() throws IOException { eOrderDecoder.readPostToAts(); eOrderDecoder.readAutoCancelParent(EClient.MIN_SERVER_VER_AUTO_CANCEL_PARENT); eOrderDecoder.readPegBestPegMidOrderAttributes(); + eOrderDecoder.readCustomerAccount(); + eOrderDecoder.readProfessionalCustomer(); m_EWrapper.openOrder(order.orderId(), contract, order, orderState); } @@ -2001,6 +2033,8 @@ private void processCompletedOrderMsg() throws IOException { eOrderDecoder.readCompletedTime(); eOrderDecoder.readCompletedStatus(); eOrderDecoder.readPegBestPegMidOrderAttributes(); + eOrderDecoder.readCustomerAccount(); + eOrderDecoder.readProfessionalCustomer(); m_EWrapper.completedOrder(contract, order, orderState); } diff --git a/ref/client/EJavaSignal.java b/ref/client/EJavaSignal.java index 28842b83..177101f7 100644 --- a/ref/client/EJavaSignal.java +++ b/ref/client/EJavaSignal.java @@ -6,7 +6,7 @@ public class EJavaSignal implements EReaderSignal { private final Object monitor = new Object(); - private boolean open = false; + private volatile boolean open = false; @Override public void issueSignal() { diff --git a/ref/client/EOrderDecoder.java b/ref/client/EOrderDecoder.java index 89e9217d..44148184 100644 --- a/ref/client/EOrderDecoder.java +++ b/ref/client/EOrderDecoder.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -159,7 +159,9 @@ public void readFAParams() throws IOException { m_order.faGroup(m_eDecoder.readStr()); m_order.faMethod(m_eDecoder.readStr()); m_order.faPercentage(m_eDecoder.readStr()); - m_order.faProfile(m_eDecoder.readStr()); + if ( m_serverVersion < EClient.MIN_SERVER_VER_FA_PROFILE_DESUPPORT ) { + m_eDecoder.readStr(); // skip deprecated faProfile field + } } } @@ -540,7 +542,7 @@ public void readVolRandomizeFlags() throws IOException { public void readPegToBenchParams() throws IOException { if (m_serverVersion >= EClient.MIN_SERVER_VER_PEGGED_TO_BENCHMARK) { - if (m_order.orderType() == OrderType.PEG_BENCH) { + if (Util.IsPegBenchOrder(m_order.orderType())) { m_order.referenceContractId(m_eDecoder.readInt()); m_order.isPeggedChangeAmountDecrease(m_eDecoder.readBoolFromInt()); m_order.peggedChangeAmount(m_eDecoder.readDouble()); @@ -690,4 +692,16 @@ public void readPegBestPegMidOrderAttributes() throws IOException { m_order.midOffsetAtHalf(m_eDecoder.readDoubleMax()); } } + + public void readCustomerAccount() throws IOException { + if (m_serverVersion >= EClient.MIN_SERVER_VER_CUSTOMER_ACCOUNT) { + m_order.customerAccount(m_eDecoder.readStr()); + } + } + + public void readProfessionalCustomer() throws IOException { + if (m_serverVersion >= EClient.MIN_SERVER_VER_PROFESSIONAL_CUSTOMER) { + m_order.professionalCustomer(m_eDecoder.readBoolFromInt()); + } + } } diff --git a/ref/client/EWrapperMsgGenerator.java b/ref/client/EWrapperMsgGenerator.java index 51aca5f7..e98d8c64 100644 --- a/ref/client/EWrapperMsgGenerator.java +++ b/ref/client/EWrapperMsgGenerator.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -9,6 +9,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import com.ib.client.Types.SecType; public class EWrapperMsgGenerator { public static final String SCANNER_PARAMETERS = "SCANNER PARAMETERS:"; @@ -138,14 +139,46 @@ private static String contractDetailsMsg(ContractDetails contractDetails) { + "minSize = " + contractDetails.minSize() + "\n" + "sizeIncrement = " + contractDetails.sizeIncrement() + "\n" + "suggestedSizeIncrement = " + contractDetails.suggestedSizeIncrement() + "\n" + + contractDetailsFundData(contractDetails) + contractDetailsSecIdList(contractDetails); } - + + private static String contractDetailsFundData(ContractDetails contractDetails) { + final StringBuilder sb = new StringBuilder(); + if (contractDetails.contract().secType() == SecType.FUND) { + sb.append("fundData={\n"); + sb.append(" fundName=").append(contractDetails.fundName()).append("\n"); + sb.append(" fundFamily=").append(contractDetails.fundFamily()).append("\n"); + sb.append(" fundType=").append(contractDetails.fundType()).append("\n"); + sb.append(" fundFrontLoad=").append(contractDetails.fundFrontLoad()).append("\n"); + sb.append(" fundBackLoad=").append(contractDetails.fundBackLoad()).append("\n"); + sb.append(" fundBackLoadTimeInterval=").append(contractDetails.fundBackLoadTimeInterval()).append("\n"); + sb.append(" fundManagementFee=").append(contractDetails.fundManagementFee()).append("\n"); + sb.append(" fundClosed=").append(contractDetails.fundClosed()).append("\n"); + sb.append(" fundClosedForNewInvestors=").append(contractDetails.fundClosedForNewInvestors()).append("\n"); + sb.append(" fundClosedForNewMoney=").append(contractDetails.fundClosedForNewMoney()).append("\n"); + sb.append(" fundNotifyAmount=").append(contractDetails.fundNotifyAmount()).append("\n"); + sb.append(" fundMinimumInitialPurchase=").append(contractDetails.fundMinimumInitialPurchase()).append("\n"); + sb.append(" fundSubsequentMinimumPurchase=").append(contractDetails.fundSubsequentMinimumPurchase()).append("\n"); + sb.append(" fundBlueSkyStates=").append(contractDetails.fundBlueSkyStates()).append("\n"); + sb.append(" fundBlueSkyTerritories=").append(contractDetails.fundBlueSkyTerritories()).append("\n"); + if (contractDetails.fundDistributionPolicyIndicator() != null) { + sb.append(" fundDistributionPolicyIndicator=").append(contractDetails.fundDistributionPolicyIndicator().name()).append("\n"); + } + if (contractDetails.fundAssetType() != null) { + sb.append(" fundAssetType=").append(contractDetails.fundAssetType().name()).append("\n"); + } + sb.append("}\n"); + } + return sb.toString(); + } + private static String contractMsg(Contract contract) { return "conid = " + contract.conid() + "\n" + "symbol = " + contract.symbol() + "\n" + "secType = " + contract.getSecType() + "\n" - + "lastTradeDate = " + contract.lastTradeDateOrContractMonth() + "\n" + + "lastTradeDateOrContractMonth = " + contract.lastTradeDateOrContractMonth() + "\n" + + "lastTradeDate = " + contract.lastTradeDate() + "\n" + "strike = " + Util.DoubleMaxString(contract.strike()) + "\n" + "right = " + contract.getRight() + "\n" + "multiplier = " + contract.multiplier() + "\n" @@ -240,6 +273,7 @@ public static String execDetails( int reqId, Contract contract, Execution execut + "evMultiplier = " + Util.DoubleMaxString(execution.evMultiplier()) + "\n" + "modelCode = " + execution.modelCode() + "\n" + "lastLiquidity = " + execution.lastLiquidity() + "\n" + + "pendingPriceRevision = " + execution.pendingPriceRevision() + "\n" + " ---- Execution Details end ----\n"; } @@ -266,7 +300,7 @@ public static String managedAccounts( String accountsList) { } public static String receiveFA(int faDataType, String xml) { - return FINANCIAL_ADVISOR + " " + EClient.faMsgTypeName(faDataType) + " " + xml; + return FINANCIAL_ADVISOR + " " + Types.FADataType.getById(faDataType) + " " + xml; } public static String historicalData(int reqId, String date, double open, double high, double low, @@ -312,7 +346,7 @@ public static String scannerData(int reqId, int rank, ContractDetails contractDe " rank=" + Util.IntMaxString(rank) + " symbol=" + contract.symbol() + " secType=" + contract.getSecType() + - " lastTradeDate=" + contract.lastTradeDateOrContractMonth() + + " lastTradeDateOrContractMonth=" + contract.lastTradeDateOrContractMonth() + " strike=" + Util.DoubleMaxString(contract.strike()) + " right=" + contract.getRight() + " exchange=" + contract.exchange() + @@ -725,7 +759,7 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co Util.appendPositiveIntValue(sb, "conid", contract.conid()); Util.appendNonEmptyString(sb, "symbol", contract.symbol()); Util.appendNonEmptyString(sb, "secType", contract.getSecType()); - Util.appendNonEmptyString(sb, "lastTradeDate", contract.lastTradeDateOrContractMonth()); + Util.appendNonEmptyString(sb, "lastTradeDateOrContractMonth", contract.lastTradeDateOrContractMonth()); Util.appendPositiveDoubleValue(sb, "strike", contract.strike()); Util.appendNonEmptyString(sb, "right", contract.getRight(), "?"); Util.appendNonEmptyString(sb, "multiplier", contract.multiplier()); @@ -754,7 +788,6 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co Util.appendNonEmptyString(sb, "faGroup", order.faGroup()); Util.appendNonEmptyString(sb, "faMethod", order.getFaMethod()); Util.appendNonEmptyString(sb, "faPercentage", order.faPercentage()); - Util.appendNonEmptyString(sb, "faProfile", order.faProfile()); Util.appendPositiveIntValue(sb, "shortSaleSlot", order.shortSaleSlot()); if (order.shortSaleSlot() > 0) { Util.appendNonEmptyString(sb, "designatedLocation", order.designatedLocation()); @@ -823,7 +856,7 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co Util.appendBooleanFlag(sb, "discretionaryUpToLimitPrice", order.discretionaryUpToLimitPrice()); Util.appendBooleanFlag(sb, "usePriceMgmtAlgo", order.usePriceMgmtAlgo()); - if ("PEG BENCH".equals(order.getOrderType())) { + if (Util.IsPegBenchOrder(order.orderType())) { Util.appendPositiveIntValue(sb, "referenceContractId", order.referenceContractId()); Util.appendBooleanFlag(sb, "isPeggedChangeAmountDecrease", order.isPeggedChangeAmountDecrease()); Util.appendValidDoubleValue(sb, "peggedChangeAmount", order.peggedChangeAmount()); @@ -926,6 +959,8 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co } Util.appendValidDoubleValue(sb, "midOffsetAtWhole", order.midOffsetAtWhole()); Util.appendValidDoubleValue(sb, "midOffsetAtHalf", order.midOffsetAtHalf()); + Util.appendNonEmptyString(sb, "customerAccount", order.customerAccount()); + Util.appendBooleanFlag(sb, "professionalCustomer", order.professionalCustomer()); Util.appendNonEmptyString(sb, "status", orderState.getStatus()); Util.appendNonEmptyString(sb, "completedTime", orderState.completedTime()); diff --git a/ref/client/Execution.java b/ref/client/Execution.java index cf8c502f..2931ef1d 100644 --- a/ref/client/Execution.java +++ b/ref/client/Execution.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -56,6 +56,7 @@ public class Execution { private double m_evMultiplier; private String m_modelCode; private Liquidities m_lastLiquidity; + private boolean m_pendingPriceRevision; // Get public int orderId() { return m_orderId; } @@ -77,6 +78,7 @@ public class Execution { public String modelCode() { return m_modelCode; } public Liquidities lastLiquidity() { return m_lastLiquidity; } public String lastLiquidityStr() { return m_lastLiquidity.toString(); } + public boolean pendingPriceRevision() { return m_pendingPriceRevision; } // Set public void orderId(int orderId) { m_orderId = orderId; } @@ -97,6 +99,7 @@ public class Execution { public void evMultiplier(double evMultiplier) { m_evMultiplier = evMultiplier; } public void modelCode(String modelCode) { m_modelCode = modelCode; } public void lastLiquidity(int v) { m_lastLiquidity = Liquidities.fromInt(v); } + public void pendingPriceRevision(boolean pendingPriceRevision) { m_pendingPriceRevision = pendingPriceRevision; } public Execution() { m_orderId = 0; @@ -109,13 +112,14 @@ public Execution() { m_avgPrice = 0; m_evMultiplier = 0; m_lastLiquidity = Liquidities.None; + m_pendingPriceRevision = false; } public Execution( int p_orderId, int p_clientId, String p_execId, String p_time, String p_acctNumber, String p_exchange, String p_side, Decimal p_shares, double p_price, int p_permId, int p_liquidation, Decimal p_cumQty, double p_avgPrice, String p_orderRef, String p_evRule, double p_evMultiplier, - String p_modelCode) { + String p_modelCode, Liquidities lastLiquidity, boolean pendingPriceRevision) { m_orderId = p_orderId; m_clientId = p_clientId; m_execId = p_execId; @@ -133,6 +137,8 @@ public Execution( int p_orderId, int p_clientId, String p_execId, String p_time, m_evRule = p_evRule; m_evMultiplier = p_evMultiplier; m_modelCode = p_modelCode; + m_lastLiquidity = lastLiquidity; + m_pendingPriceRevision = pendingPriceRevision; } @Override diff --git a/ref/client/ExecutionCondition.java b/ref/client/ExecutionCondition.java index eb054475..9a83fc47 100644 --- a/ref/client/ExecutionCondition.java +++ b/ref/client/ExecutionCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -10,6 +10,11 @@ public class ExecutionCondition extends OrderCondition { public static final OrderConditionType conditionType = OrderConditionType.Execution; + + private static final String HEADER = "trade occurs for" + SPACE; + private static final String SYMBOL_SUFFIX = SPACE + "symbol on" + SPACE; + private static final String EXCHANGE_SUFFIX = SPACE + "exchange for" + SPACE; + private static final String SECTYPE_SUFFIX = SPACE + "security type"; protected ExecutionCondition() { } @@ -24,7 +29,7 @@ public void readFrom(ObjectInput in) throws IOException{ @Override public String toString() { - return "trade occurs for " + m_symbol + " symbol on " + m_exchange + " exchange for " + m_secType + " security type"; + return HEADER + m_symbol + SYMBOL_SUFFIX + m_exchange + EXCHANGE_SUFFIX + m_secType + SECTYPE_SUFFIX + super.toString(); } @Override @@ -64,4 +69,21 @@ public void symbol(String m_symbol) { this.m_symbol = m_symbol; } + @Override public boolean tryToParse(String conditionStr) { + if (!conditionStr.startsWith(HEADER)) { + return false; + } + + try { + conditionStr = conditionStr.replace(HEADER, EMPTY); + m_symbol = conditionStr.substring(0, conditionStr.indexOf(SYMBOL_SUFFIX)); + m_exchange = conditionStr.substring(conditionStr.indexOf(SYMBOL_SUFFIX) + SYMBOL_SUFFIX.length(), conditionStr.indexOf(EXCHANGE_SUFFIX)); + m_secType = conditionStr.substring(conditionStr.indexOf(EXCHANGE_SUFFIX) + EXCHANGE_SUFFIX.length(), conditionStr.indexOf(SECTYPE_SUFFIX)); + conditionStr = conditionStr.substring(conditionStr.indexOf(SECTYPE_SUFFIX) + SECTYPE_SUFFIX.length()); + return super.tryToParse(conditionStr); + } + catch (Exception ex) { + return false; + } + } } \ No newline at end of file diff --git a/ref/client/MarginCondition.java b/ref/client/MarginCondition.java index 5ebc8751..ee34895a 100644 --- a/ref/client/MarginCondition.java +++ b/ref/client/MarginCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -6,12 +6,14 @@ public class MarginCondition extends OperatorCondition { public static final OrderConditionType conditionType = OrderConditionType.Margin; + + private static final String HEADER = "the margin cushion percent"; protected MarginCondition() { } @Override public String toString() { - return "the margin cushion percent" + super.toString(); + return HEADER + super.toString(); } private int m_percent; @@ -34,4 +36,11 @@ protected void valueFromString(String v) { m_percent = Integer.parseInt(v); } + @Override public boolean tryToParse(String conditionStr) { + if (!conditionStr.startsWith(HEADER)) { + return false; + } + conditionStr = conditionStr.replace(HEADER, EMPTY); + return super.tryToParse(conditionStr); + } } \ No newline at end of file diff --git a/ref/client/OperatorCondition.java b/ref/client/OperatorCondition.java index a29eccde..14ce3248 100644 --- a/ref/client/OperatorCondition.java +++ b/ref/client/OperatorCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -10,6 +10,10 @@ public abstract class OperatorCondition extends OrderCondition { + private static final String HEADER = SPACE + "is" + SPACE; + private static final String IS_MORE = ">="; + private static final String IS_LESS = "<="; + private boolean m_isMore; protected abstract String valueToString(); @@ -27,7 +31,7 @@ public void readFrom(ObjectInput in) throws IOException { @Override public String toString() { - return " is " + (isMore() ? ">= " : "<= ") + valueToString(); + return HEADER + (isMore() ? IS_MORE + SPACE : IS_LESS + SPACE) + valueToString() + super.toString(); } @Override @@ -44,4 +48,30 @@ public boolean isMore() { public void isMore(boolean m_isMore) { this.m_isMore = m_isMore; } + + @Override public boolean tryToParse(String conditionStr) + { + if (!conditionStr.startsWith(HEADER)) { + return false; + } + + try + { + conditionStr = conditionStr.replace(HEADER, EMPTY); + if (!conditionStr.startsWith(IS_MORE) && !conditionStr.startsWith(IS_LESS)) { + return false; + } + m_isMore = conditionStr.startsWith(IS_MORE); + if (super.tryToParse(conditionStr.substring(conditionStr.lastIndexOf(SPACE)))) { + conditionStr = conditionStr.substring(0, conditionStr.lastIndexOf(SPACE)); + } + valueFromString(conditionStr.substring(3)); + } + catch (Exception ex) + { + return false; + } + + return true; + } } \ No newline at end of file diff --git a/ref/client/Order.java b/ref/client/Order.java index d7733482..923dc2e2 100644 --- a/ref/client/Order.java +++ b/ref/client/Order.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -80,7 +80,6 @@ public class Order { private String m_faGroup; private String m_faMethod = ""; // None; private String m_faPercentage; - private String m_faProfile; // volatility orders private double m_volatility = Double.MAX_VALUE; // enter percentage not decimal, e.g. 2 not .02 @@ -225,6 +224,8 @@ public class Order { private double m_competeAgainstBestOffset; private double m_midOffsetAtWhole; private double m_midOffsetAtHalf; + private String m_customerAccount; + private boolean m_professionalCustomer; // getters public Action action() { return Action.get(m_action); } @@ -294,7 +295,6 @@ public class Order { public String algoId() { return m_algoId; } public String faGroup() { return m_faGroup; } public String faPercentage() { return m_faPercentage; } - public String faProfile() { return m_faProfile; } public String goodAfterTime() { return m_goodAfterTime; } public String goodTillDate() { return m_goodTillDate; } public String hedgeParam() { return m_hedgeParam; } @@ -375,6 +375,8 @@ public class Order { public boolean isCompeteAgainstBestOffsetUpToMid() { return m_competeAgainstBestOffset == COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID; } public double midOffsetAtWhole() { return m_midOffsetAtWhole; } public double midOffsetAtHalf() { return m_midOffsetAtHalf; } + public String customerAccount() { return m_customerAccount; } + public boolean professionalCustomer() { return m_professionalCustomer; } // setters public void referenceContractId(int m_referenceContractId) { this.m_referenceContractId = m_referenceContractId; } @@ -407,7 +409,6 @@ public class Order { public void faMethod(Method v) { m_faMethod = ( v == null ) ? null : v.getApiString(); } public void faMethod(String v) { m_faMethod = v; } public void faPercentage(String v) { m_faPercentage = v; } - public void faProfile(String v) { m_faProfile = v; } public void goodAfterTime(String v) { m_goodAfterTime = v; } public void goodTillDate(String v) { m_goodTillDate = v; } public void hedgeParam(String v) { m_hedgeParam = v; } @@ -526,6 +527,8 @@ public class Order { public void setCompeteAgainstBestOffsetUpToMid() { m_competeAgainstBestOffset = COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID; } public void midOffsetAtWhole(double v) { m_midOffsetAtWhole = v; } public void midOffsetAtHalf(double v) { m_midOffsetAtHalf = v; } + public void customerAccount(String v) { m_customerAccount = v; } + public void professionalCustomer(boolean v) { m_professionalCustomer = v; } public Order() { @@ -582,6 +585,8 @@ public Order() { m_competeAgainstBestOffset = Double.MAX_VALUE; m_midOffsetAtWhole = Double.MAX_VALUE; m_midOffsetAtHalf = Double.MAX_VALUE; + m_customerAccount = EMPTY_STR; + m_professionalCustomer = false; } public List algoParams() { @@ -690,6 +695,7 @@ public boolean equals(Object p_other) { || m_competeAgainstBestOffset != l_theOther.m_competeAgainstBestOffset || m_midOffsetAtWhole != l_theOther.m_midOffsetAtWhole || m_midOffsetAtHalf != l_theOther.m_midOffsetAtHalf + || m_professionalCustomer != l_theOther.m_professionalCustomer ) { return false; } @@ -705,7 +711,6 @@ public boolean equals(Object p_other) { || Util.StringCompare(m_goodTillDate, l_theOther.m_goodTillDate) != 0 || Util.StringCompare(m_rule80A, l_theOther.m_rule80A) != 0 || Util.StringCompare(m_faGroup, l_theOther.m_faGroup) != 0 - || Util.StringCompare(m_faProfile, l_theOther.m_faProfile) != 0 || Util.StringCompare(m_faMethod, l_theOther.m_faMethod) != 0 || Util.StringCompare(m_faPercentage, l_theOther.m_faPercentage) != 0 || Util.StringCompare(m_openClose, l_theOther.m_openClose) != 0 @@ -736,6 +741,7 @@ public boolean equals(Object p_other) { || Util.StringCompare(m_shareholder, l_theOther.m_shareholder) != 0 || Util.StringCompare(m_advancedErrorOverride, l_theOther.m_advancedErrorOverride) != 0 || Util.StringCompare(m_manualOrderTime, l_theOther.m_manualOrderTime) != 0 + || Util.StringCompare(m_customerAccount, l_theOther.m_customerAccount) != 0 ) { return false; } diff --git a/ref/client/OrderCondition.java b/ref/client/OrderCondition.java index 30ea3501..71bce214 100644 --- a/ref/client/OrderCondition.java +++ b/ref/client/OrderCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -10,6 +10,11 @@ public abstract class OrderCondition { + protected static final String SPACE = " "; + protected static final String EMPTY = ""; + private static final String AND = SPACE + "and"; + private static final String OR = SPACE + "or"; + private OrderConditionType m_type; private boolean m_isConjunctionConnection; @@ -24,7 +29,7 @@ public void writeTo(ObjectOutput out) throws IOException { @Override public String toString() { - return conjunctionConnection() ? "" : ""; + return conjunctionConnection() ? AND : OR; } public boolean conjunctionConnection() { @@ -72,4 +77,9 @@ public static OrderCondition create(OrderConditionType type) { orderCondition.m_type = type; return orderCondition; } + + public boolean tryToParse(String conditionStr) { + m_isConjunctionConnection = conditionStr.equals(AND); + return m_isConjunctionConnection || conditionStr.equals(OR); + } } \ No newline at end of file diff --git a/ref/client/OrderType.java b/ref/client/OrderType.java index f44cb1f7..fc3526e6 100644 --- a/ref/client/OrderType.java +++ b/ref/client/OrderType.java @@ -1,62 +1,65 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; +import java.util.Arrays; +import java.util.List; public enum OrderType implements IApiEnum { - None( ""), - MKT( "MKT"), - LMT( "LMT"), - STP( "STP"), - STP_LMT( "STP LMT"), - REL( "REL"), - TRAIL( "TRAIL"), - BOX_TOP( "BOX TOP"), - FIX_PEGGED( "FIX PEGGED"), - LIT( "LIT"), - LMT_PLUS_MKT( "LMT + MKT"), - LOC( "LOC"), - MIT( "MIT"), - MKT_PRT( "MKT PRT"), - MOC( "MOC"), - MTL( "MTL"), - PASSV_REL( "PASSV REL"), - PEG_BENCH( "PEG BENCH"), - PEG_BEST( "PEG BEST"), - PEG_MID( "PEG MID"), - PEG_MKT( "PEG MKT"), - PEG_PRIM( "PEG PRIM"), - PEG_STK( "PEG STK"), - REL_PLUS_LMT( "REL + LMT"), - REL_PLUS_MKT( "REL + MKT"), - SNAP_MID( "SNAP MID"), - SNAP_MKT( "SNAP MKT"), - SNAP_PRIM( "SNAP PRIM"), - STP_PRT( "STP PRT"), - TRAIL_LIMIT( "TRAIL LIMIT"), - TRAIL_LIT( "TRAIL LIT"), - TRAIL_LMT_PLUS_MKT( "TRAIL LMT + MKT"), - TRAIL_MIT( "TRAIL MIT"), - TRAIL_REL_PLUS_MKT( "TRAIL REL + MKT"), - VOL( "VOL"), - VWAP( "VWAP"), - QUOTE("QUOTE"), - PEG_PRIM_VOL("PPV"), - PEG_MID_VOL("PDV"), - PEG_MKT_VOL("PMV"), - PEG_SRF_VOL("PSV"); + None( Arrays.asList("") ), + MKT( Arrays.asList("MKT", "MARKET") ), + LMT( Arrays.asList("LMT", "LIMIT") ), + STP( Arrays.asList("STP", "STOP") ), + STP_LMT( Arrays.asList("STP LMT", "STOP LIMIT", "STOPLIMIT", "STOPLMT", "STPLMT") ), + REL( Arrays.asList("REL", "RELATIVE") ), + TRAIL( Arrays.asList("TRAIL", "TRAILING STOP") ), + BOX_TOP( Arrays.asList("BOX TOP", "BOXTOP","BOX_TOP") ), + FIX_PEGGED( Arrays.asList("FIX PEGGED", "FIXPEGGED") ), + LIT( Arrays.asList("LIT") ), + LMT_PLUS_MKT( Arrays.asList("LMT + MKT", "LMT+MKT") ), + LOC( Arrays.asList("LOC", "LMT CLS", "LMTCLS") ), + MIDPRICE( Arrays.asList("MIDPRICE") ), + MIT( Arrays.asList("MIT") ), + MKT_PRT( Arrays.asList("MKT PRT", "MKTPRT") ), + MOC( Arrays.asList("MOC", "MKT CLS","MKTCLS") ), + MTL( Arrays.asList("MTL", "MKT TO LMT", "MKTTOLMT") ), + PASSV_REL( Arrays.asList("PASSV REL") ), + PEG_BENCH( Arrays.asList("PEG BENCH", "PEGBENCH") ), + PEG_BEST( Arrays.asList("PEG BEST", "PEGBEST") ), + PEG_MID( Arrays.asList("PEG MID", "PEGMID") ), + PEG_MKT( Arrays.asList("PEG MKT","PEGMKT") ), + PEG_PRIM( Arrays.asList("PEG PRIM", "PEGPRIM") ), // ? + PEG_STK( Arrays.asList("PEG STK", "PEGSTK") ), + REL_PLUS_LMT( Arrays.asList("REL + LMT", "REL+LMT") ), + REL_PLUS_MKT( Arrays.asList("REL + MKT", "REL+MKT") ), + SNAP_MID( Arrays.asList("SNAP MID","SNAPMID") ), + SNAP_MKT( Arrays.asList("SNAP MKT", "SNAPMKT") ), + SNAP_PRIM( Arrays.asList("SNAP PRIM", "SNAPPRIM") ), + STP_PRT( Arrays.asList("STP PRT", "STOP PROTECT") ), + TRAIL_LIMIT( Arrays.asList("TRAIL LIMIT", "TRAILLMT", "TRAILLIMIT") ), + TRAIL_LIT( Arrays.asList("TRAIL LIT", "TRAILLIT") ), + TRAIL_LMT_PLUS_MKT( Arrays.asList("TRAIL LMT + MKT") ), + TRAIL_MIT( Arrays.asList("TRAIL MIT", "TRAILMIT") ), + TRAIL_REL_PLUS_MKT( Arrays.asList("TRAIL REL + MKT") ), + VOL( Arrays.asList("VOL", "VOLATILITY","VOLAT") ), + VWAP( Arrays.asList("VWAP") ), + QUOTE( Arrays.asList("QUOTE") ), + PEG_PRIM_VOL( Arrays.asList("PPV", "PEG PRM VOL","PEGPRIMVOL") ), + PEG_MID_VOL( Arrays.asList("PDV", "PEG MID VOL", "PEGMIDVOL") ), + PEG_MKT_VOL( Arrays.asList("PMV", "PEG MKT VOL","PEGMKTVOL") ), + PEG_SRF_VOL( Arrays.asList("PSV", "PEG SURF VOL","PEGSURFVOL") ); - private String m_apiString; + private List m_apiStrings; - OrderType( String apiString) { - m_apiString = apiString; + OrderType(List apiStrings) { + m_apiStrings = apiStrings; } public static OrderType get(String apiString) { if (apiString != null && apiString.length() > 0 && !apiString.equals( "None") ) { for (OrderType type : values() ) { - if (type.m_apiString.equals( apiString) ) { + if (type.m_apiStrings.contains(apiString)) { return type; } } @@ -65,11 +68,11 @@ public static OrderType get(String apiString) { } @Override public String toString() { - return this == None ? super.toString() : m_apiString; + return this == None ? super.toString() : m_apiStrings.get(0); } @Override public String getApiString() { - return m_apiString; + return m_apiStrings.get(0); } } diff --git a/ref/client/PriceCondition.java b/ref/client/PriceCondition.java index ff4084e7..48ed955e 100644 --- a/ref/client/PriceCondition.java +++ b/ref/client/PriceCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -6,6 +6,8 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.Optional; public class PriceCondition extends ContractCondition { @@ -70,4 +72,21 @@ public void writeTo(ObjectOutput out) throws IOException { out.writeInt(m_triggerMethod); } + public static int triggerMethodFromString(String name) { + return Arrays.asList(mthdNames).indexOf(name); + } + + @Override public boolean tryToParse(final String conditionStr) { + Optional triggerMethod = Arrays.stream(mthdNames).filter(name -> !name.isEmpty()).filter(name -> conditionStr.startsWith(name)).sorted((name1, name2) -> name2.length() - name1.length()).findFirst(); + if (!triggerMethod.isPresent()) { + return false; + } + try { + m_triggerMethod = triggerMethodFromString(triggerMethod.get()); + return super.tryToParse(conditionStr.substring(conditionStr.indexOf(triggerMethod.get()) + triggerMethod.get().length() + 1)); + } + catch (Exception ex) { + return false; + } + } } \ No newline at end of file diff --git a/ref/client/TickType.java b/ref/client/TickType.java index 32b5f998..17a7f291 100644 --- a/ref/client/TickType.java +++ b/ref/client/TickType.java @@ -108,6 +108,8 @@ public enum TickType { SOCIAL_MARKET_ANALYTICS(100, "socialMarketAnalytics"), ESTIMATED_IPO_MIDPOINT(101, "estimatedIPOMidpoint"), FINAL_IPO_LAST(102, "finalIPOLast"), + DELAYED_YIELD_BID(103, "delayedYieldBid"), + DELAYED_YIELD_ASK(104, "delayedYieldAsk"), UNKNOWN( Integer.MAX_VALUE , "unknown" ); diff --git a/ref/client/TimeCondition.java b/ref/client/TimeCondition.java index b1475385..11e900da 100644 --- a/ref/client/TimeCondition.java +++ b/ref/client/TimeCondition.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -7,11 +7,13 @@ public class TimeCondition extends OperatorCondition { public static final OrderConditionType conditionType = OrderConditionType.Time; + private static final String HEADER = "time"; + protected TimeCondition() { } @Override public String toString() { - return "time" + super.toString(); + return HEADER + super.toString(); } private String m_time; @@ -34,4 +36,10 @@ protected void valueFromString(String v) { m_time = v; } + @Override public boolean tryToParse(String conditionStr) { + if (!conditionStr.startsWith(HEADER)) + return false; + conditionStr = conditionStr.replace(HEADER, EMPTY); + return super.tryToParse(conditionStr); + } } \ No newline at end of file diff --git a/ref/client/Types.java b/ref/client/Types.java index 36ac7204..e1b4ea07 100644 --- a/ref/client/Types.java +++ b/ref/client/Types.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -235,7 +235,7 @@ public String getApiString() { public enum WhatToShow { TRADES, MIDPOINT, BID, ASK, // << only these are valid for real-time bars BID_ASK, HISTORICAL_VOLATILITY, OPTION_IMPLIED_VOLATILITY, YIELD_ASK, YIELD_BID, YIELD_BID_ASK, YIELD_LAST, ADJUSTED_LAST, - SCHEDULE + SCHEDULE, AGGTRADES } public enum BarSize { @@ -299,13 +299,28 @@ public static NewsType get( int ordinal) { } } - public enum FADataType { - UNUSED, GROUPS, PROFILES, ALIASES; + public enum FADataType { + GROUPS(1), ALIASES(3); - public static FADataType get( int ordinal) { - return getEnum( ordinal, values() ); - } - } + private int id; + + FADataType(int id) { + this.id = id; + } + + public static FADataType getById(int id) { + for (FADataType faDataType: values()) { + if (faDataType.id == id) { + return faDataType; + } + } + return null; + } + + public int id() { + return id; + } + } public enum SecIdType implements IApiEnum { None, CUSIP, SEDOL, ISIN, RIC; @@ -340,7 +355,7 @@ public static MktDataType get( int ordinal) { } public enum Method implements IApiEnum { - None, EqualQuantity, AvailableEquity, NetLiq, PctChange; + None, Equal, AvailableEquity, NetLiq, ContractsOrShares, Ratio, Percent, MonetaryAmount; public static Method get( String str) { return getValueOf(str, values(), None); @@ -365,6 +380,72 @@ public Boolean toBoolean() { } } + public enum FundDistributionPolicyIndicator implements IApiEnum { + None ("None", "None"), + AccumulationFund("N", "Accumulation Fund"), + IncomeFund ("Y", "Income Fund"); + + String m_value; + String m_name; + + public String getValue() { return m_value; } + public String getName() { return m_name; } + + FundDistributionPolicyIndicator(String value, String name) { + m_value = value; + m_name = name; + } + + public static FundDistributionPolicyIndicator get(String value) { + for (FundDistributionPolicyIndicator v : values() ) { + if (v.m_value == value) { + return v; + } + } + return None; + } + + @Override public String getApiString() { + return m_value; + } + } + + public enum FundAssetType implements IApiEnum { + None ("None", "None"), + Others("000", "Others"), + MoneyMarket ("001", "Money Market"), + FixedIncome ("002", "Fixed Income"), + MultiAsset ("003", "Multi-asset"), + Equity ("004", "Equity"), + Sector ("005", "Sector"), + Guaranteed ("006", "Guaranteed"), + Alternative ("007", "Alternative"); + + String m_value; + String m_name; + + public String getValue() { return m_value; } + public String getName() { return m_name; } + + FundAssetType(String value, String name) { + m_value = value; + m_name = name; + } + + public static FundAssetType get(String value) { + for (FundAssetType v : values() ) { + if (v.m_value == value) { + return v; + } + } + return None; + } + + @Override public String getApiString() { + return m_value; + } + } + public static & IApiEnum> T getValueOf( String v, T[] values, T defaultValue ) { for( T currentEnum : values ) { if( currentEnum.getApiString().equals(v) ) { diff --git a/ref/client/Util.java b/ref/client/Util.java index 8b3d0f34..8bbf1ed8 100644 --- a/ref/client/Util.java +++ b/ref/client/Util.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.client; @@ -197,5 +197,20 @@ public static void appendValidLongValue(StringBuilder sb, String name, long valu sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(Util.LongMaxString(value)); } } - + + public static boolean IsVolOrder(OrderType orderType) { + return orderType == OrderType.VOL; + } + + public static boolean IsPegBenchOrder(OrderType orderType) { + return orderType == OrderType.PEG_BENCH; + } + + public static boolean IsPegMidOrder(OrderType orderType) { + return orderType == OrderType.PEG_MID; + } + + public static Boolean IsPegBestOrder(OrderType orderType) { + return orderType == OrderType.PEG_BEST; + } } diff --git a/ref/controller/Account.java b/ref/controller/Account.java new file mode 100644 index 00000000..d2f71cde --- /dev/null +++ b/ref/controller/Account.java @@ -0,0 +1,26 @@ +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms + * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ + +package com.ib.controller; + +public class Account { + private String m_acct; + private String m_amount; + + public String acct() { return m_acct; } + public String amount() { return m_amount; } + + public void acct(String v) { m_acct = v; } + public void amount(String v) { m_amount = v; } + + Account() { } + + Account(String acct, String amount) { + m_acct = acct; + m_amount = amount; + } + + @Override public String toString() { + return String.format("%s,%s", m_acct, m_amount != null ? m_amount : ""); + } +} diff --git a/ref/controller/AdvisorUtil.java b/ref/controller/AdvisorUtil.java index fd0c9918..616b8869 100644 --- a/ref/controller/AdvisorUtil.java +++ b/ref/controller/AdvisorUtil.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.controller; @@ -10,8 +10,6 @@ import java.util.List; import com.ib.client.Types.Method; -import com.ib.controller.Profile.Allocation; -import com.ib.controller.Profile.Type; @@ -29,6 +27,7 @@ static List getGroups_( String xml) throws IOException { List list = new ArrayList<>(); Group group = null; + Account account = null; BufferedReader reader = new BufferedReader( new StringReader( xml) ); String line; @@ -66,6 +65,12 @@ else if (line.equals( "")) { else if (line.startsWith( "")) { group.defaultMethod( Method.valueOf( getVal( line) ) ); } + else if (line.startsWith( "")) { + group.defaultSize( getVal( line) ); + } + else if (line.startsWith( "")) { + group.riskCriteria( getVal( line) ); + } else if (line.startsWith( "")) { if (line.equals( "")) { state = 2; } - else { - group.addAccount( getVal( line) ); - } - break; - - // should not happen - default: - break; - } - } - - return list; - } - - static List getProfiles( String xml) { - try { - return getProfiles_( xml); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - static List getProfiles_( String xml) throws IOException { - List list = new ArrayList<>(); - - Profile profile = null; - Allocation alloc = null; - - BufferedReader reader = new BufferedReader( new StringReader( xml) ); - String line; - int state = 0; // 0=none; 1=list of groups; 2=reading group 3=listOfAllocations 4=allocation - while ( (line=reader.readLine() ) != null) { - line = line.trim(); - - switch( state) { - // top of file - case 0: - if (line.equals( "")) { - state = 1; - } - break; - - // reading profiles - case 1: - if (line.equals( "")) { - profile = new Profile(); - state = 2; - } - else if (line.equals( "")) { - state = 0; - } - else { - err( line); - } - break; - - // reading Profile - case 2: - if (line.startsWith( "") ) { - profile.name( getVal( line) ); - } - else if (line.startsWith( "")) { - int i = Integer.parseInt( getVal( line) ); - profile.type( Type.get( i) ); - } - else if (line.startsWith( "")) { - list.add( profile); - state = 1; - } - else { - err( line); - } - break; - - // reading list of allocations - case 3: - if (line.equals( "")) { - alloc = new Allocation(); + else if (line.startsWith( "")) { - state = 2; - } else { err( line); } break; - // reading Allocation + // reading account case 4: - if (line.startsWith( "") ) { - alloc.account( getVal( line) ); - } - else if (line.startsWith( "") ) { - alloc.amount( getVal( line) ); + if (line.equals( "")) { + group.addAccount( account); + state = 3; } - else if (line.startsWith( "") ) { - // skip this + else if (line.startsWith( "")) { + account.acct( getVal( line) ); } - else if (line.equals( "") ) { - profile.add( alloc); - state = 3; + else if (line.startsWith( "")) { + account.amount( getVal( line) ); } else { err( line); @@ -301,8 +220,13 @@ public static String getGroupsXml(List groups) { buf.append( String.format( "%s%n", group.name() ) ); buf.append( String.format( "%s%n", group.defaultMethod() ) ); buf.append( ""); - for( String acct : group.accounts() ) { - buf.append( String.format( "%s%n", acct) ); + for( Account account : group.accounts() ) { + buf.append( String.format( "\n") ); + buf.append( String.format( "%s%n", account.acct()) ); + if (account.amount() != null && account.amount().length() > 0) { + buf.append( String.format( "%s%n", account.amount()) ); + } + buf.append( String.format( "\n") ); } buf.append( "\n"); buf.append( "\n"); @@ -310,26 +234,4 @@ public static String getGroupsXml(List groups) { buf.append( "\n"); return buf.toString(); } - - public static String getProfilesXml(List profiles) { - StringBuilder buf = new StringBuilder(); - buf.append( "\n"); - buf.append( "\n"); - for( Profile profile : profiles) { - buf.append( "\n"); - buf.append( String.format( "%s%n", profile.name() ) ); - buf.append( String.format( "%s%n", profile.type().ordinal() ) ); - buf.append( "\n"); - for( Allocation alloc : profile.allocations() ) { - buf.append( "\n"); - buf.append( String.format( "%s%n", alloc.account() ) ); - buf.append( String.format( "%s%n", alloc.amount() ) ); - buf.append( "\n"); - } - buf.append( "\n"); - buf.append( "\n"); - } - buf.append( "\n"); - return buf.toString(); - } } diff --git a/ref/controller/ApiController.java b/ref/controller/ApiController.java index 883585ed..63e5c28e 100644 --- a/ref/controller/ApiController.java +++ b/ref/controller/ApiController.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2024 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.controller; @@ -121,8 +121,9 @@ private void startMsgProcessingThread() { }).start(); } - public void connect( String host, int port, int clientId, String connectionOpts ) { + public void connect( String host, int port, int clientId, String connectOptions ) { if(!m_client.isConnected()){ + m_client.setConnectOptions(connectOptions); m_client.eConnect(host, port, clientId); startMsgProcessingThread(); sendEOM(); @@ -767,21 +768,18 @@ public void reqExecutions( ExecutionFilter filter, ITradeReportHandler handler) // ---------------------------------------- Advisor info ---------------------------------------- public interface IAdvisorHandler { void groups(List groups); - void profiles(List profiles); void aliases(List aliases); void updateGroupsEnd(String text); - void updateProfilesEnd(String text); } private static final int REPLACE_FA_GROUPS_REQ_ID = 0; - private static final int REPLACE_FA_PROFILES_REQ_ID = 1; public void reqAdvisorData( FADataType type, IAdvisorHandler handler) { if (!checkConnection()) return; m_advisorHandler = handler; - m_client.requestFA( type.ordinal() ); + m_client.requestFA( type.id() ); sendEOM(); } @@ -789,15 +787,7 @@ public void updateGroups( List groups) { if (!checkConnection()) return; - m_client.replaceFA( REPLACE_FA_GROUPS_REQ_ID, FADataType.GROUPS.ordinal(), AdvisorUtil.getGroupsXml( groups) ); - sendEOM(); - } - - public void updateProfiles(List profiles) { - if (!checkConnection()) - return; - - m_client.replaceFA( REPLACE_FA_PROFILES_REQ_ID, FADataType.PROFILES.ordinal(), AdvisorUtil.getProfilesXml( profiles) ); + m_client.replaceFA( REPLACE_FA_GROUPS_REQ_ID, FADataType.GROUPS.id(), AdvisorUtil.getGroupsXml( groups) ); sendEOM(); } @@ -806,7 +796,7 @@ public void updateProfiles(List profiles) { return; } - FADataType type = FADataType.get( faDataType); + FADataType type = FADataType.getById( faDataType); switch( type) { case GROUPS: @@ -814,11 +804,6 @@ public void updateProfiles(List profiles) { m_advisorHandler.groups(groups); break; - case PROFILES: - List profiles = AdvisorUtil.getProfiles( xml); - m_advisorHandler.profiles(profiles); - break; - case ALIASES: List aliases = AdvisorUtil.getAliases( xml); m_advisorHandler.aliases(aliases); @@ -835,9 +820,6 @@ public void updateProfiles(List profiles) { case REPLACE_FA_GROUPS_REQ_ID: m_advisorHandler.updateGroupsEnd(text); break; - case REPLACE_FA_PROFILES_REQ_ID: - m_advisorHandler.updateProfilesEnd(text); - break; default: break; } @@ -894,11 +876,11 @@ public void cancelAllOrders() { sendEOM(); } - public void exerciseOption( String account, Contract contract, ExerciseType type, int quantity, boolean override) { + public void exerciseOption( String account, Contract contract, ExerciseType type, int quantity, boolean override, String manualOrderTime, String customerAccount, boolean professionalCustomer) { if (!checkConnection()) return; - m_client.exerciseOptions( m_reqId++, contract, type.ordinal(), quantity, account, override ? 1 : 0); + m_client.exerciseOptions( m_reqId++, contract, type.ordinal(), quantity, account, override ? 1 : 0, manualOrderTime, customerAccount, professionalCustomer); sendEOM(); } @@ -1198,6 +1180,8 @@ public void reqBulletins( boolean allMessages, IBulletinHandler handler) { } public void cancelBulletins() { + m_bulletinHandler = null; + if (!checkConnection()) return; @@ -1205,7 +1189,9 @@ public void cancelBulletins() { } @Override public void updateNewsBulletin(int msgId, int msgType, String message, String origExchange) { - m_bulletinHandler.bulletin( msgId, NewsType.get( msgType), message, origExchange); + if (m_bulletinHandler != null) + m_bulletinHandler.bulletin( msgId, NewsType.get( msgType), message, origExchange); + recEOM(); } diff --git a/ref/controller/Group.java b/ref/controller/Group.java index 44a8ca70..36463dd8 100644 --- a/ref/controller/Group.java +++ b/ref/controller/Group.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2023 Interactive Brokers LLC. All rights reserved. This code is subject to the terms * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ package com.ib.controller; @@ -6,29 +6,49 @@ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; +import java.util.stream.Collectors; import com.ib.client.Types.Method; public class Group { - private String m_name; - private Method m_defaultMethod; - private List m_accounts = new ArrayList<>(); - - public String name() { return m_name; } - public Method defaultMethod() { return m_defaultMethod; } - public List accounts() { return m_accounts; } - - public void name( String v) { m_name = v; } - public void defaultMethod( Method v) { m_defaultMethod = v; } - public void addAccount( String acct) { m_accounts.add( acct); } - - /** @param val is a comma or space delimited string of accounts */ - public void setAllAccounts(String val) { - m_accounts.clear(); - - StringTokenizer st = new StringTokenizer( val, " ,"); - while( st.hasMoreTokens() ) { - m_accounts.add( st.nextToken() ); - } - } + private String m_name; + private Method m_defaultMethod; + private List m_accounts = new ArrayList(); + private String m_defaultSize; + private String m_riskCriteria; + + public String name() { return m_name; } + public Method defaultMethod() { return m_defaultMethod; } + public List accounts() { return m_accounts; } + public String defaultSize() { return m_defaultSize; } + public String riskCriteria() { return m_riskCriteria; } + + public void name( String v) { m_name = v; } + public void defaultMethod( Method v) { m_defaultMethod = v; } + public void addAccount( Account account) { m_accounts.add( account); } + public void defaultSize(String v) { m_defaultSize = v; } + public void riskCriteria(String v) { m_riskCriteria = v; } + + public String getAllAccounts() { + return accounts().stream().map(Object::toString).collect(Collectors.joining(";")); + } + + /** @param val is a string of accounts in format: acct1,amount1;acct2,amount2;... */ + public void setAllAccounts(String val) { + m_accounts.clear(); + + StringTokenizer st1 = new StringTokenizer(val, ";"); + while( st1.hasMoreTokens() ) { + String account = st1.nextToken(); + StringTokenizer st2 = new StringTokenizer(account, ","); + if (st2.hasMoreTokens()) { + String acct = st2.nextToken(); + String amount = null; + if (st2.hasMoreTokens()) { + amount = st2.nextToken(); + } + m_accounts.add( new Account(acct, amount)); + } + } + } } diff --git a/ref/controller/MarketValueTag.java b/ref/controller/MarketValueTag.java index 208ee3a9..65c0fc4f 100644 --- a/ref/controller/MarketValueTag.java +++ b/ref/controller/MarketValueTag.java @@ -11,6 +11,7 @@ public enum MarketValueTag { IssuerOptionValue("IssuerOption"), NetLiquidationByCurrency("Net Liq"), CashBalance("CashBalance"), + Cryptocurrency("Cryptocurrency"), TotalCashBalance("TotalCashBalance"), AccruedCash("AccruedCash"), StockMarketValue("Stocks"), diff --git a/ref/controller/Profile.java b/ref/controller/Profile.java deleted file mode 100644 index b4a6ab59..00000000 --- a/ref/controller/Profile.java +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms - * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */ - -package com.ib.controller; - -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import com.ib.client.Types; - -public class Profile { - static final String SEP = "/"; - - private String m_name; - private Type m_type; - private List m_allocations = new ArrayList<>(); - - public String name() { return m_name; } - public Type type() { return m_type; } - public List allocations() { return m_allocations; } - - public void name( String v) { m_name = v; } - public void type( Type v) { m_type = v; } - public void add( Allocation v) { m_allocations.add( v); } - - public void setAllocations(String val) { - m_allocations.clear(); - - StringTokenizer st = new StringTokenizer( val, ", "); - while( st.hasMoreTokens() ) { - String tok = st.nextToken(); - StringTokenizer st2 = new StringTokenizer( tok, SEP); - - Allocation alloc = new Allocation(); - alloc.account( st2.nextToken() ); - alloc.amount( st2.nextToken() ); - - m_allocations.add( alloc); - } - } - - public enum Type { - NONE, Percents, Ratios, Shares; - - public static Type get( int ordinal) { - return Types.getEnum( ordinal, values() ); - } - } - - public static class Allocation { - private String m_account; - private String m_amount; - - public String account() { return m_account; } - public String amount() { return m_amount; } - - public void account( String v) { m_account = v; } - public void amount( String v) { m_amount = v; } - - @Override public String toString() { - return m_account + SEP + m_amount; - } - } -} diff --git a/src/api/account/account.ts b/src/api/account/account.ts new file mode 100644 index 00000000..17d4c866 --- /dev/null +++ b/src/api/account/account.ts @@ -0,0 +1,7 @@ +export interface Account { + acct?: string; + + amount?: string; +} + +export default Account; diff --git a/src/api/account/market-value.ts b/src/api/account/market-value.ts new file mode 100644 index 00000000..da17a313 --- /dev/null +++ b/src/api/account/market-value.ts @@ -0,0 +1,28 @@ +export const MarketValueTag = { + AccountOrGroup: "AccountOrGroup", + RealCurrency: "RealCurrency", + IssuerOptionValue: "IssuerOption", + NetLiquidationByCurrency: "Net Liq", + CashBalance: "CashBalance", + Cryptocurrency: "Cryptocurrency", + TotalCashBalance: "TotalCashBalance", + AccruedCash: "AccruedCash", + StockMarketValue: "Stocks", + OptionMarketValue: "Options", + FutureOptionValue: "Futures", + FuturesPNL: "FuturesPNL", + UnrealizedPnL: "UnrealizedPnL", + RealizedPnL: "RealizedPnL", + ExchangeRate: "ExchangeRate", + FundValue: "Fund", + NetDividend: "NetDividend", + MutualFundValue: "MutualFund", + MoneyMarketFundValue: "MoneyMarketFund", + CorporateBondValue: "CorporateBond", + TBondValue: "TBond", + TBillValue: "TBill", + WarrantValue: "Warrant", + FxCashBalance: "FxCashBalance", +} as const; +export type MarketValueTag = + (typeof MarketValueTag)[keyof typeof MarketValueTag]; diff --git a/src/api/api.ts b/src/api/api.ts index b2d73592..64d0ccc5 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -18,7 +18,7 @@ import NewsProvider from "./data/container/news-provider"; import SoftDollarTier from "./data/container/soft-dollar-tier"; import TagValue from "./data/container/tag-value"; import { EventName } from "./data/enum/event-name"; -import FADataType from "./data/enum/fad-data-type"; +import FADataType from "./data/enum/fa-data-type"; import LogLevel from "./data/enum/log-level"; import MIN_SERVER_VER from "./data/enum/min-server-version"; import OptionExerciseAction from "./data/enum/option-exercise-action"; @@ -84,7 +84,7 @@ export interface IBApiCreationOptions { /** Maximum supported version. */ export const MAX_SUPPORTED_SERVER_VERSION = - MIN_SERVER_VER.PENDING_PRICE_REVISION; + MIN_SERVER_VER.PROFESSIONAL_CUSTOMER; /** Minimum supported version. */ export const MIN_SERVER_VER_SUPPORTED = 38; @@ -3349,7 +3349,7 @@ export declare interface IBApi { * - FullMaintMarginReq-C: Maintenance Margin of commodity segment's portfolio with no discounts or intraday credits. * - FullMaintMarginReq-S: Maintenance Margin of security segment's portfolio with no discounts or intraday credits. * - FundValue: Value of funds value (money market funds + mutual funds). - * - FutureOptionValue: Real-time market-to-market value of futures options. + * - FutureOption: Real-time market-to-market value of futures options. * - FuturesPNL: Real-time changes in futures value since last settlement. * - FxCashBalance: Cash balance in related IB-UKL account. * - GrossPositionValue: Gross Position Value in securities segment. @@ -3419,6 +3419,7 @@ export declare interface IBApi { * - StockMarketValue: Real-time mark-to-market value of stock. * - TBondValue: Value of treasury bonds. * - TBillValue: Value of treasury bills. + * - Cryptocurrency: Total Cash Balance including Future PNL. * - TotalCashBalance: Total Cash Balance including Future PNL. * - TotalCashValue: Total cash value of stock, commodities and securities. * - TotalCashValue-C: CashBalance in commodity segment. diff --git a/src/api/contract/contract.ts b/src/api/contract/contract.ts index 7e4b1302..a88a28d9 100644 --- a/src/api/contract/contract.ts +++ b/src/api/contract/contract.ts @@ -23,6 +23,9 @@ export interface Contract { */ lastTradeDateOrContractMonth?: string; + /** The contract's last trading day. */ + lastTradeDate?: string; + /** The option's strike price. */ strike?: number; diff --git a/src/api/contract/contractDetails.ts b/src/api/contract/contractDetails.ts index 38b8b3c3..dd788a9f 100644 --- a/src/api/contract/contractDetails.ts +++ b/src/api/contract/contractDetails.ts @@ -1,6 +1,7 @@ import TagValue from "../data/container/tag-value"; import SecType from "../data/enum/sec-type"; import { Contract } from "./contract"; +import { FundAssetType, FundDistributionPolicyIndicator } from "./fund"; /** * Extended contract details. @@ -292,6 +293,25 @@ export interface ContractDetails { * Order's suggested size increment. */ suggestedSizeIncrement?: number; + + // FUND values + fundName?: string; + fundFamily?: string; + fundType?: string; + fundFrontLoad?: string; + fundBackLoad?: string; + fundBackLoadTimeInterval?: string; + fundManagementFee?: string; + fundClosed?: boolean; + fundClosedForNewInvestors?: boolean; + fundClosedForNewMoney?: boolean; + fundNotifyAmount?: string; + fundMinimumInitialPurchase?: string; + fundSubsequentMinimumPurchase?: string; + fundBlueSkyStates?: string; + fundBlueSkyTerritories?: string; + fundDistributionPolicyIndicator?: FundDistributionPolicyIndicator; + fundAssetType?: FundAssetType; } export default ContractDetails; diff --git a/src/api/contract/fund.ts b/src/api/contract/fund.ts new file mode 100644 index 00000000..49f801a2 --- /dev/null +++ b/src/api/contract/fund.ts @@ -0,0 +1,14 @@ +export const FundDistributionPolicyIndicator = { + None: "None", + AccumulationFund: "N", + IncomeFund: "Y", +} as const; +export type FundDistributionPolicyIndicator = + (typeof FundDistributionPolicyIndicator)[keyof typeof FundDistributionPolicyIndicator]; + +export const FundAssetType = { + None: "None", + AccumulationFund: "N", + IncomeFund: "Y", +} as const; +export type FundAssetType = (typeof FundAssetType)[keyof typeof FundAssetType]; diff --git a/src/api/data/enum/fad-data-type.ts b/src/api/data/enum/fa-data-type.ts similarity index 100% rename from src/api/data/enum/fad-data-type.ts rename to src/api/data/enum/fa-data-type.ts diff --git a/src/api/data/enum/min-server-version.ts b/src/api/data/enum/min-server-version.ts index 39b450d5..1f546fa0 100644 --- a/src/api/data/enum/min-server-version.ts +++ b/src/api/data/enum/min-server-version.ts @@ -125,6 +125,12 @@ export enum MIN_SERVER_VER { BOND_ISSUERID = 176, FA_PROFILE_DESUPPORT = 177, PENDING_PRICE_REVISION = 178, + FUND_DATA_FIELDS = 179, + MANUAL_ORDER_TIME_EXERCISE_OPTIONS = 180, + OPEN_ORDER_AD_STRATEGY = 181, + LAST_TRADE_DATE = 182, + CUSTOMER_ACCOUNT = 183, + PROFESSIONAL_CUSTOMER = 184, } export default MIN_SERVER_VER; diff --git a/src/api/historical/what-to-show.ts b/src/api/historical/what-to-show.ts index b0d07147..8b7c0db0 100644 --- a/src/api/historical/what-to-show.ts +++ b/src/api/historical/what-to-show.ts @@ -21,5 +21,6 @@ export const WhatToShow = { YIELD_LAST: "YIELD_LAST", ADJUSTED_LAST: "ADJUSTED_LAST", SCHEDULE: "SCHEDULE", + AGGTRADES: "AGGTRADES", } as const; export type WhatToShow = (typeof WhatToShow)[keyof typeof WhatToShow]; diff --git a/src/api/order/enum/orderType.ts b/src/api/order/enum/orderType.ts index b7593bbf..3950d313 100644 --- a/src/api/order/enum/orderType.ts +++ b/src/api/order/enum/orderType.ts @@ -45,6 +45,8 @@ export enum OrderType { PEG_SRF_VOL = "PSV", } +export const isVolOrder = (orderType: OrderType) => orderType == OrderType.VOL; + export const isPegBenchOrder = (orderType: OrderType): boolean => { if (orderType == OrderType.PEG_BENCH || (orderType as string) == "PEGBENCH") return true; diff --git a/src/api/order/order.ts b/src/api/order/order.ts index e01a510b..b38566ed 100644 --- a/src/api/order/order.ts +++ b/src/api/order/order.ts @@ -757,8 +757,15 @@ export interface Order { /** This offset is applied when the spread is an odd number of cents wide. This offset must be in half-penny increments. For IBKRATS orders. */ midOffsetAtHalf?: number; + + customerAccount?: string; + + professionalCustomer?: boolean; } export const COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID = Infinity; +export const isCompeteAgainstBestOffsetUpToMid = (order: Order): boolean => + order.competeAgainstBestOffset === COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID; + export default Order; diff --git a/src/common/errorCode.ts b/src/common/errorCode.ts index 931ea6c7..510ef201 100644 --- a/src/common/errorCode.ts +++ b/src/common/errorCode.ts @@ -222,55 +222,70 @@ export enum ErrorCode { /** Request Head Time Stamp Sending Error. */ FAIL_SEND_REQHEADTIMESTAMP = 566, - /** Cancel Head Time Stamp Sending Error. */ - FAIL_SEND_CANHEADTIMESTAMP = 567, + /** CRequest Histogram Data Sending Error */ + FAIL_SEND_REQHISTOGRAMDATA = 567, /** Request Market Rule Sending Error. */ - FAIL_SEND_REQMARKETRULE = 568, + FAIL_SEND_CANCELHISTOGRAMDATA = 568, + + /** Cancel PnL Single Sending Error. */ + FAIL_SEND_CANCELHEADTIMESTAMP = 569, + + /** Request Historical Ticks Sending Error. */ + FAIL_SEND_HISTORICAL_TICK = 569, + + /** Request Market Rule Sending Error. */ + FAIL_SEND_REQMARKETRULE = 570, /** Request PnL Sending Error. */ - FAIL_SEND_REQPNL = 566, + FAIL_SEND_REQPNL = 571, /** Cancel PnL Sending Error. */ - FAIL_SEND_CANPNL = 567, + FAIL_SEND_CANCELPNL = 572, - /** Request PnL Single Sending Error. */ - FAIL_SEND_REQPNL_SINGLE = 568, + /** Request PnL Single Error. */ + FAIL_SEND_REQPNLSINGLE = 573, - /** Cancel PnL Single Sending Error. */ - FAIL_SEND_CANPNL_SINGLE = 569, + /** Cancel PnL Single Sending Error . */ + FAIL_SEND_CANCELPNLSINGLE = 574, - /** Request Historical Ticks Sending Error. */ - FAIL_SEND_HISTORICAL_TICK = 569, + /** Request Historical Ticks Error. */ + FAIL_SEND_REQHISTORICALTICKS = 575, - /** Request Tick-By-Tick Sending Error. */ - FAIL_SEND_REQTICKBYTICK = 570, + /** Request Tick-By-Tick Data Sending Error */ + FAIL_SEND_REQTICKBYTICKDATA = 576, - /** Cancel Tick-By-Tick Sending Error. */ - FAIL_SEND_CANTICKBYTICK = 571, + /** Cancel Tick-By-Tick Data Sending Error */ + FAIL_SEND_CANCELTICKBYTICKDATA = 577, - /** Request Completed Orders Sending Error. */ - FAIL_SEND_REQ_COMPLETED_ORDERS = 572, + /** Request Completed Orders Sending Error */ + FAIL_SEND_REQCOMPLETEDORDERS = 578, - /** Request WSH Meta Data Sending Error. */ - FAIL_SEND_REQ_WSH_META_DATA = 573, + /** Invalid symbol in string */ + INVALID_SYMBOL = 579, + + /** "Request WSH Meta Data Sending Error */ + FAIL_SEND_REQ_WSH_META_DATA = 580, /** Cancel WSH Meta Data Sending Error */ - FAIL_SEND_CAN_WSH_META_DATA = 574, + FAIL_SEND_CAN_WSH_META_DATA = 581, /** Request WSH Event Data Sending Error */ - FAIL_SEND_REQ_WSH_EVENT_DATA = 575, + FAIL_SEND_REQ_WSH_EVENT_DATA = 582, /** Cancel WSH Event Data Sending Error */ - FAIL_SEND_CAN_WSH_EVENT_DATA = 576, + FAIL_SEND_CAN_WSH_EVENT_DATA = 583, - /* Invalid symbol in string */ - INVALID_SYMBOL = 579, + /** Request User Info Sending Error */ + FAIL_SEND_REQ_USER_INFO = 584, + + /** FA Profile is not supported anymore, use FA Group instead */ + FA_PROFILE_NOT_SUPPORTED = 585, - /* Part of requested market data is not subscribed. */ + /** Part of requested market data is not subscribed. */ PART_OF_REQUESTED_DATA_NOT_SUBSCRIBED = 10090, - /* Requested market data is not subscribed. Displaying delayed market data. */ + /** Requested market data is not subscribed. Displaying delayed market data. */ DISPLAYING_DELAYED_DATA = 10167, /* News feed is not allowed. */ diff --git a/src/core/io/decoder.ts b/src/core/io/decoder.ts index 0c841a27..6c52e950 100644 --- a/src/core/io/decoder.ts +++ b/src/core/io/decoder.ts @@ -1,8 +1,11 @@ -import { ComboLeg } from "../../api/contract/comboLeg"; import { Contract } from "../../api/contract/contract"; import { ContractDescription } from "../../api/contract/contractDescription"; import { ContractDetails } from "../../api/contract/contractDetails"; import { DeltaNeutralContract } from "../../api/contract/deltaNeutralContract"; +import { + FundAssetType, + FundDistributionPolicyIndicator, +} from "../../api/contract/fund"; import DepthMktDataDescription from "../../api/data/container/depth-mkt-data-description"; import FamilyCode from "../../api/data/container/family-code"; import NewsProvider from "../../api/data/container/news-provider"; @@ -822,6 +825,8 @@ export class Decoder { orderDecoder.readPostToAts(); orderDecoder.readAutoCancelParent(MIN_SERVER_VER.AUTO_CANCEL_PARENT); orderDecoder.readPegBestPegMidOrderAttributes(); + orderDecoder.readCustomerAccount(); + orderDecoder.readProfessionalCustomer(); this.emit(EventName.openOrder, order.orderId, contract, order, orderState); } @@ -946,6 +951,9 @@ export class Decoder { contract.contract.symbol = this.readStr(); contract.contract.secType = this.readStr() as SecType; this.readLastTradeDate(contract, false); + if (this.serverVersion >= MIN_SERVER_VER.LAST_TRADE_DATE) { + contract.contract.lastTradeDate = this.readStr(); + } contract.contract.strike = this.readDouble(); contract.contract.right = validateOptionType(this.readStr() as OptionType); contract.contract.exchange = this.readStr(); @@ -1009,40 +1017,64 @@ export class Decoder { contract.secIdList.push(tagValue); } } + } - if (this.serverVersion >= MIN_SERVER_VER.AGG_GROUP) { - contract.aggGroup = this.readInt(); - } + if (this.serverVersion >= MIN_SERVER_VER.AGG_GROUP) { + contract.aggGroup = this.readInt(); + } - if (this.serverVersion >= MIN_SERVER_VER.UNDERLYING_INFO) { - contract.underSymbol = this.readStr(); - contract.underSecType = this.readStr() as SecType; - } + if (this.serverVersion >= MIN_SERVER_VER.UNDERLYING_INFO) { + contract.underSymbol = this.readStr(); + contract.underSecType = this.readStr() as SecType; + } - if (this.serverVersion >= MIN_SERVER_VER.MARKET_RULES) { - contract.marketRuleIds = this.readStr(); - } + if (this.serverVersion >= MIN_SERVER_VER.MARKET_RULES) { + contract.marketRuleIds = this.readStr(); + } - if (this.serverVersion >= MIN_SERVER_VER.REAL_EXPIRATION_DATE) { - contract.realExpirationDate = this.readStr(); - } + if (this.serverVersion >= MIN_SERVER_VER.REAL_EXPIRATION_DATE) { + contract.realExpirationDate = this.readStr(); + } - if (this.serverVersion >= MIN_SERVER_VER.STOCK_TYPE) { - contract.stockType = this.readStr(); - } + if (this.serverVersion >= MIN_SERVER_VER.STOCK_TYPE) { + contract.stockType = this.readStr(); + } - if ( - this.serverVersion >= MIN_SERVER_VER.FRACTIONAL_SIZE_SUPPORT && - this.serverVersion < MIN_SERVER_VER.SIZE_RULES - ) { - this.readDecimal(); // sizeMinTick - not used anymore - } + if ( + this.serverVersion >= MIN_SERVER_VER.FRACTIONAL_SIZE_SUPPORT && + this.serverVersion < MIN_SERVER_VER.SIZE_RULES + ) { + this.readDecimal(); // sizeMinTick - not used anymore + } - if (this.serverVersion >= MIN_SERVER_VER.SIZE_RULES) { - contract.minSize = this.readDecimal(); - contract.sizeIncrement = this.readDecimal(); - contract.suggestedSizeIncrement = this.readDecimal(); - } + if (this.serverVersion >= MIN_SERVER_VER.SIZE_RULES) { + contract.minSize = this.readDecimal(); + contract.sizeIncrement = this.readDecimal(); + contract.suggestedSizeIncrement = this.readDecimal(); + } + + if ( + this.serverVersion >= MIN_SERVER_VER.FUND_DATA_FIELDS && + contract.contract.secType == SecType.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() as FundDistributionPolicyIndicator; + contract.fundAssetType = this.readStr() as FundAssetType; } this.emit(EventName.contractDetails, reqId, contract); @@ -2575,6 +2607,8 @@ export class Decoder { orderDecoder.readCompletedTime(); orderDecoder.readCompletedStatus(); orderDecoder.readPegBestPegMidOrderAttributes(); + orderDecoder.readCustomerAccount(); + orderDecoder.readProfessionalCustomer(); this.emit(EventName.completedOrder, contract, order, orderState); } @@ -2656,164 +2690,6 @@ export class Decoder { this.emit(EventName.userInfo, reqId, whiteBrandingId); } - /** - * Decode a [[Contract]] object from data queue. - * @deprecated to remove - */ - private decodeContract(version: number): Contract { - const contract: Contract = {}; - - contract.conId = this.readInt(); - contract.symbol = this.readStr(); - contract.secType = this.readStr() as SecType; - contract.lastTradeDateOrContractMonth = this.readStr(); - contract.strike = this.readDouble(); - contract.right = validateOptionType(this.readStr() as OptionType); - - if (version >= 32) { - contract.multiplier = this.readInt(); - } - - contract.exchange = this.readStr(); - contract.currency = this.readStr(); - contract.localSymbol = this.readStr(); - - if (version >= 32) { - contract.tradingClass = this.readStr(); - } - - return contract; - } - - /** - * Decode a [[Order]] object from data queue. - * @deprecated to remove - */ - private decodeOrder(version: number): Order { - const order: Order = {}; - - order.action = this.readStr() as OrderAction; - - if (this.serverVersion >= MIN_SERVER_VER.FRACTIONAL_POSITIONS) { - order.totalQuantity = this.readDouble(); - } else { - order.totalQuantity = this.readInt(); - } - - order.orderType = this.readStr() as OrderType; - - if (version < 29) { - order.lmtPrice = this.readDouble(); - } else { - order.lmtPrice = this.readDoubleOrUndefined(); - } - - if (version < 30) { - order.auxPrice = this.readDouble(); - } else { - order.auxPrice = this.readDoubleOrUndefined(); - } - - order.tif = this.readStr() as TimeInForce; - order.ocaGroup = this.readStr(); - order.account = this.readStr(); - order.openClose = this.readStr(); - order.origin = this.readInt(); - order.orderRef = this.readStr(); - order.clientId = this.readInt(); - order.permId = this.readInt(); - order.outsideRth = this.readBool(); - order.hidden = this.readBool(); - order.discretionaryAmt = this.readDouble(); - order.goodAfterTime = this.readStr(); - this.readStr(); // skip deprecated sharesAllocation field - order.faGroup = this.readStr(); - order.faMethod = this.readStr(); - order.faPercentage = this.readStr(); - order.faProfile = this.readStr(); - if (this.serverVersion >= MIN_SERVER_VER.MODELS_SUPPORT) { - order.modelCode = this.readStr(); - } - order.goodTillDate = this.readStr(); - order.rule80A = this.readStr(); - order.percentOffset = this.readDoubleOrUndefined(); - order.settlingFirm = this.readStr(); - order.shortSaleSlot = this.readInt(); - order.designatedLocation = this.readStr(); - - if (this.serverVersion === MIN_SERVER_VER.SSHORTX_OLD) { - this.readInt(); // exemptCode - } else if (version >= 23) { - order.exemptCode = this.readInt(); - } - - order.auctionStrategy = this.readInt(); - order.startingPrice = this.readDoubleOrUndefined(); - order.stockRefPrice = this.readDoubleOrUndefined(); - order.delta = this.readDoubleOrUndefined(); - order.stockRangeLower = this.readDoubleOrUndefined(); - order.stockRangeUpper = this.readDoubleOrUndefined(); - order.displaySize = this.readInt(); - order.blockOrder = this.readBool(); - order.sweepToFill = this.readBool(); - order.allOrNone = this.readBool(); - order.minQty = this.readIntOrUndefined(); - order.ocaType = this.readInt(); - order.eTradeOnly = this.readBool(); - order.firmQuoteOnly = this.readBool(); - order.nbboPriceCap = this.readDoubleOrUndefined(); - order.parentId = this.readInt(); - order.triggerMethod = this.readInt(); - order.volatility = this.readDoubleOrUndefined(); - order.volatilityType = this.readInt(); - order.deltaNeutralOrderType = this.readStr(); - order.deltaNeutralAuxPrice = this.readDoubleOrUndefined(); - - if (version >= 27 && order?.deltaNeutralOrderType.length) { - order.deltaNeutralConId = this.readInt(); - order.deltaNeutralSettlingFirm = this.readStr(); - order.deltaNeutralClearingAccount = this.readStr(); - order.deltaNeutralClearingIntent = this.readStr(); - } - - if (version >= 31 && order?.deltaNeutralOrderType.length) { - order.deltaNeutralOpenClose = this.readStr(); - order.deltaNeutralShortSale = this.readBool(); - order.deltaNeutralShortSaleSlot = this.readInt(); - order.deltaNeutralDesignatedLocation = this.readStr(); - } - - order.continuousUpdate = this.readInt(); - order.referencePriceType = this.readInt(); - order.trailStopPrice = this.readDoubleOrUndefined(); - - if (version >= 30) { - order.trailingPercent = this.readDoubleOrUndefined(); - } - - order.basisPoints = this.readDoubleOrUndefined(); - order.basisPointsType = this.readIntOrUndefined(); - - return order; - } - - /** - * Decode a [[ComboLeg]] object from data queue. - * @deprecated to remove - */ - private decodeComboLeg(): ComboLeg { - return { - conId: this.readInt(), - ratio: this.readInt(), - action: this.readStr() as OrderAction, - exchange: this.readStr(), - openClose: this.readInt(), - shortSaleSlot: this.readInt(), - designatedLocation: this.readStr(), - exemptCode: this.readInt(), - }; - } - /** * Read last trade date, parse it and assign to proper [[ContractDetails]] attributes. */ @@ -3661,4 +3537,16 @@ class OrderDecoder { this.order.midOffsetAtHalf = this.decoder.readDoubleOrUndefined(); } } + + readCustomerAccount() { + if (this.serverVersion >= MIN_SERVER_VER.CUSTOMER_ACCOUNT) { + this.order.customerAccount = this.decoder.readStr(); + } + } + + readProfessionalCustomer() { + if (this.serverVersion >= MIN_SERVER_VER.PROFESSIONAL_CUSTOMER) { + this.order.professionalCustomer = this.decoder.readBool(); + } + } } diff --git a/src/core/io/encoder.ts b/src/core/io/encoder.ts index 393fb1cc..b4e4ddf3 100644 --- a/src/core/io/encoder.ts +++ b/src/core/io/encoder.ts @@ -3,7 +3,7 @@ import { ScanCode } from "../../api-next/market-scanner/market-scanner"; import { Contract } from "../../api/contract/contract"; import WshEventData from "../../api/contract/wsh"; import TagValue from "../../api/data/container/tag-value"; -import FADataType from "../../api/data/enum/fad-data-type"; +import FADataType from "../../api/data/enum/fa-data-type"; import LogLevel from "../../api/data/enum/log-level"; import MIN_SERVER_VER from "../../api/data/enum/min-server-version"; import OptionExerciseAction from "../../api/data/enum/option-exercise-action"; @@ -22,10 +22,11 @@ import { isPegBenchOrder, isPegBestOrder, isPegMidOrder, + isVolOrder, } from "../../api/order/enum/orderType"; import { - COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID, Order, + isCompeteAgainstBestOffsetUpToMid, } from "../../api/order/order"; import { ExecutionFilter } from "../../api/report/executionFilter"; import { ErrorCode } from "../../common/errorCode"; @@ -608,6 +609,9 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { exerciseQuantity: number, account: string, override: number, + manualOrderTime: string = "", + customerAccount: string = "", + professionalCustomer: boolean = false, ): void { const version = 2; @@ -629,6 +633,37 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { } } + if ( + this.serverVersion < MIN_SERVER_VER.MANUAL_ORDER_TIME_EXERCISE_OPTIONS && + manualOrderTime + ) { + return this.emitError( + "It does not support manual order time parameter in exerciseOptions.", + ErrorCode.UPDATE_TWS, + tickerId, + ); + } + + if (this.serverVersion < MIN_SERVER_VER.CUSTOMER_ACCOUNT) { + if (customerAccount) { + return this.emitError( + "It does not support customer account parameter in exerciseOptions.", + ErrorCode.UPDATE_TWS, + tickerId, + ); + } + } + + if (this.serverVersion < MIN_SERVER_VER.PROFESSIONAL_CUSTOMER) { + if (professionalCustomer) { + return this.emitError( + "It does not support professional customer parameter in exerciseOptions.", + ErrorCode.UPDATE_TWS, + tickerId, + ); + } + } + const tokens: unknown[] = [OUT_MSG_ID.EXERCISE_OPTIONS, version, tickerId]; // send contract fields @@ -654,6 +689,17 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { tokens.push(exerciseQuantity); tokens.push(account); tokens.push(override); + if ( + this.serverVersion >= MIN_SERVER_VER.MANUAL_ORDER_TIME_EXERCISE_OPTIONS + ) { + tokens.push(manualOrderTime); + } + if (this.serverVersion >= MIN_SERVER_VER.CUSTOMER_ACCOUNT) { + tokens.push(customerAccount); + } + if (this.serverVersion >= MIN_SERVER_VER.PROFESSIONAL_CUSTOMER) { + tokens.push(professionalCustomer); + } this.sendMsg(tokens); } @@ -1111,6 +1157,26 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { ); } + if (this.serverVersion < MIN_SERVER_VER.CUSTOMER_ACCOUNT) { + if (order.customerAccount) { + return this.emitError( + "It does not support customer account parameter", + ErrorCode.UPDATE_TWS, + id, + ); + } + } + + if (this.serverVersion < MIN_SERVER_VER.PROFESSIONAL_CUSTOMER) { + if (order.professionalCustomer) { + return this.emitError( + "It does not support professional customer parameter", + ErrorCode.UPDATE_TWS, + id, + ); + } + } + const version = this.serverVersion < MIN_SERVER_VER.NOT_HELD ? 27 : 45; // send place order msg @@ -1319,11 +1385,11 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { // Volatility orders had specific watermark price attribs in server version 26 const lower = - this.serverVersion === 26 && order.orderType === "VOL" + this.serverVersion === 26 && isVolOrder(order.orderType) ? undefined : order.stockRangeLower; const upper = - this.serverVersion === 26 && order.orderType === "VOL" + this.serverVersion === 26 && isVolOrder(order.orderType) ? undefined : order.stockRangeUpper; tokens.push(lower); @@ -1370,10 +1436,12 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { if (this.serverVersion === 26) { // Volatility orders had specific watermark price attribs in server version 26 - const lower = - order.orderType === "VOL" ? order.stockRangeLower : undefined; - const upper = - order.orderType === "VOL" ? order.stockRangeUpper : undefined; + const lower = isVolOrder(order.orderType) + ? order.stockRangeLower + : undefined; + const upper = isVolOrder(order.orderType) + ? order.stockRangeUpper + : undefined; tokens.push(nullifyMax(lower)); tokens.push(nullifyMax(upper)); } @@ -1642,15 +1710,13 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { if (this.serverVersion >= MIN_SERVER_VER.PEGBEST_PEGMID_OFFSETS) { let sendMidOffsets = false; - if (contract.exchange == "IBKRATS") tokens.push(order.minTradeQty); + if (contract.exchange == "IBKRATS") { + tokens.push(order.minTradeQty); + } if (isPegBestOrder(order.orderType)) { tokens.push(order.minCompeteSize); tokens.push(order.competeAgainstBestOffset); - if ( - order.competeAgainstBestOffset == - COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID - ) - sendMidOffsets = true; + if (isCompeteAgainstBestOffsetUpToMid(order)) sendMidOffsets = true; } else if (isPegMidOrder(order.orderType)) { sendMidOffsets = true; } @@ -1660,6 +1726,14 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { } } + if (this.serverVersion >= MIN_SERVER_VER.CUSTOMER_ACCOUNT) { + tokens.push(order.customerAccount); + } + + if (this.serverVersion >= MIN_SERVER_VER.PROFESSIONAL_CUSTOMER) { + tokens.push(order.professionalCustomer); + } + this.sendMsg(tokens); } @@ -1667,24 +1741,17 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { * Encode a REPLACE_FA message to an array of tokens. */ replaceFA(reqId: number, faDataType: FADataType, xml: string): void { - if (this.serverVersion < 13) { + if ( + this.serverVersion >= MIN_SERVER_VER.FA_PROFILE_DESUPPORT && + faDataType == FADataType.PROFILES + ) { return this.emitError( - "This feature is only available for versions of TWS >= 13.", + "FA Profile is not supported anymore, use FA Group instead.", ErrorCode.UPDATE_TWS, reqId, ); } - if (this.serverVersion >= MIN_SERVER_VER.FA_PROFILE_DESUPPORT) { - if (faDataType == FADataType.PROFILES) { - return this.emitError( - "FA Profile is not supported anymore, use FA Group instead.", - ErrorCode.UPDATE_TWS, - reqId, - ); - } - } - const version = 1; const tokens: unknown[] = [OUT_MSG_ID.REPLACE_FA, version, faDataType, xml]; @@ -2839,24 +2906,17 @@ function tagValuesToTokens(tagValues: TagValue[]): unknown[] { * Encode a REQ_FA message. */ requestFA(faDataType: FADataType): void { - if (this.serverVersion < 13) { + if ( + this.serverVersion >= MIN_SERVER_VER.FA_PROFILE_DESUPPORT && + faDataType == FADataType.PROFILES + ) { return this.emitError( - "This feature is only available for versions of TWS >= 13.", + "FA Profile is not supported anymore, use FA Group instead.", ErrorCode.UPDATE_TWS, -1, ); } - if (this.serverVersion >= MIN_SERVER_VER.FA_PROFILE_DESUPPORT) { - if (faDataType == FADataType.PROFILES) { - return this.emitError( - "FA Profile is not supported anymore, use FA Group instead.", - ErrorCode.UPDATE_TWS, - -1, - ); - } - } - const version = 1; this.sendMsg(OUT_MSG_ID.REQ_FA, version, faDataType); diff --git a/src/index.ts b/src/index.ts index b7c6a7bc..5507f298 100644 --- a/src/index.ts +++ b/src/index.ts @@ -63,7 +63,7 @@ export { TagValue } from "./api/data/container/tag-value"; // export enum types export { EventName } from "./api/data/enum/event-name"; -export { FADataType } from "./api/data/enum/fad-data-type"; +export { FADataType } from "./api/data/enum/fa-data-type"; export { LogLevel } from "./api/data/enum/log-level"; export { MIN_SERVER_VER } from "./api/data/enum/min-server-version"; export { OptionExerciseAction } from "./api/data/enum/option-exercise-action"; diff --git a/src/tests/unit/api-next-live/subscription-registry.test.ts b/src/tests/unit/api-next-live/subscription-registry.test.ts index aebb4fe9..f9225f54 100644 --- a/src/tests/unit/api-next-live/subscription-registry.test.ts +++ b/src/tests/unit/api-next-live/subscription-registry.test.ts @@ -42,9 +42,7 @@ describe("Subscription registry Tests", () => { }); it("Twice the same event callback bug", (done) => { - // Two active subscriptions for the same Event #193 - done("Please fix issue #193"); - return; + // Two active subscriptions for the same Event issue #193 subscription$ = api.getOpenOrders().subscribe({ next: (data) => { console.log(data); @@ -67,10 +65,5 @@ describe("Subscription registry Tests", () => { .catch((err: IBApiNextError) => { console.error(`getAllOpenOrders failed with '${err}'`); }); - - // awaitTimeout(15).then(() => { - // subscription$.unsubscribe(); - // done(); - // }); }); }); diff --git a/src/tests/unit/api/order/placeOrder.test.ts b/src/tests/unit/api/order/placeOrder.test.ts index 3b8e82fb..874421e4 100644 --- a/src/tests/unit/api/order/placeOrder.test.ts +++ b/src/tests/unit/api/order/placeOrder.test.ts @@ -280,4 +280,68 @@ describe("Place Orders", () => { ib.connect().reqOpenOrders(); }); + + test("Issue #203", (done) => { + let refId: number; + + const refContract: Contract = { + conId: 708846212, + exchange: "CME", + symbol: "MES", + }; + const refOrder: Order = { + action: OrderAction.BUY, + lmtPrice: 1, + totalQuantity: 1, + transmit: true, + orderType: OrderType.LMT, + account: "DU5784856", + tif: "DAY", + orderRef: "RS/3/9", + }; + + let isDone = false; + ib.once(EventName.nextValidId, (orderId: number) => { + refId = orderId; + ib.placeOrder(refId, refContract, refOrder); + }) + .on(EventName.openOrder, (orderId, contract, order, _orderState) => { + if (orderId == refId && !isDone) { + isDone = true; + expect(contract.symbol).toEqual(refContract.symbol); + expect(order.totalQuantity).toEqual(refOrder.totalQuantity); + done(); + } + }) + .on( + EventName.error, + ( + error: Error, + code: ErrorCode, + reqId: number, + _advancedOrderReject?: unknown, + ) => { + if (reqId === -1) { + logger.info(error.message); + } else { + const msg = `[${reqId}] ${error.message} (Error #${code})`; + if ( + error.message.includes("Warning:") || + error.message.includes("Order Message:") + ) { + logger.warn(msg); + } else if (code == ErrorCode.NO_TRADING_PERMISSIONS) { + // Ignore this error for tests + logger.warn(msg); + done(); + } else { + ib.disconnect(); + done(msg); + } + } + }, + ); + + ib.connect().reqOpenOrders(); + }); }); diff --git a/yarn.lock b/yarn.lock index 72fd7920..bb0e3002 100644 --- a/yarn.lock +++ b/yarn.lock @@ -412,7 +412,12 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/regexpp@^4.10.0": + version "4.10.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.1.tgz#361461e5cb3845d874e61731c11cfedd664d83a0" + integrity sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA== + +"@eslint-community/regexpp@^4.6.1": version "4.8.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== @@ -815,7 +820,7 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.9": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== @@ -832,7 +837,7 @@ dependencies: undici-types "~5.26.4" -"@types/semver@^7.3.12", "@types/semver@^7.5.0": +"@types/semver@^7.3.12": version "7.5.1" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367" integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg== @@ -861,22 +866,20 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz#dd71fc5c7ecec745ca26ece506d84d203a205c0e" - integrity sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "7.1.1" - "@typescript-eslint/type-utils" "7.1.1" - "@typescript-eslint/utils" "7.1.1" - "@typescript-eslint/visitor-keys" "7.1.1" - debug "^4.3.4" +"@typescript-eslint/eslint-plugin@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz#3cdeb5d44d051b21a9567535dd90702b2a42c6ff" + integrity sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/type-utils" "7.13.0" + "@typescript-eslint/utils" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" graphemer "^1.4.0" - ignore "^5.2.4" + ignore "^5.3.1" natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" + ts-api-utils "^1.3.0" "@typescript-eslint/experimental-utils@^5.0.0": version "5.62.0" @@ -885,15 +888,15 @@ dependencies: "@typescript-eslint/utils" "5.62.0" -"@typescript-eslint/parser@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.1.1.tgz#6a9d0a5c9ccdf5dbd3cb8c949728c64e24e07d1f" - integrity sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ== +"@typescript-eslint/parser@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.13.0.tgz#9489098d68d57ad392f507495f2b82ce8b8f0a6b" + integrity sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA== dependencies: - "@typescript-eslint/scope-manager" "7.1.1" - "@typescript-eslint/types" "7.1.1" - "@typescript-eslint/typescript-estree" "7.1.1" - "@typescript-eslint/visitor-keys" "7.1.1" + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/typescript-estree" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": @@ -904,33 +907,33 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" -"@typescript-eslint/scope-manager@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz#9e301803ff8e21a74f50c6f89a4baccad9a48f93" - integrity sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA== +"@typescript-eslint/scope-manager@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz#6927d6451537ce648c6af67a2327378d4cc18462" + integrity sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng== dependencies: - "@typescript-eslint/types" "7.1.1" - "@typescript-eslint/visitor-keys" "7.1.1" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" -"@typescript-eslint/type-utils@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz#aee820d5bedd39b83c18585a526cc520ddb7a226" - integrity sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g== +"@typescript-eslint/type-utils@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz#4587282b5227a23753ea8b233805ecafc3924c76" + integrity sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A== dependencies: - "@typescript-eslint/typescript-estree" "7.1.1" - "@typescript-eslint/utils" "7.1.1" + "@typescript-eslint/typescript-estree" "7.13.0" + "@typescript-eslint/utils" "7.13.0" debug "^4.3.4" - ts-api-utils "^1.0.1" + ts-api-utils "^1.3.0" "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== -"@typescript-eslint/types@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.1.1.tgz#ca33ba7cf58224fb46a84fea62593c2c53cd795f" - integrity sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q== +"@typescript-eslint/types@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.13.0.tgz#0cca95edf1f1fdb0cfe1bb875e121b49617477c5" + integrity sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA== "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" @@ -945,21 +948,21 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz#09c54af0151a1b05d0875c0fc7fe2ec7a2476ece" - integrity sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw== +"@typescript-eslint/typescript-estree@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz#4cc24fc155088ebf3b3adbad62c7e60f72c6de1c" + integrity sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw== dependencies: - "@typescript-eslint/types" "7.1.1" - "@typescript-eslint/visitor-keys" "7.1.1" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/visitor-keys" "7.13.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.10.0": +"@typescript-eslint/utils@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== @@ -973,18 +976,15 @@ eslint-scope "^5.1.1" semver "^7.3.7" -"@typescript-eslint/utils@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.1.1.tgz#bdeeb789eee4af5d3fb5400a69566d4dbf97ff3b" - integrity sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg== +"@typescript-eslint/utils@7.13.0", "@typescript-eslint/utils@^6.0.0 || ^7.0.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.13.0.tgz#f84e7e8aeceae945a9a3f40d077fd95915308004" + integrity sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "7.1.1" - "@typescript-eslint/types" "7.1.1" - "@typescript-eslint/typescript-estree" "7.1.1" - semver "^7.5.4" + "@typescript-eslint/scope-manager" "7.13.0" + "@typescript-eslint/types" "7.13.0" + "@typescript-eslint/typescript-estree" "7.13.0" "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" @@ -994,13 +994,13 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz#e6538a58c9b157f03bcbb29e3b6a92fe39a6ab0d" - integrity sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ== +"@typescript-eslint/visitor-keys@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz#2eb7ce8eb38c2b0d4a494d1fe1908e7071a1a353" + integrity sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw== dependencies: - "@typescript-eslint/types" "7.1.1" - eslint-visitor-keys "^3.4.1" + "@typescript-eslint/types" "7.13.0" + eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": version "1.2.0" @@ -1496,12 +1496,12 @@ eslint-etc@^5.1.0: tsutils "^3.17.1" tsutils-etc "^1.4.1" -eslint-plugin-jest@^27.9.0: - version "27.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz#7c98a33605e1d8b8442ace092b60e9919730000b" - integrity sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug== +eslint-plugin-jest@^28.6.0: + version "28.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.6.0.tgz#8410588d60bcafa68a91b6ec272e4a415502302a" + integrity sha512-YG28E1/MIKwnz+e2H7VwYPzHUYU4aMa19w0yGcwXnnmJH6EfgHahTJ2un3IyraUxNfnz/KUhJAFXNNwWPo12tg== dependencies: - "@typescript-eslint/utils" "^5.10.0" + "@typescript-eslint/utils" "^6.0.0 || ^7.0.0" eslint-plugin-rxjs@^5.0.3: version "5.0.3" @@ -1896,11 +1896,16 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -ignore@^5.2.0, ignore@^5.2.4: +ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2642,19 +2647,26 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@9.0.3, minimatch@^9.0.3: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +minimatch@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" mkdirp@^1.0.4: version "1.0.4" @@ -2974,6 +2986,11 @@ semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3132,15 +3149,15 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -ts-api-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.2.tgz#7c094f753b6705ee4faee25c3c684ade52d66d99" - integrity sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -ts-jest@^29.1.4: - version "29.1.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.4.tgz#26f8a55ce31e4d2ef7a1fd47dc7fa127e92793ef" - integrity sha512-YiHwDhSvCiItoAgsKtoLFCuakDzDsJ1DLDnSouTaTmdOcOwIkSzbLXduaQ6M5DRVhuZC/NYaaZ/mtHbWMv/S6Q== +ts-jest@^29.1.5: + version "29.1.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.5.tgz#d6c0471cc78bffa2cb4664a0a6741ef36cfe8f69" + integrity sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg== dependencies: bs-logger "0.x" fast-json-stable-stringify "2.x" From ffd36db8e969e0cc4a5aed1dfbf5b6ca76f00b8d Mon Sep 17 00:00:00 2001 From: Ronan-Yann Lorin Date: Tue, 18 Jun 2024 08:37:12 +0200 Subject: [PATCH 3/3] ReadMe updated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dfec4794..ad175da9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ -`@stoqey/ib` is an [Interactive Brokers](http://interactivebrokers.com/) TWS (or IB Gateway) Typescript API client library for [Node.js](http://nodejs.org/). It is a direct port of Interactive Brokers' Java Client Version 10.25 ("latest") from Sept 7 2023. +`@stoqey/ib` is an [Interactive Brokers](http://interactivebrokers.com/) TWS (or IB Gateway) Typescript API client library for [Node.js](http://nodejs.org/). It is a port of Interactive Brokers' Java Client Version 10.29.01 ("latest") from June 18th, 2024. Refer to the [Trader Workstation API](https://interactivebrokers.github.io/tws-api/) for the official documentation and the C#/Java/VB/C++/Python client.