From 6f1593c5f15780289f971ba49038988bd52bbf47 Mon Sep 17 00:00:00 2001 From: Ronan-Yann Lorin Date: Fri, 22 Sep 2023 08:04:53 +0200 Subject: [PATCH] Update Java reference API --- ref/client/Bar.java | 10 +- ref/client/Builder.java | 38 +- ref/client/Contract.java | 24 +- ref/client/ContractDescription.java | 2 + ref/client/ContractDetails.java | 30 +- ref/client/Decimal.java | 174 +++++ ref/client/DefaultEWrapper.java | 58 +- ref/client/EClient.java | 894 ++++++++++++++++++------- ref/client/EClientErrors.java | 6 + ref/client/EClientException.java | 23 + ref/client/EClientSocket.java | 11 +- ref/client/EClientSocketSSL.java | 92 --- ref/client/EDecoder.java | 235 +++++-- ref/client/EOrderDecoder.java | 49 +- ref/client/EReader.java | 14 +- ref/client/EWrapper.java | 31 +- ref/client/EWrapperMsgGenerator.java | 262 +++++--- ref/client/Execution.java | 20 +- ref/client/HistogramEntry.java | 33 +- ref/client/HistoricalSession.java | 28 + ref/client/HistoricalTick.java | 6 +- ref/client/HistoricalTickBidAsk.java | 10 +- ref/client/HistoricalTickLast.java | 6 +- ref/client/MarginCondition.java | 2 +- ref/client/Order.java | 77 ++- ref/client/OrderType.java | 1 + ref/client/PercentChangeCondition.java | 2 +- ref/client/PriceCondition.java | 2 +- ref/client/TickByTick.java | 16 +- ref/client/TickType.java | 13 + ref/client/Types.java | 14 +- ref/client/Util.java | 24 +- ref/client/VolumeCondition.java | 2 +- ref/client/WshEventData.java | 50 ++ ref/contracts/FutContract.java | 4 +- ref/controller/AccountSummaryTag.java | 2 +- ref/controller/ApiController.java | 265 ++++++-- ref/controller/Bar.java | 31 +- ref/controller/Formats.java | 10 +- ref/controller/LocationCode.java | 5 - ref/controller/Position.java | 7 +- 41 files changed, 1888 insertions(+), 695 deletions(-) create mode 100644 ref/client/Decimal.java create mode 100644 ref/client/EClientException.java delete mode 100644 ref/client/EClientSocketSSL.java create mode 100644 ref/client/HistoricalSession.java create mode 100644 ref/client/WshEventData.java diff --git a/ref/client/Bar.java b/ref/client/Bar.java index 17b9fc0c..a16e412a 100644 --- a/ref/client/Bar.java +++ b/ref/client/Bar.java @@ -10,11 +10,11 @@ public class Bar { private double m_high; private double m_low; private double m_close; - private long m_volume; + private Decimal m_volume; private int m_count; - private double m_wap; + private Decimal m_wap; - public Bar(String time, double open, double high, double low, double close, long volume, int count, double wap) { + public Bar(String time, double open, double high, double low, double close, Decimal volume, int count, Decimal wap) { this.m_time = time; this.m_open = open; this.m_high = high; @@ -45,7 +45,7 @@ public double close() { return m_close; } - public long volume() { + public Decimal volume() { return m_volume; } @@ -53,7 +53,7 @@ public int count() { return m_count; } - public double wap() { + public Decimal wap() { return m_wap; } diff --git a/ref/client/Builder.java b/ref/client/Builder.java index 44c07525..27c0a6c1 100644 --- a/ref/client/Builder.java +++ b/ref/client/Builder.java @@ -24,31 +24,35 @@ public Builder( int size ) { m_sb = new ByteBuffer( size ); } - public void send(int a) { + public void send(int a) throws EClientException { send( String.valueOf(a) ); } - public void sendMax(int a) { + public void sendMax(int a) throws EClientException { send( a == Integer.MAX_VALUE ? "" : String.valueOf( a) ); } - public void send(double a) { + public void send(double a) throws EClientException { send( String.valueOf( a) ); } - public void sendMax(double a) { + public void sendMax(double a) throws EClientException { send( a == Double.MAX_VALUE ? "" : String.valueOf( a) ); } - public void send(Boolean a) { + public void send(Boolean a) throws EClientException { sendMax(a == null ? Integer.MAX_VALUE : a ? 1 : 0); } - public void send( IApiEnum a) { + public void send( IApiEnum a) throws EClientException { send( a == null ? null : a.getApiString() ); } - public void send( String a) { + public void send( String a) throws EClientException { + if (a != null && !isAsciiPrintable(a)) { + throw new EClientException(EClientErrors.INVALID_SYMBOL, a); + } + if (a != null) { byte[] buffer = a.getBytes(StandardCharsets.UTF_8); m_sb.write( buffer, 0, buffer.length ); @@ -62,14 +66,14 @@ public void send( byte[] bytes ) { } } - public void send(List miscOptions) { + public void send(List miscOptions) throws EClientException { String miscOptionsString = Optional.ofNullable(miscOptions).orElse(new ArrayList()).stream(). map(option -> option.m_tag + "=" + option.m_value + ";").reduce("", (sum, option) -> sum + option); send(miscOptionsString); } - public void send(Contract contract) { + public void send(Contract contract) throws EClientException { send(contract.conid()); send(contract.symbol()); send(contract.getSecType()); @@ -106,6 +110,22 @@ static void intToBytes(int val, byte b[], int position) { b[position+2] = (byte)(0xff & (val >> 8)); b[position+3] = (byte)(0xff & val); } + + private static boolean isAsciiPrintable(String str) { + if (str == null) { + return false; + } + for (int i = 0; i < str.length(); i++) { + if (isAsciiPrintable(str.charAt(i)) == false) { + return false; + } + } + return true; + } + + private static boolean isAsciiPrintable(char ch) { + return ch >= 32 && ch < 127; + } /** inner class: ByteBuffer - storage for bytes and direct access to buffer. */ private static class ByteBuffer extends ByteArrayOutputStream { diff --git a/ref/client/Contract.java b/ref/client/Contract.java index 9bc3efdd..9e60e097 100644 --- a/ref/client/Contract.java +++ b/ref/client/Contract.java @@ -25,6 +25,8 @@ public class Contract implements Cloneable { private String m_tradingClass; private String m_secIdType; // CUSIP;SEDOL;ISIN;RIC private String m_secId; + private String m_description; + private String m_issuerId; private DeltaNeutralContract m_deltaNeutralContract; private boolean m_includeExpired; // can not be set to true for orders @@ -54,6 +56,8 @@ public class Contract implements Cloneable { public DeltaNeutralContract deltaNeutralContract() { return m_deltaNeutralContract; } public List comboLegs() { return m_comboLegs; } public String comboLegsDescrip() { return m_comboLegsDescrip; } + public String description() { return m_description; } + public String issuerId() { return m_issuerId; } // Set public void conid(int v) { m_conid = v; } @@ -77,6 +81,8 @@ public class Contract implements Cloneable { public void includeExpired(boolean v) { m_includeExpired = v; } public void comboLegs(List v) { m_comboLegs = v; } public void comboLegsDescrip(String v) { m_comboLegsDescrip = v; } + public void description(String v) { m_description = v; } + public void issuerId(String v) { m_issuerId = v; } public Contract() { m_conid = 0; @@ -105,7 +111,7 @@ public Contract(int p_conId, String p_symbol, String p_secType, String p_lastTra 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, - String p_secIdType, String p_secId) { + String p_secIdType, String p_secId, String p_description, String p_issuerId) { m_conid = p_conId; m_symbol = p_symbol; m_secType = p_secType; @@ -121,7 +127,9 @@ public Contract(int p_conId, String p_symbol, String p_secType, String p_lastTra m_comboLegs = p_comboLegs; m_primaryExch = p_primaryExch; m_secIdType = p_secIdType; - m_secId = p_secId ; + m_secId = p_secId; + m_description = p_description; + m_issuerId = p_issuerId; } @Override @@ -187,6 +195,14 @@ public boolean equals(Object p_other) { return false; } } + + if (Util.StringCompare(m_description, l_theOther.m_description) != 0) { + return false; + } + if (Util.StringCompare(m_issuerId, l_theOther.m_issuerId) != 0) { + return false; + } + return true; } @@ -201,7 +217,7 @@ public int hashCode() { } /** Returns a text description that can be used for display. */ - public String description() { + public String textDescription() { StringBuilder sb = new StringBuilder(); if (isCombo() ) { @@ -264,6 +280,8 @@ public boolean isCombo() { add( sb, "primaryExch", m_primaryExch); add( sb, "secIdType", m_secIdType); add( sb, "secId", m_secId); + add( sb, "description", m_description); + add( sb, "issuerId", m_issuerId); return sb.toString(); } diff --git a/ref/client/ContractDescription.java b/ref/client/ContractDescription.java index a09a1aeb..1ed6b517 100644 --- a/ref/client/ContractDescription.java +++ b/ref/client/ContractDescription.java @@ -51,6 +51,8 @@ public String toString() { + "secType: " + m_contract.secType().toString() + "\n" + "primaryExch: " + m_contract.primaryExch() + "\n" + "currency: " + m_contract.currency() + "\n" + + "description: " + m_contract.description() + "\n" + + "issuerId: " + m_contract.issuerId() + "\n" + "derivativeSecTypes: " + Arrays.toString(m_derivativeSecTypes) + "\n"; } } diff --git a/ref/client/ContractDetails.java b/ref/client/ContractDetails.java index b9100c66..f269677a 100644 --- a/ref/client/ContractDetails.java +++ b/ref/client/ContractDetails.java @@ -23,7 +23,6 @@ public class ContractDetails { private String m_liquidHours; private String m_evRule; private double m_evMultiplier; - private int m_mdSizeMultiplier; private List m_secIdList; // CUSIP/ISIN/etc. private int m_aggGroup; private String m_underSymbol; @@ -31,6 +30,10 @@ public class ContractDetails { private String m_marketRuleIds; private String m_realExpirationDate; private String m_lastTradeTime; + private String m_stockType; // COMMON, ETF, ADR etc. + private Decimal m_minSize; + private Decimal m_sizeIncrement; + private Decimal m_suggestedSizeIncrement; // BOND values private String m_cusip; @@ -68,7 +71,6 @@ public class ContractDetails { public String liquidHours() { return m_liquidHours; } public String evRule() { return m_evRule; } public double evMultiplier() { return m_evMultiplier; } - public int mdSizeMultiplier() { return m_mdSizeMultiplier; } public List secIdList() { return m_secIdList; } public int aggGroup() { return m_aggGroup; } public String underSymbol() { return m_underSymbol; } @@ -76,6 +78,10 @@ public class ContractDetails { public String marketRuleIds() { return m_marketRuleIds; } public String realExpirationDate() { return m_realExpirationDate; } public String lastTradeTime() { return m_lastTradeTime; } + public String stockType() { return m_stockType; } + public Decimal minSize() { return m_minSize; } + public Decimal sizeIncrement() { return m_sizeIncrement; } + public Decimal suggestedSizeIncrement() { return m_suggestedSizeIncrement; } public String cusip() { return m_cusip; } public String ratings() { return m_ratings; } @@ -111,7 +117,6 @@ public class ContractDetails { public void liquidHours(String liquidHours) { m_liquidHours = liquidHours; } public void evRule(String evRule) { m_evRule = evRule; } public void evMultiplier(double evMultiplier) { m_evMultiplier = evMultiplier; } - public void mdSizeMultiplier(int mdSizeMultiplier) { m_mdSizeMultiplier = mdSizeMultiplier; } public void secIdList(List secIdList) { m_secIdList = secIdList; } public void aggGroup(int aggGroup) { m_aggGroup = aggGroup; } public void underSymbol(String underSymbol) { m_underSymbol = underSymbol; } @@ -119,6 +124,10 @@ public class ContractDetails { public void marketRuleIds(String marketRuleIds) { m_marketRuleIds = marketRuleIds; } public void realExpirationDate(String realExpirationDate) { m_realExpirationDate = realExpirationDate; } public void lastTradeTime(String lastTradeTime) { m_lastTradeTime = lastTradeTime; } + public void stockType(String stockType) { m_stockType = stockType; } + public void minSize(Decimal minSize) { m_minSize = minSize; } + public void sizeIncrement(Decimal sizeIncrement) { m_sizeIncrement = sizeIncrement; } + public void suggestedSizeIncrement(Decimal suggestedSizeIncrement) { m_suggestedSizeIncrement = suggestedSizeIncrement; } public void cusip(String cusip) { m_cusip = cusip; } public void ratings(String ratings) { m_ratings = ratings; } @@ -147,8 +156,9 @@ 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_mdSizeMultiplier, int p_aggGroup, - String p_underSymbol, String p_underSecType, String p_marketRuleIds, String p_realExpirationDate, String p_lastTradeTime) { + 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; @@ -165,13 +175,16 @@ public ContractDetails( Contract p_contract, String p_marketName, m_liquidHours = p_liquidHours; m_evRule = p_evRule; m_evMultiplier = p_evMultiplier; - m_mdSizeMultiplier = p_mdSizeMultiplier; 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() { @@ -193,13 +206,16 @@ public ContractDetails( Contract p_contract, String p_marketName, add( sb, "liquidHours", m_liquidHours); add( sb, "evRule", m_evRule); add( sb, "evMultiplier", m_evMultiplier); - add( sb, "mdSizeMultiplier", m_mdSizeMultiplier); add( sb, "aggGroup", m_aggGroup); add( sb, "underSymbol", m_underSymbol); add( sb, "underSecType", m_underSecType); add( sb, "marketRuleIds", m_marketRuleIds); add( sb, "realExpirationDate", m_realExpirationDate); add( sb, "lastTradeTime", m_lastTradeTime); + add( sb, "stockType", m_stockType); + add( sb, "minSize", m_minSize); + add( sb, "sizeIncrement", m_sizeIncrement); + add( sb, "suggestedSizeIncrement", m_suggestedSizeIncrement); add( sb, "cusip", m_cusip); add( sb, "ratings", m_ratings); diff --git a/ref/client/Decimal.java b/ref/client/Decimal.java new file mode 100644 index 00000000..6372390d --- /dev/null +++ b/ref/client/Decimal.java @@ -0,0 +1,174 @@ +/* Copyright (C) 2021 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.math.BigDecimal; +import java.math.MathContext; +import java.text.DecimalFormat; + +public class Decimal implements Comparable{ + + // constants + private static final String NAN_STRING = Double.toString(Double.NaN); + public static final MathContext MATH_CONTEXT = MathContext.DECIMAL64; + public static final Decimal ZERO = new Decimal( BigDecimal.ZERO ); + public static final Decimal ONE = new Decimal( BigDecimal.ONE ); + public static final Decimal MINUS_ONE = ONE.negate(); + public static final Decimal INVALID = new Decimal(BigDecimal.valueOf(Long.MIN_VALUE)); // maybe would better to choose 0 as invalid's value, as in at least half of the operations invalid behaves 0 like + public static final Decimal NaN = new Decimal(BigDecimal.valueOf(Long.MIN_VALUE)) { // we need NaN for bar replacement at the moment, if it can be solved differently remove it + @Override public long longValue() { return Long.MAX_VALUE; } + @Override public String toString() { return NAN_STRING; } + }; + public static final Decimal ONE_HUNDRED = new Decimal( BigDecimal.valueOf(100) ); + + // vars + private final BigDecimal m_value; + + // gets + @Override public int hashCode() { return m_value.hashCode(); } + public BigDecimal value() { return m_value; } + public boolean isZero() { return isZero(m_value); } + private static boolean isZero(final BigDecimal d) { return d == BigDecimal.ZERO || d.signum() == 0; } + public boolean isValid() { return this != INVALID && this != NaN; } + + public static Decimal get(final BigDecimal v) { + Decimal result; + if (v == null) { + result = INVALID; + } else if (isZero(v)) { + result = ZERO; + } else { + result = new Decimal(v); + } + return result; + } + + public static final Decimal get(final double v) { + Decimal result; + if (v == Double.MAX_VALUE) { + result = INVALID; + } else if (v == 0) { + result = ZERO; + } else if (Double.isNaN(v) || Double.isInfinite(v)) { + result = NaN; + } else { + DecimalFormat df = new DecimalFormat("#"); + df.setMaximumFractionDigits(16); + result = Decimal.parse(df.format(v)); + } + return result; + } + + public static Decimal get(final long v) { + Decimal result; + if (v == Long.MAX_VALUE) { + result = INVALID; + } else if (v == 0) { + result = ZERO; + } else { + result = new Decimal(v); + } + return result; + } + + private Decimal( double value ) { + BigDecimal bd = new BigDecimal( value, MATH_CONTEXT ); + m_value = bd.setScale( 16, MATH_CONTEXT.getRoundingMode() ); + } + + private Decimal( long value ) { + BigDecimal bd = new BigDecimal( value, MATH_CONTEXT ); + m_value = bd.setScale( 16, MATH_CONTEXT.getRoundingMode() ); + } + + private Decimal( BigDecimal value ) { + m_value = value.setScale( 16, MATH_CONTEXT.getRoundingMode() ); + } + + public static boolean isValidNotZeroValue(Decimal value) { return isValid( value ) && !value.isZero(); } + public static boolean isValid(Decimal value) { return value != null && value.isValid(); } + + public static Decimal parse( String text ) { + if( Util.StringIsEmpty(text) ) { + return null; + } else if( NAN_STRING.equals(text) ) { + return NaN; + } else { + try { + text = text.trim().replaceAll(",", ""); + BigDecimal decimal = new BigDecimal( text.toCharArray(), 0, text.length(), MATH_CONTEXT ); + return new Decimal( decimal ); + } catch( NumberFormatException ex ) { + // ignore + } + } + return null; + } + + public Decimal negate() { + return isValid() ? get(m_value.negate()) : this; + } + + public Decimal add(final Decimal another) { + return !isValid( another) || another.isZero() + ? this + : isZero() || !isValid() + ? another + : get(m_value.add(another.value())); + } + + public Decimal divide(final Decimal another) { + Decimal result; + if (Decimal.ONE.equals(another) || isZero()) { + result = this; + } else { + result = INVALID; + if (isValid() && isValid(another)) { + try { // try is rather expensive, so we narrow the scope + result = get(m_value.divide(another.value(), MATH_CONTEXT)); + } catch( ArithmeticException ex ) { + + } + } + } + return result; + } + + public Decimal multiply(final Decimal another) { + return another == null ? null + : isZero() || another.isZero() ? ZERO + : isValid() && another.isValid() + ? ONE.equals(another) ? this + : get(m_value.multiply(another.value())) + : INVALID; + } + + @Override public boolean equals( Object another ) { + return another instanceof Decimal && compareTo((Decimal)another) == 0; + } + + @Override public int compareTo( final Decimal another ) { + return another == this + ? 0 + : another == null + ? 1 + : isValid() + ? another.isValid() + ? m_value.compareTo(another.m_value) + : 1 + : another.isValid() ? -1 : 0; + } + + public static int compare(Decimal value1, Decimal value2) { + return value1.value().compareTo(value2.value()); + } + + @Override public String toString() { + return isValid() ? m_value.stripTrailingZeros().toPlainString() : ""; + } + + public long longValue() { + return isValid() ? m_value.longValue() : Long.MAX_VALUE; + } +} diff --git a/ref/client/DefaultEWrapper.java b/ref/client/DefaultEWrapper.java index a3fa951d..c53eb52e 100644 --- a/ref/client/DefaultEWrapper.java +++ b/ref/client/DefaultEWrapper.java @@ -18,13 +18,13 @@ public void tickPrice(int tickerId, int field, double price, } @Override - public void tickSize(int tickerId, int field, int size) { + public void tickSize(int tickerId, int field, Decimal size) { // TODO Auto-generated method stub } @Override - public void tickOptionComputation(int tickerId, int field, + public void tickOptionComputation(int tickerId, int field, int tickAttrib, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { @@ -53,8 +53,8 @@ public void tickEFP(int tickerId, int tickType, double basisPoints, } @Override - public void orderStatus(int orderId, String status, double filled, - double remaining, double avgFillPrice, int permId, int parentId, + public void orderStatus(int orderId, String status, Decimal filled, + Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice) { // TODO Auto-generated method stub @@ -81,7 +81,7 @@ public void updateAccountValue(String key, String value, String currency, } @Override - public void updatePortfolio(Contract contract, double position, + public void updatePortfolio(Contract contract, Decimal position, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String accountName) { // TODO Auto-generated method stub @@ -138,14 +138,14 @@ public void execDetailsEnd(int reqId) { @Override public void updateMktDepth(int tickerId, int position, int operation, - int side, double price, int size) { + int side, double price, Decimal size) { // TODO Auto-generated method stub } @Override public void updateMktDepthL2(int tickerId, int position, - String marketMaker, int operation, int side, double price, int size, boolean isSmartDepth) { + String marketMaker, int operation, int side, double price, Decimal size, boolean isSmartDepth) { // TODO Auto-generated method stub } @@ -197,7 +197,7 @@ public void scannerDataEnd(int reqId) { @Override public void realtimeBar(int reqId, long time, double open, double high, - double low, double close, long volume, double wap, int count) { + double low, double close, Decimal volume, Decimal wap, int count) { // TODO Auto-generated method stub } @@ -239,7 +239,7 @@ public void commissionReport(CommissionReport commissionReport) { } @Override - public void position(String account, Contract contract, double pos, + public void position(String account, Contract contract, Decimal pos, double avgCost) { // TODO Auto-generated method stub @@ -313,7 +313,7 @@ public void error(String str) { } @Override - public void error(int id, int errorCode, String errorMsg) { + public void error(int id, int errorCode, String errorMsg, String advancedOrderRejectJson) { // TODO Auto-generated method stub } @@ -331,7 +331,7 @@ public void connectAck() { } @Override - public void positionMulti( int reqId, String account, String modelCode, Contract contract, double pos, double avgCost) { + public void positionMulti( int reqId, String account, String modelCode, Contract contract, Decimal pos, double avgCost) { // TODO Auto-generated method stub } @@ -483,7 +483,7 @@ public void marketRule(int marketRuleId, PriceIncrement[] priceIncrements) { } @Override - public void pnlSingle(int reqId, int pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { + public void pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { // TODO Auto-generated method stub } @@ -508,13 +508,13 @@ public void historicalTicksLast(int reqId, List ticks, boole } @Override - public void tickByTickAllLast(int reqId, int tickType, long time, double price, int size, TickAttribLast tickAttribLast, + public void tickByTickAllLast(int reqId, int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions) { // TODO Auto-generated method stub } @Override - public void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, int bidSize, int askSize, + public void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, Decimal bidSize, Decimal askSize, TickAttribBidAsk tickAttribBidAsk) { // TODO Auto-generated method stub } @@ -538,4 +538,34 @@ public void completedOrder(Contract contract, Order order, OrderState orderState public void completedOrdersEnd() { // TODO Auto-generated method stub } + + @Override + public void replaceFAEnd(int reqId, String text) { + // TODO Auto-generated method stub + } + + @Override + public void wshMetaData(int reqId, String dataJson) { + // TODO Auto-generated method stub + + } + + @Override + public void wshEventData(int reqId, String dataJson) { + // TODO Auto-generated method stub + + } + + @Override + public void historicalSchedule(int reqId, String startDateTime, String endDateTime, String timeZone, + List sessions) { + // TODO Auto-generated method stub + + } + + @Override + public void userInfo(int reqId, String whiteBrandingId) { + // TODO Auto-generated method stub + + } } diff --git a/ref/client/EClient.java b/ref/client/EClient.java index 70ce99dd..c3f574fc 100644 --- a/ref/client/EClient.java +++ b/ref/client/EClient.java @@ -8,6 +8,7 @@ import java.util.List; import com.ib.client.Types.SecType; +import com.ib.client.Types.WhatToShow; public abstract class EClient { @@ -193,6 +194,11 @@ public static String faMsgTypeName(int faDataType) { private static final int REQ_TICK_BY_TICK_DATA = 97; private static final int CANCEL_TICK_BY_TICK_DATA = 98; private static final int REQ_COMPLETED_ORDERS = 99; + private static final int REQ_WSH_META_DATA = 100; + private static final int CANCEL_WSH_META_DATA = 101; + private static final int REQ_WSH_EVENT_DATA = 102; + private static final int CANCEL_WSH_EVENT_DATA = 103; + private static final int REQ_USER_INFO = 104; private static final int MIN_SERVER_VER_REAL_TIME_BARS = 34; private static final int MIN_SERVER_VER_SCALE_ORDERS = 35; @@ -287,9 +293,34 @@ public static String faMsgTypeName(int faDataType) { protected static final int MIN_SERVER_VER_MKT_DEPTH_PRIM_EXCHANGE = 149; protected static final int MIN_SERVER_VER_REQ_COMPLETED_ORDERS = 150; protected static final int MIN_SERVER_VER_PRICE_MGMT_ALGO = 151; + protected static final int MIN_SERVER_VER_STOCK_TYPE = 152; + protected static final int MIN_SERVER_VER_ENCODE_MSG_ASCII7 = 153; + protected static final int MIN_SERVER_VER_SEND_ALL_FAMILY_CODES = 154; + protected static final int MIN_SERVER_VER_NO_DEFAULT_OPEN_CLOSE = 155; + protected static final int MIN_SERVER_VER_PRICE_BASED_VOLATILITY = 156; + protected static final int MIN_SERVER_VER_REPLACE_FA_END = 157; + protected static final int MIN_SERVER_VER_DURATION = 158; + protected static final int MIN_SERVER_VER_MARKET_DATA_IN_SHARES = 159; + protected static final int MIN_SERVER_VER_POST_TO_ATS = 160; + protected static final int MIN_SERVER_VER_WSHE_CALENDAR = 161; + protected static final int MIN_SERVER_VER_AUTO_CANCEL_PARENT = 162; + protected static final int MIN_SERVER_VER_FRACTIONAL_SIZE_SUPPORT = 163; + protected static final int MIN_SERVER_VER_SIZE_RULES = 164; + protected static final int MIN_SERVER_VER_HISTORICAL_SCHEDULE = 165; + protected static final int MIN_SERVER_VER_ADVANCED_ORDER_REJECT = 166; + protected static final int MIN_SERVER_VER_USER_INFO = 167; + protected static final int MIN_SERVER_VER_CRYPTO_AGGREGATED_TRADES = 168; + protected static final int MIN_SERVER_VER_MANUAL_ORDER_TIME = 169; + protected static final int MIN_SERVER_VER_PEGBEST_PEGMID_OFFSETS = 170; + protected static final int MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS = 171; + protected static final int MIN_SERVER_VER_IPO_PRICES = 172; + protected static final int MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS_DATE = 173; + 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; public static final int MIN_VERSION = 100; // envelope encoding, applicable to useV100Plus mode only - public static final int MAX_VERSION = MIN_SERVER_VER_PRICE_MGMT_ALGO; // ditto + public static final int MAX_VERSION = MIN_SERVER_VER_BOND_ISSUERID; // ditto protected EReaderSignal m_signal; protected EWrapper m_eWrapper; // msg handler @@ -342,7 +373,7 @@ protected void sendConnectRequest() throws IOException { public void disableUseV100Plus() { if( isConnected() ) { m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.ALREADY_CONNECTED.code(), - EClientErrors.ALREADY_CONNECTED.msg()); + EClientErrors.ALREADY_CONNECTED.msg(), null); return; } @@ -353,7 +384,7 @@ public void disableUseV100Plus() { public void setConnectOptions(String options) { if( isConnected() ) { m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.ALREADY_CONNECTED.code(), - EClientErrors.ALREADY_CONNECTED.msg()); + EClientErrors.ALREADY_CONNECTED.msg(), null); return; } @@ -362,13 +393,13 @@ public void setConnectOptions(String options) { protected void connectionError() { m_eWrapper.error( EClientErrors.NO_VALID_ID, EClientErrors.CONNECT_FAIL.code(), - EClientErrors.CONNECT_FAIL.msg()); + EClientErrors.CONNECT_FAIL.msg(), null); } protected String checkConnected(String host) { if( isConnected()) { m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.ALREADY_CONNECTED.code(), - EClientErrors.ALREADY_CONNECTED.msg()); + EClientErrors.ALREADY_CONNECTED.msg(), null); return null; } if( IsEmpty( host) ) { @@ -400,9 +431,11 @@ public synchronized void startAPI() { } closeAndSend(b); } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, - EClientErrors.FAIL_SEND_STARTAPI, e.toString()); + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } + catch(Exception e) { + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_STARTAPI, e.toString()); close(); } } @@ -544,8 +577,11 @@ public synchronized void reqScannerSubscription(int tickerId, closeAndSend(b); } - catch( Exception e) { - error( tickerId, EClientErrors.FAIL_SEND_REQSCANNER, e.toString()); + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch(Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQSCANNER, e.toString()); close(); } } @@ -688,8 +724,11 @@ public synchronized void reqMktData(int tickerId, Contract contract, closeAndSend(b); } - catch( Exception e) { - error( tickerId, EClientErrors.FAIL_SEND_REQMKT, e.toString()); + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch(Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQMKT, e.toString()); close(); } } @@ -784,6 +823,14 @@ public synchronized void reqHistoricalData( int tickerId, Contract contract, } } + if (m_serverVersion < MIN_SERVER_VER_HISTORICAL_SCHEDULE) { + if (!IsEmpty(whatToShow) && whatToShow.equalsIgnoreCase(WhatToShow.SCHEDULE.name())) { + error(tickerId, EClientErrors.UPDATE_TWS, + " It does not support requesting of historical schedule."); + return; + } + } + Builder b = prepareBuffer(); b.send(REQ_HISTORICAL_DATA); @@ -862,9 +909,12 @@ public synchronized void reqHistoricalData( int tickerId, Contract contract, closeAndSend(b); } - catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, e.toString()); - close(); + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch(Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, e.toString()); + close(); } } @@ -895,9 +945,12 @@ public synchronized void reqHeadTimestamp(int tickerId, Contract contract, closeAndSend(b); } + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_REQHEADTIMESTAMP, e.toString()); - close(); + error(tickerId, EClientErrors.FAIL_SEND_REQHEADTIMESTAMP, e.toString()); + close(); } } @@ -990,8 +1043,11 @@ public synchronized void reqRealTimeBars(int tickerId, Contract contract, int ba closeAndSend(b); } - catch( Exception e) { - error( tickerId, EClientErrors.FAIL_SEND_REQRTBARS, e.toString()); + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch(Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQRTBARS, e.toString()); close(); } } @@ -1032,6 +1088,14 @@ public synchronized void reqContractDetails(int reqId, Contract contract) { return; } } + + if (m_serverVersion < MIN_SERVER_VER_BOND_ISSUERID) { + if (!IsEmpty(contract.issuerId())) { + error(reqId, EClientErrors.UPDATE_TWS, + " It does not support issuerId parameter in reqContractDetails."); + return; + } + } final int VERSION = 8; @@ -1085,10 +1149,16 @@ else if (m_serverVersion >= MIN_SERVER_VER_LINKING) { b.send( contract.getSecIdType()); b.send( contract.secId()); } + if (m_serverVersion >= MIN_SERVER_VER_BOND_ISSUERID) { + b.send(contract.issuerId()); + } closeAndSend(b); } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQCONTRACT, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQCONTRACT, e.toString()); close(); } } @@ -1179,8 +1249,11 @@ public synchronized void reqMktDepth( int tickerId, Contract contract, int numRo closeAndSend(b); } - catch( Exception e) { - error( tickerId, EClientErrors.FAIL_SEND_REQMKTDEPTH, e.toString()); + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch(Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQMKTDEPTH, e.toString()); close(); } } @@ -1265,53 +1338,56 @@ public synchronized void exerciseOptions( int tickerId, Contract contract, final int VERSION = 2; try { - if (m_serverVersion < 21) { - error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, - " It does not support options exercise from the API."); - return; - } + if (m_serverVersion < 21) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, + " It does not support options exercise from the API."); + return; + } - if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { - if (!IsEmpty(contract.tradingClass()) || (contract.conid() > 0)) { - error(tickerId, EClientErrors.UPDATE_TWS, - " It does not support conId and tradingClass parameters in exerciseOptions."); - return; - } - } + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if (!IsEmpty(contract.tradingClass()) || (contract.conid() > 0)) { + error(tickerId, EClientErrors.UPDATE_TWS, + " It does not support conId and tradingClass parameters in exerciseOptions."); + return; + } + } - Builder b = prepareBuffer(); + Builder b = prepareBuffer(); - b.send(EXERCISE_OPTIONS); - b.send(VERSION); - b.send(tickerId); + b.send(EXERCISE_OPTIONS); + b.send(VERSION); + b.send(tickerId); - // send contract fields - if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { - b.send(contract.conid()); - } - b.send(contract.symbol()); - b.send(contract.getSecType()); - b.send(contract.lastTradeDateOrContractMonth()); - b.send(contract.strike()); - b.send(contract.getRight()); - b.send(contract.multiplier()); - b.send(contract.exchange()); - b.send(contract.currency()); - b.send(contract.localSymbol()); - if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { - b.send(contract.tradingClass()); - } - b.send(exerciseAction); - b.send(exerciseQuantity); - b.send(account); - b.send(override); + // send contract fields + if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + b.send(contract.conid()); + } + b.send(contract.symbol()); + b.send(contract.getSecType()); + b.send(contract.lastTradeDateOrContractMonth()); + b.send(contract.strike()); + b.send(contract.getRight()); + b.send(contract.multiplier()); + b.send(contract.exchange()); + b.send(contract.currency()); + b.send(contract.localSymbol()); + if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + b.send(contract.tradingClass()); + } + b.send(exerciseAction); + b.send(exerciseQuantity); + b.send(account); + b.send(override); - closeAndSend(b); - } - catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_REQMKT, e.toString()); - close(); - } + closeAndSend(b); + } + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch (Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQMKT, e.toString()); + close(); + } } public synchronized void placeOrder( int id, Contract contract, Order order) { @@ -1590,9 +1666,54 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { if (m_serverVersion < MIN_SERVER_VER_PRICE_MGMT_ALGO && order.usePriceMgmtAlgo() != null) { error(id, EClientErrors.UPDATE_TWS, " It does not support price management algo parameter"); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_DURATION + && order.duration() != Integer.MAX_VALUE) { + error(id, EClientErrors.UPDATE_TWS, " It does not support duration attribute"); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_POST_TO_ATS + && order.postToAts() != Integer.MAX_VALUE) { + error(id, EClientErrors.UPDATE_TWS, " It does not support postToAts attribute"); + return; } + if (m_serverVersion < MIN_SERVER_VER_AUTO_CANCEL_PARENT + && order.autoCancelParent()) { + error(id, EClientErrors.UPDATE_TWS, " It does not support autoCancelParent attribute"); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_ADVANCED_ORDER_REJECT) { + if (!IsEmpty(order.advancedErrorOverride())) { + error(id, EClientErrors.UPDATE_TWS, " It does not support advanced error override attribute"); + return; + } + } + if (m_serverVersion < MIN_SERVER_VER_MANUAL_ORDER_TIME) { + if (!IsEmpty(order.manualOrderTime())) { + error(id, EClientErrors.UPDATE_TWS, " It does not support manual order time attribute"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_PEGBEST_PEGMID_OFFSETS) { + if (order.minTradeQty() != Integer.MAX_VALUE || + order.minCompeteSize() != Integer.MAX_VALUE || + order.competeAgainstBestOffset() != Double.MAX_VALUE || + order.midOffsetAtWhole() != Double.MAX_VALUE || + order.midOffsetAtHalf() != Double.MAX_VALUE) { + error(id, EClientErrors.UPDATE_TWS, + " It does not support PEG BEST / PEG MID order parameters: minTradeQty, minCompeteSize, " + + "competeAgainstBestOffset, midOffsetAtWhole and midOffsetAtHalf"); + return; + } + } + int VERSION = (m_serverVersion < MIN_SERVER_VER_NOT_HELD) ? 27 : 45; // send place order msg @@ -1639,9 +1760,9 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.send( order.getAction()); if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) - b.send(order.totalQuantity()); + b.send(order.totalQuantity().toString()); else - b.send((int) order.totalQuantity()); + b.send((int) order.totalQuantity().longValue()); b.send( order.getOrderType()); if (m_serverVersion < MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE) { @@ -1785,9 +1906,9 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.send( order.allOrNone()); b.sendMax( order.minQty()); b.sendMax( order.percentOffset()); - b.send( order.eTradeOnly()); - b.send( order.firmQuoteOnly()); - b.sendMax( order.nbboPriceCap()); + b.send( false); + b.send( false); + b.sendMax( Double.MAX_VALUE); b.sendMax( order.auctionStrategy()); b.sendMax( order.startingPrice()); b.sendMax( order.stockRefPrice()); @@ -2017,10 +2138,53 @@ public synchronized void placeOrder( int id, Contract contract, Order order) { b.send(order.usePriceMgmtAlgo()); } + if (m_serverVersion >= MIN_SERVER_VER_DURATION) { + b.send(order.duration()); + } + + if (m_serverVersion >= MIN_SERVER_VER_POST_TO_ATS) { + b.send(order.postToAts()); + } + + if (m_serverVersion >= MIN_SERVER_VER_AUTO_CANCEL_PARENT) { + b.send(order.autoCancelParent()); + } + + if (m_serverVersion >= MIN_SERVER_VER_ADVANCED_ORDER_REJECT) { + b.send(order.advancedErrorOverride()); + } + + if (m_serverVersion >= MIN_SERVER_VER_MANUAL_ORDER_TIME) { + b.send(order.manualOrderTime()); + } + + if (m_serverVersion >= MIN_SERVER_VER_PEGBEST_PEGMID_OFFSETS) { + if (contract.exchange().equals("IBKRATS")) { + b.sendMax(order.minTradeQty()); + } + boolean sendMidOffsets = false; + if (order.orderType().equals(OrderType.PEG_BEST)) { + b.sendMax(order.minCompeteSize()); + b.sendMax(order.competeAgainstBestOffset()); + if (order.isCompeteAgainstBestOffsetUpToMid()) { + sendMidOffsets = true; + } + } else if (order.orderType().equals(OrderType.PEG_MID)) { + sendMidOffsets = true; + } + if (sendMidOffsets) { + b.sendMax(order.midOffsetAtWhole()); + b.sendMax(order.midOffsetAtHalf()); + } + } + closeAndSend(b); } - catch( Exception e) { - error( id, EClientErrors.FAIL_SEND_ORDER, e.toString()); + catch(EClientException e) { + error(id, e.error(), e.text()); + } + catch(Exception e) { + error(id, EClientErrors.FAIL_SEND_ORDER, e.toString()); close(); } } @@ -2047,9 +2211,12 @@ public synchronized void reqAccountUpdates(boolean subscribe, String acctCode) { b.send( acctCode); } closeAndSend(b); - } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_ACCT, e.toString()); + } + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } + catch(Exception e) { + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_ACCT, e.toString()); close(); } } @@ -2079,7 +2246,7 @@ public synchronized void reqExecutions(int reqId, ExecutionFilter filter) { b.send( filter.clientId()); b.send( filter.acctCode()); - // Note that the valid format for m_time is "yyyymmdd-hh:mm:ss" + // Note that the valid format for m_time is "yyyyMMdd-HH:mm:ss" (UTC) or "yyyyMMdd HH:mm:ss timezone" b.send( filter.time()); b.send( filter.symbol()); b.send( filter.secType()); @@ -2088,19 +2255,29 @@ public synchronized void reqExecutions(int reqId, ExecutionFilter filter) { } closeAndSend(b); } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_EXEC, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_EXEC, e.toString()); close(); } } - public synchronized void cancelOrder( int id) { + public synchronized void cancelOrder( int id, String manualOrderCancelTime) { // not connected? if( !isConnected()) { notConnected(); return; } + if (m_serverVersion < MIN_SERVER_VER_MANUAL_ORDER_TIME) { + if (!IsEmpty(manualOrderCancelTime)) { + error(id, EClientErrors.UPDATE_TWS, " It does not support manual order cancel time attribute"); + return; + } + } + final int VERSION = 1; // send cancel order msg @@ -2111,6 +2288,10 @@ public synchronized void cancelOrder( int id) { b.send( VERSION); b.send( id); + if (m_serverVersion >= MIN_SERVER_VER_MANUAL_ORDER_TIME) { + b.send(manualOrderCancelTime); + } + closeAndSend(b); } catch( Exception e) { @@ -2338,13 +2519,13 @@ public synchronized void requestFA( int faDataType ) { closeAndSend(b); } - catch( Exception e) { + catch(Exception e) { error( faDataType, EClientErrors.FAIL_SEND_FA_REQUEST, e.toString()); close(); } } - public synchronized void replaceFA( int faDataType, String xml ) { + public synchronized void replaceFA( int reqId, int faDataType, String xml ) { // not connected? if( !isConnected()) { notConnected(); @@ -2367,11 +2548,17 @@ public synchronized void replaceFA( int faDataType, String xml ) { b.send( VERSION); b.send( faDataType); b.send( xml); + if(m_serverVersion >= MIN_SERVER_VER_REPLACE_FA_END) { + b.send(reqId); + } closeAndSend(b); } - catch( Exception e) { - error( faDataType, EClientErrors.FAIL_SEND_FA_REPLACE, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_FA_REPLACE, e.toString()); close(); } } @@ -2459,8 +2646,11 @@ public synchronized void reqFundamentalData(int reqId, Contract contract, String closeAndSend(b); } - catch( Exception e) { - error( reqId, EClientErrors.FAIL_SEND_REQFUNDDATA, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQFUNDDATA, e.toString()); close(); } } @@ -2557,8 +2747,11 @@ public synchronized void calculateImpliedVolatility(int reqId, Contract contract closeAndSend(b); } - catch( Exception e) { - error( reqId, EClientErrors.FAIL_SEND_REQCALCIMPLIEDVOLAT, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQCALCIMPLIEDVOLAT, e.toString()); close(); } } @@ -2656,8 +2849,11 @@ public synchronized void calculateOptionPrice(int reqId, Contract contract, closeAndSend(b); } - catch( Exception e) { - error( reqId, EClientErrors.FAIL_SEND_REQCALCOPTIONPRICE, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQCALCOPTIONPRICE, e.toString()); close(); } } @@ -2772,10 +2968,9 @@ public synchronized void reqPositions() { Builder b = prepareBuffer(); - b.send( REQ_POSITIONS); - b.send( VERSION); - try { + b.send( REQ_POSITIONS); + b.send( VERSION); closeAndSend(b); } catch (IOException e) { @@ -2799,18 +2994,21 @@ public synchronized void reqSecDefOptParams(int reqId, String underlyingSymbol, Builder b = prepareBuffer(); - b.send(REQ_SEC_DEF_OPT_PARAMS); - b.send(reqId); - b.send(underlyingSymbol); - b.send(futFopExchange); - b.send(underlyingSecType); - b.send(underlyingConId); - try { + b.send(REQ_SEC_DEF_OPT_PARAMS); + b.send(reqId); + b.send(underlyingSymbol); + b.send(futFopExchange); + b.send(underlyingSecType); + b.send(underlyingConId); closeAndSend(b); } - catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQSECDEFOPTPARAMS, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(IOException e) { + error(reqId, EClientErrors.FAIL_SEND_REQSECDEFOPTPARAMS, e.toString()); + close(); } } @@ -2828,11 +3026,10 @@ public synchronized void reqSoftDollarTiers(int reqId) { Builder b = prepareBuffer(); - b.send(REQ_SOFT_DOLLAR_TIERS); - b.send(reqId); - try { - closeAndSend(b); + b.send(REQ_SOFT_DOLLAR_TIERS); + b.send(reqId); + closeAndSend(b); } catch (IOException e) { error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQSOFTDOLLARTIERS, e.toString()); @@ -2856,10 +3053,9 @@ public synchronized void cancelPositions() { Builder b = prepareBuffer(); - b.send( CANCEL_POSITIONS); - b.send( VERSION); - try { + b.send( CANCEL_POSITIONS); + b.send( VERSION); closeAndSend(b); } catch (IOException e) { @@ -2884,17 +3080,20 @@ public synchronized void reqPositionsMulti( int reqId, String account, String mo Builder b = prepareBuffer(); - b.send( REQ_POSITIONS_MULTI); - b.send( VERSION); - b.send( reqId); - b.send( account); - b.send( modelCode); - try { + b.send( REQ_POSITIONS_MULTI); + b.send( VERSION); + b.send( reqId); + b.send( account); + b.send( modelCode); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQPOSITIONSMULTI, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQPOSITIONSMULTI, e.toString()); + close(); } } @@ -2915,11 +3114,10 @@ public synchronized void cancelPositionsMulti( int reqId) { Builder b = prepareBuffer(); - b.send( CANCEL_POSITIONS_MULTI); - b.send( VERSION); - b.send( reqId); - try { + b.send( CANCEL_POSITIONS_MULTI); + b.send( VERSION); + b.send( reqId); closeAndSend(b); } catch (IOException e) { @@ -2944,15 +3142,14 @@ public synchronized void cancelAccountUpdatesMulti( int reqId) { Builder b = prepareBuffer(); - b.send( CANCEL_ACCOUNT_UPDATES_MULTI); - b.send( VERSION); - b.send( reqId); - try { + b.send( CANCEL_ACCOUNT_UPDATES_MULTI); + b.send( VERSION); + b.send( reqId); closeAndSend(b); } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CANACCOUNTUPDATESMULTI, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_CANACCOUNTUPDATESMULTI, e.toString()); } } @@ -2973,18 +3170,21 @@ public synchronized void reqAccountUpdatesMulti( int reqId, String account, Stri Builder b = prepareBuffer(); - b.send( REQ_ACCOUNT_UPDATES_MULTI); - b.send( VERSION); - b.send( reqId); - b.send( account); - b.send( modelCode); - b.send( ledgerAndNLV); - try { + b.send( REQ_ACCOUNT_UPDATES_MULTI); + b.send( VERSION); + b.send( reqId); + b.send( account); + b.send( modelCode); + b.send( ledgerAndNLV); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQACCOUNTUPDATESMULTI, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQACCOUNTUPDATESMULTI, e.toString()); + close(); } } @@ -3005,17 +3205,20 @@ public synchronized void reqAccountSummary( int reqId, String group, String tags Builder b = prepareBuffer(); - b.send( REQ_ACCOUNT_SUMMARY); - b.send( VERSION); - b.send( reqId); - b.send( group); - b.send( tags); - try { + b.send( REQ_ACCOUNT_SUMMARY); + b.send( VERSION); + b.send( reqId); + b.send( group); + b.send( tags); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQACCOUNTDATA, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQACCOUNTDATA, e.toString()); + close(); } } @@ -3036,11 +3239,10 @@ public synchronized void cancelAccountSummary( int reqId) { Builder b = prepareBuffer(); - b.send( CANCEL_ACCOUNT_SUMMARY); - b.send( VERSION); - b.send( reqId); - try { + b.send( CANCEL_ACCOUNT_SUMMARY); + b.send( VERSION); + b.send( reqId); closeAndSend(b); } catch (IOException e) { @@ -3068,17 +3270,20 @@ public synchronized void verifyRequest( String apiName, String apiVersion) { final int VERSION = 1; - Builder b = prepareBuffer(); - b.send( VERIFY_REQUEST); - b.send( VERSION); - b.send( apiName); - b.send( apiVersion); - try { + Builder b = prepareBuffer(); + b.send( VERIFY_REQUEST); + b.send( VERSION); + b.send( apiName); + b.send( apiVersion); closeAndSend(b); } + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYREQUEST, e.toString()); + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYREQUEST, e.toString()); + close(); } } @@ -3098,15 +3303,19 @@ public synchronized void verifyMessage( String apiData) { final int VERSION = 1; Builder b = prepareBuffer(); - b.send( VERIFY_MESSAGE); - b.send( VERSION); - b.send( apiData); try { + b.send( VERIFY_MESSAGE); + b.send( VERSION); + b.send( apiData); closeAndSend(b); } + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYMESSAGE, e.toString()); + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYMESSAGE, e.toString()); + close(); } } @@ -3132,17 +3341,21 @@ public synchronized void verifyAndAuthRequest( String apiName, String apiVersion final int VERSION = 1; Builder b = prepareBuffer(); - b.send( VERIFY_AND_AUTH_REQUEST); - b.send( VERSION); - b.send( apiName); - b.send( apiVersion); - b.send( opaqueIsvKey); try { + b.send( VERIFY_AND_AUTH_REQUEST); + b.send( VERSION); + b.send( apiName); + b.send( apiVersion); + b.send( opaqueIsvKey); closeAndSend(b); } + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYANDAUTHREQUEST, e.toString()); + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYANDAUTHREQUEST, e.toString()); + close(); } } @@ -3162,16 +3375,20 @@ public synchronized void verifyAndAuthMessage( String apiData, String xyzRespons final int VERSION = 1; Builder b = prepareBuffer(); - b.send( VERIFY_AND_AUTH_MESSAGE); - b.send( VERSION); - b.send( apiData); - b.send( xyzResponse); try { + b.send( VERIFY_AND_AUTH_MESSAGE); + b.send( VERSION); + b.send( apiData); + b.send( xyzResponse); closeAndSend(b); } + catch(EClientException e) { + error(EClientErrors.NO_VALID_ID, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYANDAUTHMESSAGE, e.toString()); + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_VERIFYANDAUTHMESSAGE, e.toString()); + close(); } } @@ -3192,11 +3409,10 @@ public synchronized void queryDisplayGroups( int reqId) { Builder b = prepareBuffer(); - b.send( QUERY_DISPLAY_GROUPS); - b.send( VERSION); - b.send( reqId); - try { + b.send( QUERY_DISPLAY_GROUPS); + b.send( VERSION); + b.send( reqId); closeAndSend(b); } catch (IOException e) { @@ -3221,12 +3437,11 @@ public synchronized void subscribeToGroupEvents( int reqId, int groupId) { Builder b = prepareBuffer(); - b.send( SUBSCRIBE_TO_GROUP_EVENTS); - b.send( VERSION); - b.send( reqId); - b.send( groupId); - try { + b.send( SUBSCRIBE_TO_GROUP_EVENTS); + b.send( VERSION); + b.send( reqId); + b.send( groupId); closeAndSend(b); } catch (IOException e) { @@ -3251,16 +3466,19 @@ public synchronized void updateDisplayGroup( int reqId, String contractInfo) { Builder b = prepareBuffer(); - b.send( UPDATE_DISPLAY_GROUP); - b.send( VERSION); - b.send( reqId); - b.send( contractInfo); - try { + b.send( UPDATE_DISPLAY_GROUP); + b.send( VERSION); + b.send( reqId); + b.send( contractInfo); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_UPDATEDISPLAYGROUP, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_UPDATEDISPLAYGROUP, e.toString()); + close(); } } @@ -3281,11 +3499,10 @@ public synchronized void unsubscribeFromGroupEvents( int reqId) { Builder b = prepareBuffer(); - b.send( UNSUBSCRIBE_FROM_GROUP_EVENTS); - b.send( VERSION); - b.send( reqId); - try { + b.send( UNSUBSCRIBE_FROM_GROUP_EVENTS); + b.send( VERSION); + b.send( reqId); closeAndSend(b); } catch (IOException e) { @@ -3308,15 +3525,18 @@ public synchronized void reqMatchingSymbols( int reqId, String pattern) { Builder b = prepareBuffer(); - b.send( REQ_MATCHING_SYMBOLS); - b.send( reqId); - b.send( pattern); - try { + b.send( REQ_MATCHING_SYMBOLS); + b.send( reqId); + b.send( pattern); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQMATCHINGSYMBOLS, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQMATCHINGSYMBOLS, e.toString()); + close(); } } @@ -3335,9 +3555,8 @@ public synchronized void reqFamilyCodes() { Builder b = prepareBuffer(); - b.send( REQ_FAMILY_CODES); - try { + b.send( REQ_FAMILY_CODES); closeAndSend(b); } catch (IOException e) { @@ -3360,9 +3579,8 @@ public synchronized void reqMktDepthExchanges() { Builder b = prepareBuffer(); - b.send( REQ_MKT_DEPTH_EXCHANGES); - try { + b.send( REQ_MKT_DEPTH_EXCHANGES); closeAndSend(b); } catch (IOException e) { @@ -3385,16 +3603,18 @@ public synchronized void reqSmartComponents(int reqId, String bboExchange) { Builder b = prepareBuffer(); - b.send(REQ_SMART_COMPONENTS); - b.send(reqId); - b.send(bboExchange); - try { - + b.send(REQ_SMART_COMPONENTS); + b.send(reqId); + b.send(bboExchange); closeAndSend(b); } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } catch (IOException e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQSMARTCOMPONENTS, e.toString()); + error(reqId, EClientErrors.FAIL_SEND_REQSMARTCOMPONENTS, e.toString()); + close(); } } @@ -3413,9 +3633,8 @@ public synchronized void reqNewsProviders() { Builder b = prepareBuffer(); - b.send( REQ_NEWS_PROVIDERS); - try { + b.send( REQ_NEWS_PROVIDERS); closeAndSend(b); } catch (IOException e) { @@ -3438,21 +3657,25 @@ public synchronized void reqNewsArticle(int requestId, String providerCode, Stri Builder b = prepareBuffer(); - b.send(REQ_NEWS_ARTICLE); - b.send(requestId); - b.send(providerCode); - b.send(articleId); - - // send newsArticleOptions parameter - if (m_serverVersion >= MIN_SERVER_VER_NEWS_QUERY_ORIGINS) { - b.send(newsArticleOptions); - } - try { + b.send(REQ_NEWS_ARTICLE); + b.send(requestId); + b.send(providerCode); + b.send(articleId); + + // send newsArticleOptions parameter + if (m_serverVersion >= MIN_SERVER_VER_NEWS_QUERY_ORIGINS) { + b.send(newsArticleOptions); + } + closeAndSend(b); } + catch(EClientException e) { + error(requestId, e.error(), e.text()); + } catch (IOException e) { - error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQNEWSARTICLE, e.toString()); + error(requestId, EClientErrors.FAIL_SEND_REQNEWSARTICLE, e.toString()); + close(); } } @@ -3473,24 +3696,28 @@ public synchronized void reqHistoricalNews( int requestId, int conId, String pro Builder b = prepareBuffer(); - b.send(REQ_HISTORICAL_NEWS); - b.send(requestId); - b.send(conId); - b.send(providerCodes); - b.send(startDateTime); - b.send(endDateTime); - b.send(totalResults); + try { + b.send(REQ_HISTORICAL_NEWS); + b.send(requestId); + b.send(conId); + b.send(providerCodes); + b.send(startDateTime); + b.send(endDateTime); + b.send(totalResults); - // send historicalNewsOptions parameter - if (m_serverVersion >= MIN_SERVER_VER_NEWS_QUERY_ORIGINS) { - b.send(historicalNewsOptions); - } + // send historicalNewsOptions parameter + if (m_serverVersion >= MIN_SERVER_VER_NEWS_QUERY_ORIGINS) { + b.send(historicalNewsOptions); + } - try { closeAndSend(b); } - catch (IOException e) { - error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQHISTORICALNEWS, e.toString()); + catch(EClientException e) { + error(requestId, e.error(), e.text()); + } + catch(IOException e) { + error(requestId, EClientErrors.FAIL_SEND_REQHISTORICALNEWS, e.toString()); + close(); } } @@ -3518,11 +3745,14 @@ public synchronized void reqHistogramData(int tickerId, Contract contract, b.send(timePeriod); closeAndSend(b); - } - catch (Exception e) { - error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, e.toString()); - close(); - } + } + catch(EClientException e) { + error(tickerId, e.error(), e.text()); + } + catch (Exception e) { + error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, e.toString()); + close(); + } } public synchronized void cancelHistogramData( int tickerId ) { @@ -3575,8 +3805,8 @@ public synchronized void reqMarketRule( int marketRuleId) { closeAndSend(b); } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQMARKETRULE, e.toString()); + catch(Exception e) { + error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQMARKETRULE, e.toString()); close(); } } @@ -3602,7 +3832,11 @@ public synchronized void reqPnL(int reqId, String account, String modelCode) { b.send(modelCode); closeAndSend(b); - } catch(Exception e) { + } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { error(reqId, EClientErrors.FAIL_SEND_REQPNL, e.toString()); close(); } @@ -3627,7 +3861,8 @@ public synchronized void cancelPnL(int reqId) { b.send(reqId); closeAndSend(b); - } catch(Exception e) { + } + catch(Exception e) { error(reqId, EClientErrors.FAIL_SEND_CANPNL, e.toString()); close(); } @@ -3655,7 +3890,11 @@ public synchronized void reqPnLSingle(int reqId, String account, String modelCod b.send(conId); closeAndSend(b); - } catch(Exception e) { + } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { error(reqId, EClientErrors.FAIL_SEND_REQPNL_SINGLE, e.toString()); close(); } @@ -3715,7 +3954,11 @@ public synchronized void reqHistoricalTicks(int reqId, Contract contract, String b.send(miscOptions); closeAndSend(b); - } catch(Exception e) { + } + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { error(reqId, EClientErrors.FAIL_SEND_HISTORICAL_TICK, e.toString()); close(); } @@ -3767,9 +4010,11 @@ public synchronized void reqTickByTickData(int reqId, Contract contract, String closeAndSend(b); } - catch( Exception e) { - error( EClientErrors.NO_VALID_ID, - EClientErrors.FAIL_SEND_REQTICKBYTICK, e.toString()); + catch(EClientException e) { + error(reqId, e.error(), e.text()); + } + catch(Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQTICKBYTICK, e.toString()); close(); } } @@ -3830,6 +4075,173 @@ public synchronized void reqCompletedOrders(boolean apiOnly) { } } + public synchronized void reqWshMetaData(int reqId) { + // not connected? + if( !isConnected()) { + notConnected(); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_WSHE_CALENDAR) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, + " It does not support WSHE Calendar API."); + return; + } + + try { + Builder b = prepareBuffer(); + + b.send(REQ_WSH_META_DATA); + b.send(reqId); + + closeAndSend(b); + } + catch( Exception e) { + error( EClientErrors.NO_VALID_ID, + EClientErrors.FAIL_SEND_REQ_WSH_META_DATA, e.toString()); + close(); + } + } + + public synchronized void cancelWshMetaData(int reqId) { + // not connected? + if( !isConnected()) { + notConnected(); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_WSHE_CALENDAR) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, + " It does not support WSHE Calendar API."); + return; + } + + try { + Builder b = prepareBuffer(); + + b.send(CANCEL_WSH_META_DATA); + b.send(reqId); + + closeAndSend(b); + } + catch( Exception e) { + error( EClientErrors.NO_VALID_ID, + EClientErrors.FAIL_SEND_CAN_WSH_META_DATA, e.toString()); + close(); + } + } + + public synchronized void reqWshEventData(int reqId, WshEventData wshEventData) { + // not connected? + if( !isConnected()) { + notConnected(); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_WSHE_CALENDAR) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, + " It does not support WSHE Calendar API."); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS) { + if (!IsEmpty(wshEventData.filter()) || wshEventData.fillWatchlist() || wshEventData.fillPortfolio() || wshEventData.fillCompetitors()) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support WSH event data filters."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS_DATE) { + if (!IsEmpty(wshEventData.startDate()) || !IsEmpty(wshEventData.endDate()) || wshEventData.totalLimit() != Integer.MAX_VALUE) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support WSH event data date filters."); + return; + } + } + + try { + Builder b = prepareBuffer(); + + b.send(REQ_WSH_EVENT_DATA); + b.send(reqId); + b.send(wshEventData.conId()); + + if (m_serverVersion >= MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS) { + b.send(wshEventData.filter()); + b.send(wshEventData.fillWatchlist()); + b.send(wshEventData.fillPortfolio()); + b.send(wshEventData.fillCompetitors()); + } + + if (m_serverVersion >= MIN_SERVER_VER_WSH_EVENT_DATA_FILTERS_DATE) { + b.send(wshEventData.startDate()); + b.send(wshEventData.endDate()); + b.send(wshEventData.totalLimit()); + } + + closeAndSend(b); + } + catch( Exception e) { + error( EClientErrors.NO_VALID_ID, + EClientErrors.FAIL_SEND_REQ_WSH_META_DATA, e.toString()); + close(); + } + } + + public synchronized void cancelWshEventData(int reqId) { + // not connected? + if( !isConnected()) { + notConnected(); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_WSHE_CALENDAR) { + error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, + " It does not support WSHE Calendar API."); + return; + } + + try { + Builder b = prepareBuffer(); + + b.send(CANCEL_WSH_EVENT_DATA); + b.send(reqId); + + closeAndSend(b); + } + catch( Exception e) { + error( EClientErrors.NO_VALID_ID, + EClientErrors.FAIL_SEND_CAN_WSH_EVENT_DATA, e.toString()); + close(); + } + } + + public synchronized void reqUserInfo(int reqId) { + + // not connected? + if( !isConnected()) { + notConnected(); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_USER_INFO) { + error(reqId, EClientErrors.UPDATE_TWS, " It does not support user info requests."); + return; + } + + try { + Builder b = prepareBuffer(); + + b.send(REQ_USER_INFO); + b.send(reqId); + + closeAndSend(b); + } + catch( Exception e) { + error(reqId, EClientErrors.FAIL_SEND_REQUSERINFO, e.toString()); + close(); + } + } + /** * @deprecated This method is never called. */ @@ -3839,7 +4251,7 @@ protected synchronized void error( String err) { } protected synchronized void error( int id, int errorCode, String errorMsg) { - m_eWrapper.error( id, errorCode, errorMsg); + m_eWrapper.error( id, errorCode, errorMsg, null); } protected void close() { diff --git a/ref/client/EClientErrors.java b/ref/client/EClientErrors.java index b9aba302..fee2816c 100644 --- a/ref/client/EClientErrors.java +++ b/ref/client/EClientErrors.java @@ -85,6 +85,12 @@ public class EClientErrors { 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 INVALID_SYMBOL = new CodeMsgPair(579, "Invalid symbol in string - "); public EClientErrors() { } diff --git a/ref/client/EClientException.java b/ref/client/EClientException.java new file mode 100644 index 00000000..fba4088b --- /dev/null +++ b/ref/client/EClientException.java @@ -0,0 +1,23 @@ +/* Copyright (C) 2020 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.io.IOException; + +import com.ib.client.EClientErrors.CodeMsgPair; + +class EClientException extends IOException { + + private static final long serialVersionUID = 1L; + private final CodeMsgPair m_error; + private final String m_text; + + public CodeMsgPair error() { return m_error; } + public String text() { return m_text; } + + EClientException(CodeMsgPair err, String text) { + m_error = err; + m_text = text; + } +} diff --git a/ref/client/EClientSocket.java b/ref/client/EClientSocket.java index 4b3a8152..d317cdd8 100644 --- a/ref/client/EClientSocket.java +++ b/ref/client/EClientSocket.java @@ -63,7 +63,8 @@ protected synchronized void eConnect(Socket socket) throws IOException { EReader reader = new EReader(this, m_signal); if (!m_asyncEConnect) { - reader.putMessageToQueue(); + if (!reader.putMessageToQueue()) + return; while (m_serverVersion == 0) { m_signal.waitForSignal(); @@ -115,7 +116,7 @@ public void allowRedirect(boolean val) { public synchronized void redirect(String newAddress) { if( m_useV100Plus ) { if (!m_allowRedirect) { - m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.CONNECT_FAIL.code(), EClientErrors.CONNECT_FAIL.msg()); + m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.CONNECT_FAIL.code(), EClientErrors.CONNECT_FAIL.msg(), null); return; } @@ -144,13 +145,13 @@ public synchronized void serverVersion(int version, String time) { if( m_useV100Plus && (m_serverVersion < MIN_VERSION || m_serverVersion > MAX_VERSION) ) { eDisconnect(); - m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.UNSUPPORTED_VERSION.code(), EClientErrors.UNSUPPORTED_VERSION.msg()); + m_eWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.UNSUPPORTED_VERSION.code(), EClientErrors.UNSUPPORTED_VERSION.msg(), null); return; } if( m_serverVersion < MIN_SERVER_VER_SUPPORTED) { eDisconnect(); - m_eWrapper.error( EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); + m_eWrapper.error( EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg(), null); return; } @@ -223,6 +224,8 @@ private synchronized void eDisconnect( boolean resetState ) { dis.close(); } catch (Exception ignored) { } + // Notify client: connection closed + m_eWrapper.connectionClosed(); } public int read(byte[] buf, int off, int len) throws IOException { diff --git a/ref/client/EClientSocketSSL.java b/ref/client/EClientSocketSSL.java deleted file mode 100644 index b322df5e..00000000 --- a/ref/client/EClientSocketSSL.java +++ /dev/null @@ -1,92 +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.client; - -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -public class EClientSocketSSL extends EClientSocket { - - public EClientSocketSSL(EWrapper eWrapper, EReaderSignal signal) { - super(eWrapper, signal); - - SSLContext ctx; - try { - ctx = SSLContext.getInstance("TLS"); - ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); - SSLContext.setDefault(ctx); - } catch (KeyManagementException | NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private static class DefaultTrustManager implements X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - @Override - public synchronized void eConnect( String host, int port, int clientId, boolean extraAuth) { - // already connected? - m_host = checkConnected(host); - - m_clientId = clientId; - m_extraAuth = extraAuth; - m_redirectCount = 0; - - if(m_host == null){ - return; - } - - try{ - SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(m_host, port); - eConnect(socket); - } - catch( Exception e) { - eDisconnect(); - wrapper().error(e); - } - } - - @Override - protected synchronized void performRedirect( String address, int defaultPort ) throws IOException { - System.out.println("Server Redirect: " + address); - - // Get host:port from address string and reconnect (note: port is optional) - String[] array = address.split(":"); - m_host = array[0]; // reset connected host - int newPort; - - try { - newPort = ( array.length > 1 ) ? Integer.parseInt(array[1]) : defaultPort; - } - catch ( NumberFormatException e ) { - System.out.println( "Warning: redirect port is invalid, using default port"); - newPort = defaultPort; - } - - eConnect( SSLSocketFactory.getDefault().createSocket( m_host, newPort ) ); - } -} diff --git a/ref/client/EDecoder.java b/ref/client/EDecoder.java index 0d0b2eb0..718b2761 100644 --- a/ref/client/EDecoder.java +++ b/ref/client/EDecoder.java @@ -97,6 +97,11 @@ class EDecoder implements ObjectInput { private static final int ORDER_BOUND = 100; private static final int COMPLETED_ORDER = 101; private static final int COMPLETED_ORDERS_END = 102; + private static final int REPLACE_FA_END = 103; + private static final int WSH_META_DATA = 104; + private static final int WSH_EVENT_DATA = 105; + private static final int HISTORICAL_SCHEDULE = 106; + private static final int USER_INFO = 107; static final int MAX_MSG_LENGTH = 0xffffff; private static final int REDIRECT_MSG_ID = -1; @@ -476,9 +481,29 @@ public int processMsg(EMessage msg) throws IOException { case COMPLETED_ORDERS_END: processCompletedOrdersEndMsg(); break; + + case REPLACE_FA_END: + processReplaceFAEndMsg(); + break; + + case WSH_META_DATA: + processWshMetaData(); + break; + + case WSH_EVENT_DATA: + processWshEventData(); + break; + + case HISTORICAL_SCHEDULE: + processHistoricalSchedule(); + break; + + case USER_INFO: + processUserInfo(); + break; default: { - m_EWrapper.error( EClientErrors.NO_VALID_ID, EClientErrors.UNKNOWN_ID.code(), EClientErrors.UNKNOWN_ID.msg()); + m_EWrapper.error( EClientErrors.NO_VALID_ID, EClientErrors.UNKNOWN_ID.code(), EClientErrors.UNKNOWN_ID.msg(), null); return 0; } } @@ -501,7 +526,7 @@ private void processHistoricalTicksLast() throws IOException { tickAttribLast.unreported(mask.get(1)); double price = readDouble(); - long size = readLong(); + Decimal size = readDecimal(); String exchange = readStr(), specialConditions = readStr(); @@ -528,8 +553,8 @@ private void processHistoricalTicksBidAsk() throws IOException { double priceBid = readDouble(), priceAsk = readDouble(); - long sizeBid = readLong(), - sizeAsk = readLong(); + Decimal sizeBid = readDecimal(), + sizeAsk = readDecimal(); ticks.add(new HistoricalTickBidAsk(time, tickAttribBidAsk, priceBid, priceAsk, sizeBid, sizeAsk)); } @@ -549,7 +574,7 @@ private void processHistoricalTicks() throws IOException { long time = readLong(); readInt();//for consistency double price = readDouble(); - long size = readLong(); + Decimal size = readDecimal(); ticks.add(new HistoricalTick(time, price, size)); } @@ -600,15 +625,15 @@ private void processHistoricalDataUpdateMsg() throws IOException { double close = readDouble(); double high = readDouble(); double low = readDouble(); - double WAP = readDouble(); - long volume = readLong(); + Decimal WAP = readDecimal(); + Decimal volume = readDecimal(); m_EWrapper.historicalDataUpdate(reqId, new Bar(date, open, high, low, close, volume, barCount, WAP)); } private void processPnLSingleMsg() throws IOException { int reqId = readInt(); - int pos = readInt(); + Decimal pos = readDecimal(); double dailyPnL = readDouble(); double unrealizedPnL = Double.MAX_VALUE; double realizedPnL = Double.MAX_VALUE; @@ -649,7 +674,7 @@ private void processHistogramDataMsg() throws IOException { List items = new ArrayList<>(n); for (int i = 0; i < n; i++) { - items.add(new HistogramEntry(readDouble(), readLong())); + items.add(new HistogramEntry(readDouble(), readDecimal())); } m_EWrapper.histogramData(reqId, items); @@ -764,6 +789,11 @@ private void processSymbolSamplesMsg() throws IOException { } } + if (m_serverVersion >= EClient.MIN_SERVER_VER_BOND_ISSUERID) { + contract.description(readStr()); + contract.issuerId(readStr()); + } + ContractDescription contractDescription = new ContractDescription(contract, derivativeSecTypes); contractDescriptions[i] = contractDescription; } @@ -953,8 +983,8 @@ private void processRealTimeBarsMsg() throws IOException { double high = readDouble(); double low = readDouble(); double close = readDouble(); - long volume = readLong(); - double wap = readDouble(); + Decimal volume = readDecimal(); + Decimal wap = readDecimal(); int count = readInt(); m_EWrapper.realtimeBar(reqId, time, open, high, low, close, volume, wap, count); } @@ -993,8 +1023,8 @@ private void processHistoricalDataMsg() throws IOException { double high = readDouble(); double low = readDouble(); double close = readDouble(); - long volume = m_serverVersion < EClient.MIN_SERVER_VER_SYNT_REALTIME_BARS ? readInt() : readLong(); - double WAP = readDouble(); + Decimal volume = readDecimal(); + Decimal WAP = readDecimal(); if (m_serverVersion < EClient.MIN_SERVER_VER_SYNT_REALTIME_BARS) { /*String hasGaps = */readStr(); @@ -1046,7 +1076,7 @@ private void processMarketDepthL2Msg() throws IOException { int operation = readInt(); int side = readInt(); double price = readDouble(); - int size = readInt(); + Decimal size = readDecimal(); boolean isSmartDepth = false; if (m_serverVersion >= EClient.MIN_SERVER_VER_SMART_DEPTH) { @@ -1065,7 +1095,7 @@ private void processMarketDepthMsg() throws IOException { int operation = readInt(); int side = readInt(); double price = readDouble(); - int size = readInt(); + Decimal size = readDecimal(); m_EWrapper.updateMktDepth(id, position, operation, side, price, size); @@ -1112,12 +1142,7 @@ private void processExecutionDataMsg() throws IOException { exec.acctNumber(readStr()); exec.exchange(readStr()); exec.side(readStr()); - - if (m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS) - exec.shares(readDouble()); - else - exec.shares(readInt()); - + exec.shares(readDecimal()); exec.price(readDouble()); if ( version >= 2 ) { exec.permId(readInt()); @@ -1129,7 +1154,7 @@ private void processExecutionDataMsg() throws IOException { exec.liquidation(readInt()); } if (version >= 6) { - exec.cumQty(readDouble()); + exec.cumQty(readDecimal()); exec.avgPrice(readDouble()); } if (version >= 8) { @@ -1152,7 +1177,10 @@ private void processExecutionDataMsg() throws IOException { } private void processBondContractDataMsg() throws IOException { - int version = readInt(); + int version = 6; + if (m_serverVersion < EClient.MIN_SERVER_VER_SIZE_RULES) { + version = readInt(); + } int reqId = -1; if (version >= 3) { @@ -1180,8 +1208,8 @@ private void processBondContractDataMsg() throws IOException { contract.contract().tradingClass(readStr()); contract.contract().conid(readInt()); contract.minTick(readDouble()); - if (m_serverVersion >= EClient.MIN_SERVER_VER_MD_SIZE_MULTIPLIER) { - contract.mdSizeMultiplier(readInt()); + if (m_serverVersion >= EClient.MIN_SERVER_VER_MD_SIZE_MULTIPLIER && m_serverVersion < EClient.MIN_SERVER_VER_SIZE_RULES) { + readInt(); // mdSizeMultiplier - not used anymore } contract.orderTypes(readStr()); contract.validExchanges(readStr()); @@ -1216,12 +1244,20 @@ private void processBondContractDataMsg() throws IOException { if (m_serverVersion >= EClient.MIN_SERVER_VER_MARKET_RULES) { contract.marketRuleIds(readStr()); } + if (m_serverVersion >= EClient.MIN_SERVER_VER_SIZE_RULES) { + contract.minSize(readDecimal()); + contract.sizeIncrement(readDecimal()); + contract.suggestedSizeIncrement(readDecimal()); + } m_EWrapper.bondContractDetails( reqId, contract); } private void processContractDataMsg() throws IOException { - int version = readInt(); + int version = 8; + if (m_serverVersion < EClient.MIN_SERVER_VER_SIZE_RULES) { + version = readInt(); + } int reqId = -1; if (version >= 3) { @@ -1241,8 +1277,8 @@ private void processContractDataMsg() throws IOException { contract.contract().tradingClass(readStr()); contract.contract().conid(readInt()); contract.minTick(readDouble()); - if (m_serverVersion >= EClient.MIN_SERVER_VER_MD_SIZE_MULTIPLIER) { - contract.mdSizeMultiplier(readInt()); + if (m_serverVersion >= EClient.MIN_SERVER_VER_MD_SIZE_MULTIPLIER && m_serverVersion < EClient.MIN_SERVER_VER_SIZE_RULES) { + readInt(); // mdSizeMultiplier - not used anymore } contract.contract().multiplier(readStr()); contract.orderTypes(readStr()); @@ -1254,7 +1290,7 @@ private void processContractDataMsg() throws IOException { contract.underConid(readInt()); } if( version >= 5) { - contract.longName(readStr()); + contract.longName(m_serverVersion >= EClient.MIN_SERVER_VER_ENCODE_MSG_ASCII7 ? decodeUnicodeEscapedString(readStr()) : readStr()); contract.contract().primaryExch(readStr()); } if( version >= 6) { @@ -1295,7 +1331,18 @@ private void processContractDataMsg() throws IOException { if (m_serverVersion >= EClient.MIN_SERVER_VER_REAL_EXPIRATION_DATE) { contract.realExpirationDate(readStr()); } - + if (m_serverVersion >= EClient.MIN_SERVER_VER_STOCK_TYPE) { + contract.stockType(readStr()); + } + if (m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_SIZE_SUPPORT && m_serverVersion < EClient.MIN_SERVER_VER_SIZE_RULES) { + readDecimal(); // sizeMinTick - not used anymore + } + if (m_serverVersion >= EClient.MIN_SERVER_VER_SIZE_RULES) { + contract.minSize(readDecimal()); + contract.sizeIncrement(readDecimal()); + contract.suggestedSizeIncrement(readDecimal()); + } + m_EWrapper.contractDetails( reqId, contract); } @@ -1419,6 +1466,10 @@ private void processOpenOrderMsg() throws IOException { eOrderDecoder.readIsOmsContainer(); eOrderDecoder.readDiscretionaryUpToLimitPrice(); eOrderDecoder.readUsePriceMgmtAlgo(); + eOrderDecoder.readDuration(); + eOrderDecoder.readPostToAts(); + eOrderDecoder.readAutoCancelParent(EClient.MIN_SERVER_VER_AUTO_CANCEL_PARENT); + eOrderDecoder.readPegBestPegMidOrderAttributes(); m_EWrapper.openOrder(order.orderId(), contract, order, orderState); } @@ -1430,9 +1481,13 @@ private void processErrMsgMsg() throws IOException { m_EWrapper.error( msg); } else { int id = readInt(); - int errorCode = readInt(); - String errorMsg = readStr(); - m_EWrapper.error(id, errorCode, errorMsg); + int errorCode = readInt(); + String errorMsg = m_serverVersion >= EClient.MIN_SERVER_VER_ENCODE_MSG_ASCII7 ? decodeUnicodeEscapedString(readStr()) : readStr(); + String advancedOrderRejectJson = null; + if (m_serverVersion >= EClient.MIN_SERVER_VER_ADVANCED_ORDER_REJECT) { + advancedOrderRejectJson = decodeUnicodeEscapedString(readStr()); + } + m_EWrapper.error(id, errorCode, errorMsg, advancedOrderRejectJson); } } @@ -1465,7 +1520,7 @@ private void processPortfolioValueMsg() throws IOException { contract.tradingClass(readStr()); } - double position = m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS ? readDouble() : readInt(); + Decimal position = readDecimal(); double marketPrice = readDouble(); double marketValue = readDouble(); double averageCost = 0.0; @@ -1506,8 +1561,8 @@ private void processOrderStatusMsg() throws IOException { int version = m_serverVersion >= EClient.MIN_SERVER_VER_MARKET_CAP_PRICE ? Integer.MAX_VALUE : readInt(); int id = readInt(); String status = readStr(); - double filled = m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS ? readDouble() : readInt(); - double remaining = m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS ? readDouble() : readInt(); + Decimal filled = readDecimal(); + Decimal remaining = readDecimal(); double avgFillPrice = readDouble(); int permId = 0; @@ -1579,9 +1634,13 @@ private void processTickGenericMsg() throws IOException { } private void processTickOptionComputationMsg() throws IOException { - int version = readInt(); + int version = m_serverVersion >= EClient.MIN_SERVER_VER_PRICE_BASED_VOLATILITY ? Integer.MAX_VALUE : readInt(); int tickerId = readInt(); int tickType = readInt(); + int tickAttrib = Integer.MAX_VALUE; + if (m_serverVersion >= EClient.MIN_SERVER_VER_PRICE_BASED_VOLATILITY) { + tickAttrib = readInt(); + } double impliedVol = readDouble(); if (Double.compare(impliedVol, -1) == 0) { // -1 is the "not yet computed" indicator impliedVol = Double.MAX_VALUE; @@ -1627,7 +1686,7 @@ private void processTickOptionComputationMsg() throws IOException { } } - m_EWrapper.tickOptionComputation( tickerId, tickType, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice); + m_EWrapper.tickOptionComputation( tickerId, tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice); } private void processAccountSummaryEndMsg() throws IOException { @@ -1670,7 +1729,7 @@ private void processPositionMsg() throws IOException { contract.tradingClass(readStr()); } - double pos = m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS ? readDouble() : readInt(); + Decimal pos = readDecimal(); double avgCost = 0; if (version >= 3) { avgCost = readDouble(); @@ -1683,7 +1742,7 @@ private void processTickSizeMsg() throws IOException { /*int version =*/ readInt(); int tickerId = readInt(); int tickType = readInt(); - int size = readInt(); + Decimal size = readDecimal(); m_EWrapper.tickSize( tickerId, tickType, size); } @@ -1693,11 +1752,11 @@ private void processTickPriceMsg() throws IOException { int tickerId = readInt(); int tickType = readInt(); double price = readDouble(); - int size = 0; + Decimal size = Decimal.INVALID; TickAttrib attribs = new TickAttrib(); if( version >= 2) { - size = readInt(); + size = readDecimal(); } if (version >= 3) { @@ -1766,7 +1825,7 @@ private void processPositionMultiMsg() throws IOException { contract.currency(readStr()); contract.localSymbol(readStr()); contract.tradingClass(readStr()); - double pos = readDouble(); + Decimal pos = readDecimal(); double avgCost = readDouble(); String modelCode = readStr(); @@ -1836,7 +1895,7 @@ private void processTickByTickMsg() throws IOException { case 1: // Last case 2: // AllLast double price = readDouble(); - int size = readInt(); + Decimal size = readDecimal(); mask = new BitMask(readInt()); TickAttribLast tickAttribLast = new TickAttribLast(); tickAttribLast.pastLimit(mask.get(0)); @@ -1848,8 +1907,8 @@ private void processTickByTickMsg() throws IOException { case 3: // BidAsk double bidPrice = readDouble(); double askPrice = readDouble(); - int bidSize = readInt(); - int askSize = readInt(); + Decimal bidSize = readDecimal(); + Decimal askSize = readDecimal(); mask = new BitMask(readInt()); TickAttribBidAsk tickAttribBidAsk = new TickAttribBidAsk(); tickAttribBidAsk.bidPastLow(mask.get(0)); @@ -1941,6 +2000,7 @@ private void processCompletedOrderMsg() throws IOException { eOrderDecoder.readParentPermId(); eOrderDecoder.readCompletedTime(); eOrderDecoder.readCompletedStatus(); + eOrderDecoder.readPegBestPegMidOrderAttributes(); m_EWrapper.completedOrder(contract, order, orderState); } @@ -1949,10 +2009,56 @@ private void processCompletedOrdersEndMsg() throws IOException { m_EWrapper.completedOrdersEnd(); } + private void processReplaceFAEndMsg() throws IOException { + int reqId = readInt(); + String text = readStr(); + + m_EWrapper.replaceFAEnd(reqId, text); + } + + private void processWshMetaData() throws IOException { + int reqId = readInt(); + String dataJson = readStr(); + + m_EWrapper.wshMetaData(reqId, dataJson); + } + + private void processWshEventData() throws IOException { + int reqId = readInt(); + String dataJson = readStr(); + + m_EWrapper.wshEventData(reqId, dataJson); + } + + private void processHistoricalSchedule() throws IOException { + int reqId = readInt(); + String startDateTime = readStr(); + String endDateTime = readStr(); + String timeZone = readStr(); + + int sessionsCount = readInt(); + List sessions = new ArrayList<>(); + for (int i = 0; i < sessionsCount; i++) { + String sessionStartDateTime = readStr(); + String sessionEndDateTime = readStr(); + String sessionRefDate = readStr(); + sessions.add(new HistoricalSession(sessionStartDateTime, sessionEndDateTime, sessionRefDate)); + } + + m_EWrapper.historicalSchedule(reqId, startDateTime, endDateTime, timeZone, sessions); + } + + private void processUserInfo() throws IOException { + int reqId = readInt(); + String whiteBrandingId = readStr(); + + m_EWrapper.userInfo(reqId, whiteBrandingId); + } + private void readLastTradeDate(ContractDetails contract, boolean isBond) throws IOException { String lastTradeDateOrContractMonth = readStr(); if (lastTradeDateOrContractMonth != null) { - String[] splitted = lastTradeDateOrContractMonth.split("\\s+"); + String[] splitted = lastTradeDateOrContractMonth.contains("-") ? lastTradeDateOrContractMonth.split("-") : lastTradeDateOrContractMonth.split("\\s+"); if (splitted.length > 0) { if (isBond) { contract.maturity(splitted[0]); @@ -2005,6 +2111,14 @@ public double readDoubleMax() throws IOException { : Double.parseDouble( str); } + public Decimal readDecimal() throws IOException { + String str = readStr(); + return (str == null || str.isEmpty() || + str.equals(String.valueOf(Long.MAX_VALUE)) || + str.equals(String.valueOf(Integer.MAX_VALUE)) || + str.equals(String.valueOf(Double.MAX_VALUE))) ? Decimal.INVALID : Decimal.parse(str); + } + /** Message reader interface */ private interface IMessageReader extends Closeable { String readStr() throws IOException; @@ -2048,6 +2162,33 @@ public int msgLength() { /* noop in pre-v100 */ } } + + static String decodeUnicodeEscapedString(String str) { + + if (str == null) { + return str; + } + + String v = new String(str); + + try { + for (;;) { + int escapeIndex = v.indexOf("\\u"); + + if (escapeIndex == -1 + || v.length() - escapeIndex < 6) { + break; + } + + String escapeString = v.substring(escapeIndex , escapeIndex + 6); + int hexVal = Integer.parseInt(escapeString.replace("\\u", ""), 16); + + v = v.replace(escapeString, "" + (char)hexVal); + } + } catch (NumberFormatException e) { } + + return v; + } @Override public int skipBytes(int arg0) throws IOException { throw new UnsupportedOperationException(); } diff --git a/ref/client/EOrderDecoder.java b/ref/client/EOrderDecoder.java index c77e114b..89e9217d 100644 --- a/ref/client/EOrderDecoder.java +++ b/ref/client/EOrderDecoder.java @@ -56,11 +56,7 @@ public void readAction() throws IOException { } public void readTotalQuantity() throws IOException { - if (m_serverVersion >= EClient.MIN_SERVER_VER_FRACTIONAL_POSITIONS) { - m_order.totalQuantity(m_eDecoder.readDouble()); - } else { - m_order.totalQuantity(m_eDecoder.readInt()); - } + m_order.totalQuantity(m_eDecoder.readDecimal()); } public void readOrderType() throws IOException { @@ -233,7 +229,7 @@ public void readPegToStkOrVolOrderParams() throws IOException { public void readDisplaySize() throws IOException { if ( m_version >= 9) { - m_order.displaySize(m_eDecoder.readInt()); + m_order.displaySize(m_eDecoder.readIntMax()); } } @@ -278,19 +274,22 @@ public void readOcaType() throws IOException { public void readETradeOnly() throws IOException { if ( m_version >= 9) { - m_order.eTradeOnly(m_eDecoder.readBoolFromInt()); + // skip deprecated field + m_eDecoder.readBoolFromInt(); } } public void readFirmQuoteOnly() throws IOException { if ( m_version >= 9) { - m_order.firmQuoteOnly(m_eDecoder.readBoolFromInt()); + // skip deprecated field + m_eDecoder.readBoolFromInt(); } } public void readNbboPriceCap() throws IOException { if ( m_version >= 9) { - m_order.nbboPriceCap(m_eDecoder.readDoubleMax()); + // skip deprecated field + m_eDecoder.readDoubleMax(); } } @@ -623,7 +622,7 @@ public void readAutoCancelDate() throws IOException { } public void readFilledQuantity() throws IOException { - m_order.filledQuantity(m_eDecoder.readDoubleMax()); + m_order.filledQuantity(m_eDecoder.readDecimal()); } public void readRefFuturesConId() throws IOException { @@ -631,7 +630,13 @@ public void readRefFuturesConId() throws IOException { } public void readAutoCancelParent() throws IOException { - m_order.autoCancelParent(m_eDecoder.readBoolFromInt()); + readAutoCancelParent(EClient.MIN_VERSION); + } + + public void readAutoCancelParent(int minVersionAutoCancelParent) throws IOException { + if (m_serverVersion >= minVersionAutoCancelParent) { + m_order.autoCancelParent(m_eDecoder.readBoolFromInt()); + } } public void readShareholder() throws IOException { @@ -663,4 +668,26 @@ public void readUsePriceMgmtAlgo() throws IOException { m_order.usePriceMgmtAlgo(m_eDecoder.readBoolFromInt()); } } + + public void readDuration() throws IOException { + if (m_serverVersion >= EClient.MIN_SERVER_VER_DURATION) { + m_order.duration(m_eDecoder.readInt()); + } + } + + public void readPostToAts() throws IOException { + if (m_serverVersion >= EClient.MIN_SERVER_VER_POST_TO_ATS) { + m_order.postToAts(m_eDecoder.readIntMax()); + } + } + + public void readPegBestPegMidOrderAttributes() throws IOException { + if (m_serverVersion >= EClient.MIN_SERVER_VER_PEGBEST_PEGMID_OFFSETS) { + m_order.minTradeQty(m_eDecoder.readIntMax()); + m_order.minCompeteSize(m_eDecoder.readIntMax()); + m_order.competeAgainstBestOffset(m_eDecoder.readDoubleMax()); + m_order.midOffsetAtWhole(m_eDecoder.readDoubleMax()); + m_order.midOffsetAtHalf(m_eDecoder.readDoubleMax()); + } + } } diff --git a/ref/client/EReader.java b/ref/client/EReader.java index 95f5c090..921d1a20 100644 --- a/ref/client/EReader.java +++ b/ref/client/EReader.java @@ -62,7 +62,7 @@ public void run() { //if (parent().isConnected()) { if( ex instanceof EOFException ) { eWrapper().error(EClientErrors.NO_VALID_ID, EClientErrors.BAD_LENGTH.code(), - EClientErrors.BAD_LENGTH.msg() + " " + ex.getMessage()); + EClientErrors.BAD_LENGTH.msg() + " " + ex.getMessage(), null); } else { eWrapper().error( ex); @@ -116,7 +116,17 @@ public void processMsgs() throws IOException { private EMessage readSingleMessage() throws IOException { if (isUseV100Plus()) { - int msgSize = m_clientSocket.readInt(); + int msgSize = 0; + try { + msgSize = m_clientSocket.readInt(); + } + catch (Exception ex) { + if (ex instanceof EOFException) { + parent().connectionError(); + parent().eDisconnect(); + } + return null; + } if (msgSize > MAX_MSG_LENGTH) { throw new InvalidMessageLengthException("message is too long: " diff --git a/ref/client/EWrapper.java b/ref/client/EWrapper.java index e248526a..4d865f1c 100644 --- a/ref/client/EWrapper.java +++ b/ref/client/EWrapper.java @@ -13,8 +13,8 @@ public interface EWrapper { // Interface methods /////////////////////////////////////////////////////////////////////// void tickPrice( int tickerId, int field, double price, TickAttrib attrib); - void tickSize( int tickerId, int field, int size); - void tickOptionComputation( int tickerId, int field, double impliedVol, + void tickSize( int tickerId, int field, Decimal size); + void tickOptionComputation( int tickerId, int field, int tickAttrib, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice); void tickGeneric(int tickerId, int tickType, double value); @@ -22,13 +22,13 @@ void tickOptionComputation( int tickerId, int field, double impliedVol, void tickEFP(int tickerId, int tickType, double basisPoints, String formattedBasisPoints, double impliedFuture, int holdDays, String futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate); - void orderStatus( int orderId, String status, double filled, double remaining, + void orderStatus( int orderId, String status, Decimal filled, Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice); void openOrder( int orderId, Contract contract, Order order, OrderState orderState); void openOrderEnd(); void updateAccountValue(String key, String value, String currency, String accountName); - void updatePortfolio(Contract contract, double position, double marketPrice, double marketValue, + void updatePortfolio(Contract contract, Decimal position, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String accountName); void updateAccountTime(String timeStamp); void accountDownloadEnd(String accountName); @@ -38,9 +38,9 @@ void updatePortfolio(Contract contract, double position, double marketPrice, dou void contractDetailsEnd(int reqId); void execDetails( int reqId, Contract contract, Execution execution); void execDetailsEnd( int reqId); - void updateMktDepth( int tickerId, int position, int operation, int side, double price, int size); + void updateMktDepth( int tickerId, int position, int operation, int side, double price, Decimal size); void updateMktDepthL2( int tickerId, int position, String marketMaker, int operation, - int side, double price, int size, boolean isSmartDepth); + int side, double price, Decimal size, boolean isSmartDepth); void updateNewsBulletin( int msgId, int msgType, String message, String origExchange); void managedAccounts( String accountsList); void receiveFA(int faDataType, String xml); @@ -49,14 +49,14 @@ void updateMktDepthL2( int tickerId, int position, String marketMaker, int opera void scannerData(int reqId, int rank, ContractDetails contractDetails, String distance, String benchmark, String projection, String legsStr); void scannerDataEnd(int reqId); - void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume, double wap, int count); + void realtimeBar(int reqId, long time, double open, double high, double low, double close, Decimal volume, Decimal wap, int count); void currentTime(long time); void fundamentalData(int reqId, String data); void deltaNeutralValidation(int reqId, DeltaNeutralContract deltaNeutralContract); void tickSnapshotEnd(int reqId); void marketDataType(int reqId, int marketDataType); void commissionReport(CommissionReport commissionReport); - void position(String account, Contract contract, double pos, double avgCost); + void position(String account, Contract contract, Decimal pos, double avgCost); void positionEnd(); void accountSummary(int reqId, String account, String tag, String value, String currency); void accountSummaryEnd(int reqId); @@ -68,10 +68,10 @@ void scannerData(int reqId, int rank, ContractDetails contractDetails, String di void displayGroupUpdated( int reqId, String contractInfo); void error( Exception e); void error( String str); - void error(int id, int errorCode, String errorMsg); + void error(int id, int errorCode, String errorMsg, String advancedOrderRejectJson); void connectionClosed(); void connectAck(); - void positionMulti( int reqId, String account, String modelCode, Contract contract, double pos, double avgCost); + void positionMulti( int reqId, String account, String modelCode, Contract contract, Decimal pos, double avgCost); void positionMultiEnd( int reqId); void accountUpdateMulti( int reqId, String account, String modelCode, String key, String value, String currency); void accountUpdateMultiEnd( int reqId); @@ -96,15 +96,20 @@ void scannerData(int reqId, int rank, ContractDetails contractDetails, String di void rerouteMktDepthReq(int reqId, int conId, String exchange); void marketRule(int marketRuleId, PriceIncrement[] priceIncrements); void pnl(int reqId, double dailyPnL, double unrealizedPnL, double realizedPnL); - void pnlSingle(int reqId, int pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value); + void pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value); void historicalTicks(int reqId, List ticks, boolean done); void historicalTicksBidAsk(int reqId, List ticks, boolean done); void historicalTicksLast(int reqId, List ticks, boolean done); - void tickByTickAllLast(int reqId, int tickType, long time, double price, int size, TickAttribLast tickAttribLast, String exchange, String specialConditions); - void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, int bidSize, int askSize, TickAttribBidAsk tickAttribBidAsk); + void tickByTickAllLast(int reqId, int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions); + void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, Decimal bidSize, Decimal askSize, TickAttribBidAsk tickAttribBidAsk); void tickByTickMidPoint(int reqId, long time, double midPoint); void orderBound(long orderId, int apiClientId, int apiOrderId); void completedOrder(Contract contract, Order order, OrderState orderState); void completedOrdersEnd(); + void replaceFAEnd(int reqId, String text); + void wshMetaData(int reqId, String dataJson); + void wshEventData(int reqId, String dataJson); + void historicalSchedule(int reqId, String startDateTime, String endDateTime, String timeZone, List sessions); + void userInfo(int reqId, String whiteBrandingId); } diff --git a/ref/client/EWrapperMsgGenerator.java b/ref/client/EWrapperMsgGenerator.java index 9328e16c..51aca5f7 100644 --- a/ref/client/EWrapperMsgGenerator.java +++ b/ref/client/EWrapperMsgGenerator.java @@ -3,10 +3,7 @@ package com.ib.client; -import static com.ib.controller.Formats.fmt; - import java.text.DateFormat; -import java.text.DecimalFormat; import java.util.Date; import java.util.List; import java.util.Map; @@ -18,31 +15,32 @@ public class EWrapperMsgGenerator { public static final String FINANCIAL_ADVISOR = "FA:"; public static String tickPrice( int tickerId, int field, double price, TickAttrib attribs) { - return "id=" + tickerId + " " + TickType.getField( field) + "=" + price + " " + + return "id=" + tickerId + " " + TickType.getField( field) + "=" + Util.DoubleMaxString(price) + " " + (attribs.canAutoExecute() ? " canAutoExecute" : " noAutoExecute") + " pastLimit = " + attribs.pastLimit() + (field == TickType.BID.index() || field == TickType.ASK.index() ? " preOpen = " + attribs.preOpen() : ""); } - public static String tickSize( int tickerId, int field, int size) { + public static String tickSize( int tickerId, int field, Decimal size) { return "id=" + tickerId + " " + TickType.getField( field) + "=" + size; } - public static String tickOptionComputation( int tickerId, int field, double impliedVol, + public static String tickOptionComputation( int tickerId, int field, int tickAttrib, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { - return "id=" + tickerId + " " + TickType.getField( field) + - ": impliedVol = " + Util.maxDoubleToString(impliedVol) + - " delta = " + Util.maxDoubleToString(delta) + - " gamma = " + Util.maxDoubleToString(gamma) + - " vega = " + Util.maxDoubleToString(vega) + - " theta = " + Util.maxDoubleToString(theta) + - " optPrice = " + Util.maxDoubleToString(optPrice) + - " pvDividend = " + Util.maxDoubleToString(pvDividend) + - " undPrice = " + Util.maxDoubleToString(undPrice); + return "id=" + tickerId + " " + TickType.getField( field) + + ": tickAttrib = " + Util.IntMaxString(tickAttrib) + + " impliedVol = " + Util.DoubleMaxString(impliedVol, "N/A") + + " delta = " + Util.DoubleMaxString(delta, "N/A") + + " gamma = " + Util.DoubleMaxString(gamma, "N/A") + + " vega = " + Util.DoubleMaxString(vega, "N/A") + + " theta = " + Util.DoubleMaxString(theta, "N/A") + + " optPrice = " + Util.DoubleMaxString(optPrice, "N/A") + + " pvDividend = " + Util.DoubleMaxString(pvDividend, "N/A") + + " undPrice = " + Util.DoubleMaxString(undPrice, "N/A"); } public static String tickGeneric(int tickerId, int tickType, double value) { - return "id=" + tickerId + " " + TickType.getField( tickType) + "=" + value; + return "id=" + tickerId + " " + TickType.getField( tickType) + "=" + Util.DoubleMaxString(value); } public static String tickString(int tickerId, int tickType, String value) { @@ -53,19 +51,19 @@ public static String tickEFP(int tickerId, int tickType, double basisPoints, String formattedBasisPoints, double impliedFuture, int holdDays, String futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate) { return "id=" + tickerId + " " + TickType.getField(tickType) - + ": basisPoints = " + basisPoints + "/" + formattedBasisPoints - + " impliedFuture = " + impliedFuture + " holdDays = " + holdDays + - " futureLastTradeDate = " + futureLastTradeDate + " dividendImpact = " + dividendImpact + - " dividends to expiry = " + dividendsToLastTradeDate; + + ": basisPoints = " + Util.DoubleMaxString(basisPoints) + "/" + formattedBasisPoints + + " impliedFuture = " + Util.DoubleMaxString(impliedFuture) + " holdDays = " + Util.IntMaxString(holdDays) + + " futureLastTradeDate = " + futureLastTradeDate + " dividendImpact = " + Util.DoubleMaxString(dividendImpact) + + " dividends to expiry = " + Util.DoubleMaxString(dividendsToLastTradeDate); } - public static String orderStatus( int orderId, String status, double filled, double remaining, + public static String orderStatus( int orderId, String status, Decimal filled, Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice) { - return "order status: orderId=" + orderId + " clientId=" + clientId + " permId=" + permId + + return "order status: orderId=" + orderId + " clientId=" + Util.IntMaxString(clientId) + " permId=" + Util.IntMaxString(permId) + " status=" + status + " filled=" + filled + " remaining=" + remaining + - " avgFillPrice=" + avgFillPrice + " lastFillPrice=" + lastFillPrice + - " parent Id=" + parentId + " whyHeld=" + whyHeld + " mktCapPrice=" + mktCapPrice; + " avgFillPrice=" + Util.DoubleMaxString(avgFillPrice) + " lastFillPrice=" + Util.DoubleMaxString(lastFillPrice) + + " parent Id=" + Util.IntMaxString(parentId) + " whyHeld=" + whyHeld + " mktCapPrice=" + Util.DoubleMaxString(mktCapPrice); } public static String openOrder( int orderId, Contract contract, Order order, OrderState orderState) { @@ -83,12 +81,14 @@ public static String updateAccountValue(String key, String value, String currenc return "updateAccountValue: " + key + " " + value + " " + currency + " " + accountName; } - public static String updatePortfolio(Contract contract, double position, double marketPrice, + public static String updatePortfolio(Contract contract, Decimal position, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String accountName) { return "updatePortfolio: " + contractMsg(contract) - + position + " " + marketPrice + " " + marketValue + " " + averageCost + " " + unrealizedPNL + " " + realizedPNL + " " + accountName; + + position + " " + Util.DoubleMaxString(marketPrice) + " " + Util.DoubleMaxString(marketValue) + " " + + Util.DoubleMaxString(averageCost) + " " + Util.DoubleMaxString(unrealizedPNL) + " " + + Util.DoubleMaxString(realizedPNL) + " " + accountName; } public static String updateAccountTime(String timeStamp) { @@ -113,11 +113,11 @@ public static String contractDetails(int reqId, ContractDetails contractDetails) private static String contractDetailsMsg(ContractDetails contractDetails) { return "marketName = " + contractDetails.marketName() + "\n" - + "minTick = " + contractDetails.minTick() + "\n" - + "price magnifier = " + contractDetails.priceMagnifier() + "\n" + + "minTick = " + Util.DoubleMaxString(contractDetails.minTick()) + "\n" + + "price magnifier = " + Util.IntMaxString(contractDetails.priceMagnifier()) + "\n" + "orderTypes = " + contractDetails.orderTypes() + "\n" + "validExchanges = " + contractDetails.validExchanges() + "\n" - + "underConId = " + contractDetails.underConid() + "\n" + + "underConId = " + Util.IntMaxString(contractDetails.underConid()) + "\n" + "longName = " + contractDetails.longName() + "\n" + "contractMonth = " + contractDetails.contractMonth() + "\n" + "industry = " + contractDetails.industry() + "\n" @@ -127,14 +127,17 @@ private static String contractDetailsMsg(ContractDetails contractDetails) { + "tradingHours = " + contractDetails.tradingHours() + "\n" + "liquidHours = " + contractDetails.liquidHours() + "\n" + "evRule = " + contractDetails.evRule() + "\n" - + "evMultiplier = " + contractDetails.evMultiplier() + "\n" - + "mdSizeMultiplier = " + contractDetails.mdSizeMultiplier() + "\n" - + "aggGroup = " + contractDetails.aggGroup() + "\n" + + "evMultiplier = " + Util.DoubleMaxString(contractDetails.evMultiplier()) + "\n" + + "aggGroup = " + Util.IntMaxString(contractDetails.aggGroup()) + "\n" + "underSymbol = " + contractDetails.underSymbol() + "\n" + "underSecType = " + contractDetails.underSecType() + "\n" + "marketRuleIds = " + contractDetails.marketRuleIds() + "\n" + "realExpirationDate = " + contractDetails.realExpirationDate() + "\n" + "lastTradeTime = " + contractDetails.lastTradeTime() + "\n" + + "stockType = " + contractDetails.stockType() + "\n" + + "minSize = " + contractDetails.minSize() + "\n" + + "sizeIncrement = " + contractDetails.sizeIncrement() + "\n" + + "suggestedSizeIncrement = " + contractDetails.suggestedSizeIncrement() + "\n" + contractDetailsSecIdList(contractDetails); } @@ -143,7 +146,7 @@ private static String contractMsg(Contract contract) { + "symbol = " + contract.symbol() + "\n" + "secType = " + contract.getSecType() + "\n" + "lastTradeDate = " + contract.lastTradeDateOrContractMonth() + "\n" - + "strike = " + contract.strike() + "\n" + + "strike = " + Util.DoubleMaxString(contract.strike()) + "\n" + "right = " + contract.getRight() + "\n" + "multiplier = " + contract.multiplier() + "\n" + "exchange = " + contract.exchange() + "\n" @@ -160,7 +163,7 @@ public static String bondContractDetails(int reqId, ContractDetails contractDeta + "symbol = " + contract.symbol() + "\n" + "secType = " + contract.getSecType() + "\n" + "cusip = " + contractDetails.cusip() + "\n" - + "coupon = " + contractDetails.coupon() + "\n" + + "coupon = " + Util.DoubleMaxString(contractDetails.coupon()) + "\n" + "maturity = " + contractDetails.maturity() + "\n" + "issueDate = " + contractDetails.issueDate() + "\n" + "ratings = " + contractDetails.ratings() + "\n" @@ -175,7 +178,7 @@ public static String bondContractDetails(int reqId, ContractDetails contractDeta + "marketName = " + contractDetails.marketName() + "\n" + "tradingClass = " + contract.tradingClass() + "\n" + "conid = " + contract.conid() + "\n" - + "minTick = " + contractDetails.minTick() + "\n" + + "minTick = " + Util.DoubleMaxString(contractDetails.minTick()) + "\n" + "orderTypes = " + contractDetails.orderTypes() + "\n" + "validExchanges = " + contractDetails.validExchanges() + "\n" + "nextOptionDate = " + contractDetails.nextOptionDate() + "\n" @@ -184,12 +187,14 @@ public static String bondContractDetails(int reqId, ContractDetails contractDeta + "notes = " + contractDetails.notes() + "\n" + "longName = " + contractDetails.longName() + "\n" + "evRule = " + contractDetails.evRule() + "\n" - + "evMultiplier = " + contractDetails.evMultiplier() + "\n" - + "mdSizeMultiplier = " + contractDetails.mdSizeMultiplier() + "\n" - + "aggGroup = " + contractDetails.aggGroup() + "\n" + + "evMultiplier = " + Util.DoubleMaxString(contractDetails.evMultiplier()) + "\n" + + "aggGroup = " + Util.IntMaxString(contractDetails.aggGroup()) + "\n" + "marketRuleIds = " + contractDetails.marketRuleIds() + "\n" + "timeZoneId = " + contractDetails.timeZoneId() + "\n" + "lastTradeTime = " + contractDetails.lastTradeTime() + "\n" + + "minSize = " + contractDetails.minSize() + "\n" + + "sizeIncrement = " + contractDetails.sizeIncrement() + "\n" + + "suggestedSizeIncrement = " + contractDetails.suggestedSizeIncrement() + "\n" + contractDetailsSecIdList(contractDetails) + " ---- Bond Contract Details End ----\n"; } @@ -217,7 +222,7 @@ public static String execDetails( int reqId, Contract contract, Execution execut return " ---- Execution Details begin ----\n" + "reqId = " + reqId + "\n" + "orderId = " + execution.orderId() + "\n" - + "clientId = " + execution.clientId() + "\n" + + "clientId = " + Util.IntMaxString(execution.clientId()) + "\n" + contractMsg(contract) + "execId = " + execution.execId() + "\n" + "time = " + execution.time() + "\n" @@ -225,14 +230,14 @@ public static String execDetails( int reqId, Contract contract, Execution execut + "executionExchange = " + execution.exchange() + "\n" + "side = " + execution.side() + "\n" + "shares = " + execution.shares() + "\n" - + "price = " + execution.price() + "\n" - + "permId = " + execution.permId() + "\n" - + "liquidation = " + execution.liquidation() + "\n" + + "price = " + Util.DoubleMaxString(execution.price()) + "\n" + + "permId = " + Util.IntMaxString(execution.permId()) + "\n" + + "liquidation = " + Util.IntMaxString(execution.liquidation()) + "\n" + "cumQty = " + execution.cumQty() + "\n" - + "avgPrice = " + execution.avgPrice() + "\n" + + "avgPrice = " + Util.DoubleMaxString(execution.avgPrice()) + "\n" + "orderRef = " + execution.orderRef() + "\n" + "evRule = " + execution.evRule() + "\n" - + "evMultiplier = " + execution.evMultiplier() + "\n" + + "evMultiplier = " + Util.DoubleMaxString(execution.evMultiplier()) + "\n" + "modelCode = " + execution.modelCode() + "\n" + "lastLiquidity = " + execution.lastLiquidity() + "\n" + " ---- Execution Details end ----\n"; @@ -243,17 +248,17 @@ public static String execDetailsEnd(int reqId) { } public static String updateMktDepth( int tickerId, int position, int operation, int side, - double price, int size) { - return "updateMktDepth: " + tickerId + " " + position + " " + operation + " " + side + " " + price + " " + size; + double price, Decimal size) { + return "updateMktDepth: " + tickerId + " " + position + " " + operation + " " + side + " " + Util.DoubleMaxString(price) + " " + size; } public static String updateMktDepthL2( int tickerId, int position, String marketMaker, - int operation, int side, double price, int size, boolean isSmartDepth) { - return "updateMktDepth: " + tickerId + " " + position + " " + marketMaker + " " + operation + " " + side + " " + price + " " + size + " " + isSmartDepth; + int operation, int side, double price, Decimal size, boolean isSmartDepth) { + return "updateMktDepth: " + tickerId + " " + position + " " + marketMaker + " " + operation + " " + side + " " + Util.DoubleMaxString(price) + " " + size + " " + isSmartDepth; } public static String updateNewsBulletin( int msgId, int msgType, String message, String origExchange) { - return "MsgId=" + msgId + " :: MsgType=" + msgType + " :: Origin=" + origExchange + " :: Message=" + message; + return "MsgId=" + msgId + " :: MsgType=" + Util.IntMaxString(msgType) + " :: Origin=" + origExchange + " :: Message=" + message; } public static String managedAccounts( String accountsList) { @@ -265,15 +270,15 @@ public static String receiveFA(int faDataType, String xml) { } public static String historicalData(int reqId, String date, double open, double high, double low, - double close, long volume, int count, double WAP) { + double close, Decimal volume, int count, Decimal WAP) { return "id=" + reqId + " date = " + date + - " open=" + open + - " high=" + high + - " low=" + low + - " close=" + close + + " open=" + Util.DoubleMaxString(open) + + " high=" + Util.DoubleMaxString(high) + + " low=" + Util.DoubleMaxString(low) + + " close=" + Util.DoubleMaxString(close) + " volume=" + volume + - " count=" + count + + " count=" + Util.IntMaxString(count) + " WAP=" + WAP; } public static String historicalDataEnd(int reqId, String startDate, String endDate) { @@ -283,15 +288,15 @@ public static String historicalDataEnd(int reqId, String startDate, String endDa } public static String realtimeBar(int reqId, long time, double open, - double high, double low, double close, long volume, double wap, int count) { + double high, double low, double close, Decimal volume, Decimal wap, int count) { return "id=" + reqId + - " time = " + time + - " open=" + open + - " high=" + high + - " low=" + low + - " close=" + close + + " time = " + Util.LongMaxString(time) + + " open=" + Util.DoubleMaxString(open) + + " high=" + Util.DoubleMaxString(high) + + " low=" + Util.DoubleMaxString(low) + + " close=" + Util.DoubleMaxString(close) + " volume=" + volume + - " count=" + count + + " count=" + Util.IntMaxString(count) + " WAP=" + wap; } @@ -304,11 +309,11 @@ public static String scannerData(int reqId, int rank, ContractDetails contractDe String legsStr) { Contract contract = contractDetails.contract(); return "id = " + reqId + - " rank=" + rank + + " rank=" + Util.IntMaxString(rank) + " symbol=" + contract.symbol() + " secType=" + contract.getSecType() + " lastTradeDate=" + contract.lastTradeDateOrContractMonth() + - " strike=" + contract.strike() + + " strike=" + Util.DoubleMaxString(contract.strike()) + " right=" + contract.getRight() + " exchange=" + contract.exchange() + " currency=" + contract.currency() + @@ -337,8 +342,8 @@ public static String fundamentalData(int reqId, String data) { public static String deltaNeutralValidation(int reqId, DeltaNeutralContract deltaNeutralContract) { return "id = " + reqId + " deltaNeutralContract.conId =" + deltaNeutralContract.conid() - + " deltaNeutralContract.delta =" + deltaNeutralContract.delta() - + " deltaNeutralContract.price =" + deltaNeutralContract.price(); + + " deltaNeutralContract.delta =" + Util.DoubleMaxString(deltaNeutralContract.delta()) + + " deltaNeutralContract.price =" + Util.DoubleMaxString(deltaNeutralContract.price()); } public static String tickSnapshotEnd(int tickerId) { return "id=" + tickerId + " =============== end ==============="; @@ -358,11 +363,11 @@ public static String commissionReport( CommissionReport commissionReport) { " yieldRedemptionDate=" + Util.IntMaxString(commissionReport.yieldRedemptionDate()); } - public static String position( String account, Contract contract, double pos, double avgCost) { + public static String position( String account, Contract contract, Decimal pos, double avgCost) { return " ---- Position begin ----\n" + "account = " + account + "\n" + contractMsg(contract) - + "position = " + Util.DoubleMaxString(pos) + "\n" + + "position = " + pos + "\n" + "avgCost = " + Util.DoubleMaxString(avgCost) + "\n" + " ---- Position end ----\n"; } @@ -385,13 +390,13 @@ public static String accountSummaryEnd( int reqId) { return "id=" + reqId + " =============== end ==============="; } - public static String positionMulti( int reqId, String account, String modelCode, Contract contract, double pos, double avgCost) { + public static String positionMulti( int reqId, String account, String modelCode, Contract contract, Decimal pos, double avgCost) { return " ---- Position begin ----\n" + "id = " + reqId + "\n" + "account = " + account + "\n" + "modelCode = " + modelCode + "\n" + contractMsg(contract) - + "position = " + Util.DoubleMaxString(pos) + "\n" + + "position = " + pos + "\n" + "avgCost = " + Util.DoubleMaxString(avgCost) + "\n" + " ---- Position end ----\n"; } @@ -423,7 +428,7 @@ public static String securityDefinitionOptionalParameter(int reqId, String excha } sb.append(" strikes: "); for (Double strike : strikes) { - sb.append(strike).append(", "); + sb.append(Util.DoubleMaxString(strike)).append(", "); } return sb.toString(); } @@ -473,6 +478,8 @@ public static String symbolSamples(int reqId, ContractDescription[] contractDesc sb.append(contractDescriptions[i].derivativeSecTypes()[j]).append(' '); } sb.append("\n"); + sb.append("description: ").append(Util.NormalizeString(contractDescriptions[i].contract().description())).append("\n"); + sb.append("issuerId: ").append(Util.NormalizeString(contractDescriptions[i].contract().issuerId())).append("\n"); sb.append("---- Contract Description End (").append(i).append(") ----\n"); } sb.append("==== Symbol Samples End (total=").append(contractDescriptions.length).append(") reqId: ").append(reqId).append(" ====\n"); @@ -488,15 +495,14 @@ public static String mktDepthExchanges(DepthMktDataDescription[] depthMktDataDes .append(", secType: ").append(depthMktDataDescriptions[i].secType()) .append(", listingExch: ").append(depthMktDataDescriptions[i].listingExch()) .append(", serviceDataType: ").append(depthMktDataDescriptions[i].serviceDataType()) - .append(", aggGroup: ").append(depthMktDataDescriptions[i].aggGroup() != Integer.MAX_VALUE ? - depthMktDataDescriptions[i].aggGroup() : "").append("\n"); + .append(", aggGroup: ").append(Util.IntMaxString(depthMktDataDescriptions[i].aggGroup())).append("\n"); } sb.append("==== Market Depth Exchanges End (total=").append(depthMktDataDescriptions.length).append(") ====\n"); return sb.toString(); } public static String tickNews(int tickerId, long timeStamp, String providerCode, String articleId, String headline, String extraData) { - return "TickNews. tickerId: " + tickerId + ", timeStamp: " + Util.UnixMillisecondsToString(timeStamp, "yyyy-MM-dd HH:mm:ss zzz") + + return "TickNews. tickerId: " + tickerId + ", timeStamp: " + Util.UnixMillisecondsToString(timeStamp, "yyyyMMdd-HH:mm:ss") + ", providerCode: " + providerCode + ", articleId: " + articleId + ", headline: " + headline + ", extraData: " + extraData; } @@ -515,8 +521,12 @@ public static String newsProviders(NewsProvider[] newsProviders) { public static String error( Exception ex) { return "Error - " + ex;} public static String error( String str) { return str;} - public static String error(int id, int errorCode, String errorMsg) { - return id + " | " + errorCode + " | " + errorMsg; + public static String error(int id, int errorCode, String errorMsg, String advancedOrderRejectJson) { + String ret = id + " | " + errorCode + " | " + errorMsg; + if (advancedOrderRejectJson != null) { + ret += (" | " + advancedOrderRejectJson); + } + return ret; } public static String connectionClosed() { @@ -538,7 +548,7 @@ public static String softDollarTiers(SoftDollarTier[] tiers) { } public static String tickReqParams(int tickerId, double minTick, String bboExchange, int snapshotPermissions) { - return "id=" + tickerId + " minTick = " + minTick + " bboExchange = " + bboExchange + " snapshotPermissions = " + snapshotPermissions; + return "id=" + tickerId + " minTick = " + Util.DoubleMaxString(minTick) + " bboExchange = " + bboExchange + " snapshotPermissions = " + Util.IntMaxString(snapshotPermissions); } public static String smartComponents(int reqId, Map> theMap) { @@ -585,7 +595,7 @@ public static String headTimestamp(int reqId, String headTimestamp) { public static String histogramData(int reqId, List items) { StringBuilder sb = new StringBuilder(); sb.append("Histogram data. Req Id: ").append(reqId).append(", Data (").append(items.size()).append("):\n"); - items.forEach(i -> sb.append("\tPrice: ").append(i.price).append(", Size: ").append(i.size).append("\n")); + items.forEach(i -> sb.append("\tPrice: ").append(Util.DoubleMaxString(i.price())).append(", Size: ").append(i.size()).append("\n")); return sb.toString(); } @@ -598,13 +608,11 @@ public static String rerouteMktDepthReq(int reqId, int conId, String exchange) { } public static String marketRule(int marketRuleId, PriceIncrement[] priceIncrements) { - DecimalFormat df = new DecimalFormat("#.#"); - df.setMaximumFractionDigits(340); StringBuilder sb = new StringBuilder(256); sb.append("==== Market Rule Begin (marketRuleId=").append(marketRuleId).append(") ====\n"); for (PriceIncrement priceIncrement : priceIncrements) { - sb.append("Low Edge: ").append(df.format(priceIncrement.lowEdge())); - sb.append(", Increment: ").append(df.format(priceIncrement.increment())); + sb.append("Low Edge: ").append(Util.DoubleMaxString(priceIncrement.lowEdge())); + sb.append(", Increment: ").append(Util.DoubleMaxString(priceIncrement.increment())); sb.append("\n"); } sb.append("==== Market Rule End (marketRuleId=").append(marketRuleId).append(") ====\n"); @@ -613,53 +621,53 @@ public static String marketRule(int marketRuleId, PriceIncrement[] priceIncremen public static String pnl(int reqId, double dailyPnL, double unrealizedPnL, double realizedPnL) { - return "Daily PnL. Req Id: " + reqId + ", daily PnL: " + dailyPnL + ", unrealizedPnL: " + unrealizedPnL + ", realizedPnL: " + realizedPnL; + return "Daily PnL. Req Id: " + reqId + ", daily PnL: " + Util.DoubleMaxString(dailyPnL) + ", unrealizedPnL: " + Util.DoubleMaxString(unrealizedPnL) + ", realizedPnL: " + Util.DoubleMaxString(realizedPnL); } - public static String pnlSingle(int reqId, int pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { - return "Daily PnL Single. Req Id: " + reqId + ", pos: " + pos + ", daily PnL: " + dailyPnL + ", unrealizedPnL: " + unrealizedPnL + ", realizedPnL: " + realizedPnL + ", value: " + value; + public static String pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { + return "Daily PnL Single. Req Id: " + reqId + ", pos: " + pos + ", daily PnL: " + Util.DoubleMaxString(dailyPnL) + ", unrealizedPnL: " + Util.DoubleMaxString(unrealizedPnL) + ", realizedPnL: " + Util.DoubleMaxString(realizedPnL) + ", value: " + Util.DoubleMaxString(value); } - public static String historicalTick(int reqId, long time, double price, long size) { - return "Historical Tick. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + ", price: " + price + ", size: " + public static String historicalTick(int reqId, long time, double price, Decimal size) { + return "Historical Tick. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + ", price: " + Util.DoubleMaxString(price) + ", size: " + size; } public static String historicalTickBidAsk(int reqId, long time, TickAttribBidAsk tickAttribBidAsk, double priceBid, double priceAsk, - long sizeBid, long sizeAsk) { - return "Historical Tick Bid/Ask. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + ", bid price: " + priceBid - + ", ask price: " + priceAsk + ", bid size: " + sizeBid + ", ask size: " + sizeAsk + Decimal sizeBid, Decimal sizeAsk) { + return "Historical Tick Bid/Ask. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + ", bid price: " + Util.DoubleMaxString(priceBid) + + ", ask price: " + Util.DoubleMaxString(priceAsk) + ", bid size: " + sizeBid + ", ask size: " + sizeAsk + ", tick attribs: " + (tickAttribBidAsk.bidPastLow() ? "bidPastLow " : "") + (tickAttribBidAsk.askPastHigh() ? "askPastHigh " : ""); } - public static String historicalTickLast(int reqId, long time, TickAttribLast tickAttribLast, double price, long size, String exchange, + public static String historicalTickLast(int reqId, long time, TickAttribLast tickAttribLast, double price, Decimal size, String exchange, String specialConditions) { - return "Historical Tick Last. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + ", price: " + price + ", size: " + return "Historical Tick Last. Req Id: " + reqId + ", time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + ", price: " + Util.DoubleMaxString(price) + ", size: " + size + ", exchange: " + exchange + ", special conditions:" + specialConditions + ", tick attribs: " + (tickAttribLast.pastLimit() ? "pastLimit " : "") + (tickAttribLast.unreported() ? "unreported " : ""); } - public static String tickByTickAllLast(int reqId, int tickType, long time, double price, int size, TickAttribLast tickAttribLast, + public static String tickByTickAllLast(int reqId, int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions){ return (tickType == 1 ? "Last." : "AllLast.") + - " Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + " Price: " + price + " Size: " + size + + " Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + " Price: " + Util.DoubleMaxString(price) + " Size: " + size + " Exch: " + exchange + " Spec Cond: " + specialConditions + " Tick Attibs: " + (tickAttribLast.pastLimit() ? "pastLimit " : "") + (tickType == 1 ? "" : (tickAttribLast.unreported() ? "unreported " : "")); } - public static String tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, int bidSize, int askSize, + public static String tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, Decimal bidSize, Decimal askSize, TickAttribBidAsk tickAttribBidAsk){ - return "BidAsk. Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + " BidPrice: " + bidPrice + - " AskPrice: " + askPrice + " BidSize: " + bidSize + " AskSize: " + askSize + " Tick Attibs: " + + return "BidAsk. Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + " BidPrice: " + Util.DoubleMaxString(bidPrice) + + " AskPrice: " + Util.DoubleMaxString(askPrice) + " BidSize: " + bidSize + " AskSize: " + askSize + " Tick Attibs: " + (tickAttribBidAsk.bidPastLow() ? "bidPastLow " : "") + (tickAttribBidAsk.askPastHigh() ? "askPastHigh " : ""); } public static String tickByTickMidPoint(int reqId, long time, double midPoint){ - return "MidPoint. Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss zzz") + " MidPoint: " + midPoint; + return "MidPoint. Req Id: " + reqId + " Time: " + Util.UnixSecondsToString(time, "yyyyMMdd-HH:mm:ss") + " MidPoint: " + Util.DoubleMaxString(midPoint); } public static String orderBound(long orderId, int apiClientId, int apiOrderId){ - return "order bound: orderId=" + apiOrderId + " clientId=" + apiClientId + " permId=" + orderId; + return "order bound: apiOrderId=" + Util.IntMaxString(apiOrderId) + " apiClientId=" + Util.IntMaxString(apiClientId) + " permId=" + Util.LongMaxString(orderId); } public static String completedOrder( Contract contract, Order order, OrderState orderState) { @@ -673,11 +681,46 @@ public static String completedOrdersEnd() { return "=============== end ==============="; } + public static String replaceFAEnd(int reqId, String text) { + return "id = " + reqId + " ===== " + text + " ====="; + } + + public static String wshMetaData(int reqId, String dataJson) { + return "wshMetaData. id = " + reqId + " dataJson= " + dataJson; + } + + public static String wshEventData(int reqId, String dataJson) { + return "wshEventData. id = " + reqId + " dataJson= " + dataJson; + } + + public static String historicalSchedule(int reqId, String startDateTime, String endDateTime, String timeZone, List sessions) { + StringBuilder sb = new StringBuilder(); + sb.append("==== Historical Schedule Begin (ReqId=").append(reqId).append(") ====\n"); + sb.append("Start: ").append(startDateTime); + sb.append(" End: ").append(endDateTime); + sb.append(" Time Zone: ").append(timeZone); + sb.append("\n"); + + for (HistoricalSession session: sessions) { + sb.append("Session: "); + sb.append("Start: ").append(session.startDateTime()); + sb.append(" End: ").append(session.endDateTime()); + sb.append(" Ref Date: ").append(session.refDate()); + sb.append("\n"); + } + sb.append("==== Historical Schedule End (ReqId=").append(reqId).append(") ====\n"); + return sb.toString(); + } + + public static String userInfo(int reqId, String whiteBrandingId) { + return "UserInfo. Req Id: " + reqId + " White Branding Id: " + whiteBrandingId; + } + private static void appendOrderFields(StringBuilder sb, int orderId, Contract contract, Order order, OrderState orderState, boolean isOpenOrder) { Util.appendValidIntValue(sb, "orderId", orderId); Util.appendNonEmptyString(sb, "action", order.getAction()); - Util.appendPositiveDoubleValue(sb, "quantity", order.totalQuantity()); + Util.appendNonEmptyString(sb, "quantity", order.totalQuantity().toString()); Util.appendPositiveDoubleValue(sb, "cashQty", order.cashQty()); Util.appendPositiveIntValue(sb, "conid", contract.conid()); Util.appendNonEmptyString(sb, "symbol", contract.symbol()); @@ -725,9 +768,6 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co Util.appendBooleanFlag(sb, "allOrNone", order.allOrNone()); Util.appendValidIntValue(sb, "minQty", order.minQty()); Util.appendValidDoubleValue(sb, "percentOffset", order.percentOffset()); - Util.appendBooleanFlag(sb, "eTradeOnly", order.eTradeOnly()); - Util.appendBooleanFlag(sb, "firmQuoteOnly", order.firmQuoteOnly()); - Util.appendValidDoubleValue(sb, "nbboPriceCap", order.nbboPriceCap()); Util.appendBooleanFlag(sb, "optOutSmartRouting", order.optOutSmartRouting()); Util.appendValidDoubleValue(sb, "startingPrice", order.startingPrice()); Util.appendValidDoubleValue(sb, "stockRefPrice", order.stockRefPrice()); @@ -865,13 +905,27 @@ private static void appendOrderFields(StringBuilder sb, int orderId, Contract co Util.appendNonEmptyString(sb, "autoCancelDate", order.autoCancelDate()); - Util.appendValidDoubleValue(sb, "filledQuantity", order.filledQuantity()); + Util.appendNonEmptyString(sb, "filledQuantity", order.filledQuantity().toString()); Util.appendPositiveIntValue(sb, "refFuturesConId", order.refFuturesConId()); Util.appendBooleanFlag(sb, "autoCancelParent", order.autoCancelParent()); Util.appendNonEmptyString(sb, "shareholder", order.shareholder()); Util.appendBooleanFlag(sb, "imbalanceOnly", order.imbalanceOnly()); Util.appendBooleanFlag(sb, "routeMarketableToBbo", order.routeMarketableToBbo()); Util.appendValidLongValue(sb, "parentPermId", order.parentPermId()); + Util.appendValidIntValue(sb, "duration", order.duration()); + Util.appendValidIntValue(sb, "postToAts", order.postToAts()); + + Util.appendValidIntValue(sb, "minTradeQty", order.minTradeQty()); + Util.appendValidIntValue(sb, "minCompeteSize", order.minCompeteSize()); + if (order.competeAgainstBestOffset() != Double.MAX_VALUE) { + if (order.isCompeteAgainstBestOffsetUpToMid()) { + sb.append(Util.SPACE_SYMBOL).append("competeAgainstBestOffsetUpToMid"); + } else { + sb.append(Util.SPACE_SYMBOL).append("competeAgainstBestOffset").append(Util.EQUALS_SIGN).append(order.competeAgainstBestOffset()); + } + } + Util.appendValidDoubleValue(sb, "midOffsetAtWhole", order.midOffsetAtWhole()); + Util.appendValidDoubleValue(sb, "midOffsetAtHalf", order.midOffsetAtHalf()); 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 a6a7501e..cf8c502f 100644 --- a/ref/client/Execution.java +++ b/ref/client/Execution.java @@ -45,11 +45,11 @@ public class Execution { private String m_acctNumber; private String m_exchange; private String m_side; - private double m_shares; + private Decimal m_shares; private double m_price; private int m_permId; private int m_liquidation; - private double m_cumQty; + private Decimal m_cumQty; private double m_avgPrice; private String m_orderRef; private String m_evRule; @@ -65,11 +65,11 @@ public class Execution { public String acctNumber() { return m_acctNumber; } public String exchange() { return m_exchange; } public String side() { return m_side; } - public double shares() { return m_shares; } + public Decimal shares() { return m_shares; } public double price() { return m_price; } public int permId() { return m_permId; } public int liquidation() { return m_liquidation; } - public double cumQty() { return m_cumQty; } + public Decimal cumQty() { return m_cumQty; } public double avgPrice() { return m_avgPrice; } public String orderRef() { return m_orderRef; } public String evRule() { return m_evRule; } @@ -86,11 +86,11 @@ public class Execution { public void acctNumber(String acctNumber) { m_acctNumber = acctNumber; } public void exchange(String exchange) { m_exchange = exchange; } public void side(String side) { m_side = side; } - public void shares(double shares) { m_shares = shares; } + public void shares(Decimal shares) { m_shares = shares; } public void price(double price) { m_price = price; } public void permId(int permId) { m_permId = permId; } public void liquidation(int liquidation) { m_liquidation = liquidation; } - public void cumQty(double cumQty) { m_cumQty = cumQty; } + public void cumQty(Decimal cumQty) { m_cumQty = cumQty; } public void avgPrice(double avgPrice) { m_avgPrice = avgPrice; } public void orderRef(String orderRef) { m_orderRef = orderRef; } public void evRule(String evRule) { m_evRule = evRule; } @@ -101,19 +101,19 @@ public class Execution { public Execution() { m_orderId = 0; m_clientId = 0; - m_shares = 0; + m_shares = Decimal.ZERO; m_price = 0; m_permId = 0; m_liquidation = 0; - m_cumQty = 0; + m_cumQty = Decimal.ZERO; m_avgPrice = 0; m_evMultiplier = 0; m_lastLiquidity = Liquidities.None; } public Execution( int p_orderId, int p_clientId, String p_execId, String p_time, - String p_acctNumber, String p_exchange, String p_side, int p_shares, - double p_price, int p_permId, int p_liquidation, int p_cumQty, + 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) { m_orderId = p_orderId; diff --git a/ref/client/HistogramEntry.java b/ref/client/HistogramEntry.java index b307ec21..ece6611f 100644 --- a/ref/client/HistogramEntry.java +++ b/ref/client/HistogramEntry.java @@ -5,10 +5,26 @@ public class HistogramEntry implements Comparable { - public double price; - public long size; + private double price; + private Decimal size; - public HistogramEntry(double price, long size) { + public double price() { + return price; + } + + public void price(double price) { + this.price = price; + } + + public Decimal size() { + return size; + } + + public void size(Decimal size) { + this.size = size; + } + + public HistogramEntry(double price, Decimal size) { this.price = price; this.size = size; } @@ -18,16 +34,15 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || !(o instanceof HistogramEntry)) return false; HistogramEntry he = (HistogramEntry) o; - return Double.compare(price, he.price) == 0 && size == he.size; + return Double.compare(price, he.price) == 0 && Decimal.compare(size, he.size) == 0; } @Override public int hashCode() { int result; - long temp; - temp = Double.doubleToLongBits(price); - result = (int) (temp ^ (temp >>> 32)); - result = 31 * result + (int) (size ^ (size >>> 32)); + long tempPrice = Double.doubleToLongBits(price); + result = (int) (tempPrice ^ (tempPrice >>> 32)); + result = 31 * result + size.hashCode(); return result; } @@ -37,7 +52,7 @@ public int compareTo(HistogramEntry he) { if (d != 0) { return d; } - return Long.compare(size, he.size); + return Decimal.compare(size, he.size); } @Override diff --git a/ref/client/HistoricalSession.java b/ref/client/HistoricalSession.java new file mode 100644 index 00000000..df588374 --- /dev/null +++ b/ref/client/HistoricalSession.java @@ -0,0 +1,28 @@ +/* Copyright (C) 2021 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; + +public class HistoricalSession { + private String m_startDateTime; + private String m_endDateTime; + private String m_refDate; + + public HistoricalSession(String startDateTime, String endDateTime, String refDate) { + m_startDateTime = startDateTime; + m_endDateTime = endDateTime; + m_refDate = refDate; + } + + public String startDateTime() { + return m_startDateTime; + } + + public String endDateTime() { + return m_endDateTime; + } + + public String refDate() { + return m_refDate; + } +} \ No newline at end of file diff --git a/ref/client/HistoricalTick.java b/ref/client/HistoricalTick.java index c5f1b4eb..e776e2cf 100644 --- a/ref/client/HistoricalTick.java +++ b/ref/client/HistoricalTick.java @@ -6,9 +6,9 @@ public class HistoricalTick { private long m_time; private double m_price; - private long m_size; + private Decimal m_size; - public HistoricalTick(long time, double price, long size) { + public HistoricalTick(long time, double price, Decimal size) { m_time = time; m_price = price; m_size = size; @@ -22,7 +22,7 @@ public double price() { return m_price; } - public long size() { + public Decimal size() { return m_size; } } \ No newline at end of file diff --git a/ref/client/HistoricalTickBidAsk.java b/ref/client/HistoricalTickBidAsk.java index 3297cf78..d6f24c35 100644 --- a/ref/client/HistoricalTickBidAsk.java +++ b/ref/client/HistoricalTickBidAsk.java @@ -8,10 +8,10 @@ public class HistoricalTickBidAsk { private TickAttribBidAsk m_tickAttribBidAsk; private double m_priceBid; private double m_priceAsk; - private long m_sizeBid; - private long m_sizeAsk; + private Decimal m_sizeBid; + private Decimal m_sizeAsk; - public HistoricalTickBidAsk(long time, TickAttribBidAsk tickAttribBidAsk, double priceBid, double priceAsk, long sizeBid, long sizeAsk) { + public HistoricalTickBidAsk(long time, TickAttribBidAsk tickAttribBidAsk, double priceBid, double priceAsk, Decimal sizeBid, Decimal sizeAsk) { m_time = time; m_tickAttribBidAsk = tickAttribBidAsk; m_priceBid = priceBid; @@ -36,11 +36,11 @@ public double priceAsk() { return m_priceAsk; } - public long sizeBid() { + public Decimal sizeBid() { return m_sizeBid; } - public long sizeAsk() { + public Decimal sizeAsk() { return m_sizeAsk; } diff --git a/ref/client/HistoricalTickLast.java b/ref/client/HistoricalTickLast.java index 7a59ca03..c0a91e24 100644 --- a/ref/client/HistoricalTickLast.java +++ b/ref/client/HistoricalTickLast.java @@ -7,11 +7,11 @@ public class HistoricalTickLast { private long m_time; private TickAttribLast m_tickAttribLast; private double m_price; - private long m_size; + private Decimal m_size; private String m_exchange; private String m_specialConditions; - public HistoricalTickLast(long time, TickAttribLast tickAttribLast, double price, long size, String exchange, String specialConditions) { + public HistoricalTickLast(long time, TickAttribLast tickAttribLast, double price, Decimal size, String exchange, String specialConditions) { m_time = time; m_tickAttribLast = tickAttribLast; m_price = price; @@ -32,7 +32,7 @@ public double price() { return m_price; } - public long size() { + public Decimal size() { return m_size; } diff --git a/ref/client/MarginCondition.java b/ref/client/MarginCondition.java index f08979b3..5ebc8751 100644 --- a/ref/client/MarginCondition.java +++ b/ref/client/MarginCondition.java @@ -26,7 +26,7 @@ public void percent(int m_percent) { @Override protected String valueToString() { - return "" + m_percent; + return Util.IntMaxString(m_percent); } @Override diff --git a/ref/client/Order.java b/ref/client/Order.java index cb9205a1..d7733482 100644 --- a/ref/client/Order.java +++ b/ref/client/Order.java @@ -31,6 +31,7 @@ public class Order { final public static int AUCTION_IMPROVEMENT = 2; final public static int AUCTION_TRANSPARENT = 3; final public static String EMPTY_STR = ""; + final public static double COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID = Double.POSITIVE_INFINITY; // order id's private int m_clientId; @@ -40,7 +41,7 @@ public class Order { // primary attributes private String m_action = "BUY"; - private double m_totalQuantity; + private Decimal m_totalQuantity = Decimal.INVALID; private int m_displaySize; private String m_orderType = "LMT"; private double m_lmtPrice = Double.MAX_VALUE; @@ -126,7 +127,7 @@ public class Order { private boolean m_overridePercentageConstraints; // Institutional orders only - private String m_openClose = "O"; // O=Open, C=Close + private String m_openClose; // O=Open, C=Close private int m_origin; // 0=Customer, 1=Firm private int m_shortSaleSlot; // 1 if you hold the shares, 2 if they will be delivered from elsewhere. Only for Action="SSHORT private String m_designatedLocation; // set when slot=2 only. @@ -137,9 +138,6 @@ public class Order { // SMART routing only private double m_discretionaryAmt = Double.MAX_VALUE; - private boolean m_eTradeOnly; - private boolean m_firmQuoteOnly; - private double m_nbboPriceCap = Double.MAX_VALUE; private boolean m_optOutSmartRouting; // BOX or VOL ORDERS ONLY @@ -209,7 +207,7 @@ public class Order { private boolean m_discretionaryUpToLimitPrice; private String m_autoCancelDate; - private double m_filledQuantity; + private Decimal m_filledQuantity; private int m_refFuturesConId; private boolean m_autoCancelParent; private String m_shareholder; @@ -218,14 +216,21 @@ public class Order { private long m_parentPermId; private Boolean m_usePriceMgmtAlgo; + private int m_duration; + private int m_postToAts; + private String m_advancedErrorOverride; + private String m_manualOrderTime; + private int m_minTradeQty; + private int m_minCompeteSize; + private double m_competeAgainstBestOffset; + private double m_midOffsetAtWhole; + private double m_midOffsetAtHalf; // getters public Action action() { return Action.get(m_action); } public String getAction() { return m_action; } public boolean allOrNone() { return m_allOrNone; } public boolean blockOrder() { return m_blockOrder; } - public boolean eTradeOnly() { return m_eTradeOnly; } - public boolean firmQuoteOnly() { return m_firmQuoteOnly; } public boolean hidden() { return m_hidden; } public boolean outsideRth() { return m_outsideRth; } public boolean notHeld() { return m_notHeld; } @@ -241,7 +246,6 @@ public class Order { public double deltaNeutralAuxPrice() { return m_deltaNeutralAuxPrice; } public double discretionaryAmt() { return m_discretionaryAmt; } public double lmtPrice() { return m_lmtPrice; } - public double nbboPriceCap() { return m_nbboPriceCap; } public double percentOffset() { return m_percentOffset; } public double scalePriceAdjustValue() { return m_scalePriceAdjustValue; } public double scalePriceIncrement() { return m_scalePriceIncrement; } @@ -271,7 +275,7 @@ public class Order { public int scaleInitPosition() { return m_scaleInitPosition; } public int scalePriceAdjustInterval() { return m_scalePriceAdjustInterval; } public int scaleSubsLevelSize() { return m_scaleSubsLevelSize; } - public double totalQuantity() { return m_totalQuantity; } + public Decimal totalQuantity() { return m_totalQuantity; } public int permId() { return m_permId; } public Method faMethod() { return Method.get(m_faMethod); } public String getFaMethod() { return m_faMethod; } @@ -353,7 +357,7 @@ public class Order { public boolean isOmsContainer() { return m_isOmsContainer; } public boolean discretionaryUpToLimitPrice() { return m_discretionaryUpToLimitPrice; } public String autoCancelDate() { return m_autoCancelDate; } - public double filledQuantity() { return m_filledQuantity; } + public Decimal filledQuantity() { return m_filledQuantity; } public int refFuturesConId() { return m_refFuturesConId; } public boolean autoCancelParent() { return m_autoCancelParent; } public String shareholder() { return m_shareholder; } @@ -361,6 +365,16 @@ public class Order { public boolean routeMarketableToBbo() { return m_routeMarketableToBbo; } public long parentPermId() { return m_parentPermId; } public Boolean usePriceMgmtAlgo() { return m_usePriceMgmtAlgo; } + public int duration() { return m_duration; } + public int postToAts() { return m_postToAts; } + public String advancedErrorOverride() { return m_advancedErrorOverride; } + public String manualOrderTime() { return m_manualOrderTime; } + public int minTradeQty() { return m_minTradeQty; } + public int minCompeteSize() { return m_minCompeteSize; } + public double competeAgainstBestOffset() { return m_competeAgainstBestOffset; } + 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; } // setters public void referenceContractId(int m_referenceContractId) { this.m_referenceContractId = m_referenceContractId; } @@ -389,13 +403,11 @@ public class Order { public void deltaNeutralOrderType(String v) { m_deltaNeutralOrderType = v; } public void discretionaryAmt(double v) { m_discretionaryAmt = v; } public void displaySize(int v) { m_displaySize = v; } - public void eTradeOnly(boolean v) { m_eTradeOnly = v; } public void faGroup(String v) { m_faGroup = v; } 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 firmQuoteOnly(boolean v) { m_firmQuoteOnly = 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; } @@ -404,7 +416,6 @@ public class Order { public void hidden(boolean v) { m_hidden = v; } public void lmtPrice(double v) { m_lmtPrice = v; } public void minQty(int v) { m_minQty = v; } - public void nbboPriceCap(double v) { m_nbboPriceCap = v; } public void notHeld(boolean v) { m_notHeld = v; } public void solicited(boolean v) { m_solicited = v; } public void ocaGroup(String v) { m_ocaGroup = v; } @@ -448,7 +459,7 @@ public class Order { public void sweepToFill(boolean v) { m_sweepToFill = v; } public void tif(TimeInForce v) { m_tif = ( v == null ) ? null : v.getApiString(); } public void tif(String v) { m_tif = v; } - public void totalQuantity(double v) { m_totalQuantity = v; } + public void totalQuantity(Decimal v) { m_totalQuantity = v; } public void trailingPercent(double v) { m_trailingPercent = v; } public void trailStopPrice(double v) { m_trailStopPrice = v; } public void transmit(boolean v) { m_transmit = v; } @@ -497,7 +508,7 @@ public class Order { public void isOmsContainer(boolean v) { m_isOmsContainer = v; } public void discretionaryUpToLimitPrice(boolean v) { m_discretionaryUpToLimitPrice = v; } public void autoCancelDate(String v) { m_autoCancelDate = v; } - public void filledQuantity(double v) { m_filledQuantity = v; } + public void filledQuantity(Decimal v) { m_filledQuantity = v; } public void refFuturesConId(int v) { m_refFuturesConId = v; } public void autoCancelParent(boolean v) { m_autoCancelParent = v; } public void shareholder(String v) { m_shareholder = v; } @@ -505,9 +516,20 @@ public class Order { public void routeMarketableToBbo(boolean v) { m_routeMarketableToBbo = v; } public void parentPermId(long v) { m_parentPermId = v; } public void usePriceMgmtAlgo(Boolean v) { m_usePriceMgmtAlgo = v; } + public void duration(int v) { m_duration = v; } + public void postToAts(int v) { m_postToAts = v; } + public void advancedErrorOverride(String v) { m_advancedErrorOverride = v; } + public void manualOrderTime(String v) { m_manualOrderTime = v; } + public void minTradeQty(int v) { m_minTradeQty = v; } + public void minCompeteSize(int v) { m_minCompeteSize = v; } + public void competeAgainstBestOffset(double v) { m_competeAgainstBestOffset = v; } + 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 Order() { + m_openClose = EMPTY_STR; m_activeStartTime = EMPTY_STR; m_activeStopTime = EMPTY_STR; m_outsideRth = false; @@ -543,7 +565,7 @@ public Order() { m_isOmsContainer = false; m_discretionaryUpToLimitPrice = false; m_autoCancelDate = EMPTY_STR; - m_filledQuantity = Double.MAX_VALUE; + m_filledQuantity = Decimal.INVALID; m_refFuturesConId = 0; m_autoCancelParent = false; m_shareholder = EMPTY_STR; @@ -551,6 +573,15 @@ public Order() { m_routeMarketableToBbo = false; m_parentPermId = 0; m_usePriceMgmtAlgo = null; + m_duration = Integer.MAX_VALUE; + m_postToAts = Integer.MAX_VALUE; + m_advancedErrorOverride = EMPTY_STR; + m_manualOrderTime = EMPTY_STR; + m_minTradeQty = Integer.MAX_VALUE; + m_minCompeteSize = Integer.MAX_VALUE; + m_competeAgainstBestOffset = Double.MAX_VALUE; + m_midOffsetAtWhole = Double.MAX_VALUE; + m_midOffsetAtHalf = Double.MAX_VALUE; } public List algoParams() { @@ -597,9 +628,6 @@ public boolean equals(Object p_other) { || m_origin != l_theOther.m_origin || m_shortSaleSlot != l_theOther.m_shortSaleSlot || m_discretionaryAmt != l_theOther.m_discretionaryAmt - || m_eTradeOnly != l_theOther.m_eTradeOnly - || m_firmQuoteOnly != l_theOther.m_firmQuoteOnly - || m_nbboPriceCap != l_theOther.m_nbboPriceCap || m_optOutSmartRouting != l_theOther.m_optOutSmartRouting || m_auctionStrategy != l_theOther.m_auctionStrategy || m_startingPrice != l_theOther.m_startingPrice @@ -655,6 +683,13 @@ public boolean equals(Object p_other) { || m_imbalanceOnly != l_theOther.m_imbalanceOnly || m_routeMarketableToBbo != l_theOther.m_routeMarketableToBbo || m_parentPermId != l_theOther.m_parentPermId + || m_duration != l_theOther.m_duration + || m_postToAts != l_theOther.m_postToAts + || m_minTradeQty != l_theOther.m_minTradeQty + || m_minCompeteSize != l_theOther.m_minCompeteSize + || m_competeAgainstBestOffset != l_theOther.m_competeAgainstBestOffset + || m_midOffsetAtWhole != l_theOther.m_midOffsetAtWhole + || m_midOffsetAtHalf != l_theOther.m_midOffsetAtHalf ) { return false; } @@ -699,6 +734,8 @@ public boolean equals(Object p_other) { || Util.StringCompare(m_mifid2ExecutionAlgo, l_theOther.m_mifid2ExecutionAlgo) != 0 || Util.StringCompare(m_autoCancelDate, l_theOther.m_autoCancelDate) != 0 || 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 ) { return false; } diff --git a/ref/client/OrderType.java b/ref/client/OrderType.java index bcb2d354..f44cb1f7 100644 --- a/ref/client/OrderType.java +++ b/ref/client/OrderType.java @@ -23,6 +23,7 @@ public enum OrderType implements IApiEnum { 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"), diff --git a/ref/client/PercentChangeCondition.java b/ref/client/PercentChangeCondition.java index fc942852..dd7355c8 100644 --- a/ref/client/PercentChangeCondition.java +++ b/ref/client/PercentChangeCondition.java @@ -31,7 +31,7 @@ public void changePercent(double m_changePercent) { @Override protected String valueToString() { - return "" + m_changePercent; + return Util.DoubleMaxString(m_changePercent); } @Override diff --git a/ref/client/PriceCondition.java b/ref/client/PriceCondition.java index d3ba133f..ff4084e7 100644 --- a/ref/client/PriceCondition.java +++ b/ref/client/PriceCondition.java @@ -49,7 +49,7 @@ public void triggerMethod(int m_triggerMethod) { @Override protected String valueToString() { - return "" + m_price; + return Util.DoubleMaxString(m_price); } @Override diff --git a/ref/client/TickByTick.java b/ref/client/TickByTick.java index 4bdb1f5d..db67907c 100644 --- a/ref/client/TickByTick.java +++ b/ref/client/TickByTick.java @@ -7,18 +7,18 @@ public class TickByTick { private int m_tickType; // 0 - None, 1 - Last, 2 - AllLast, 3 -BidAsk, 4 - MidPoint private long m_time; // in seconds private double m_price; - private long m_size; + private Decimal m_size; private TickAttribLast m_tickAttribLast; private TickAttribBidAsk m_tickAttribBidAsk; private String m_exchange; private String m_specialConditions; private double m_bidPrice; - private long m_bidSize; + private Decimal m_bidSize; private double m_askPrice; - private long m_askSize; + private Decimal m_askSize; private double m_midPoint; - public TickByTick(int tickType, long time, double price, long size, TickAttribLast tickAttribLast, String exchange, String specialConditions) { + public TickByTick(int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions) { m_tickType = tickType; m_time = time; m_price = price; @@ -28,7 +28,7 @@ public TickByTick(int tickType, long time, double price, long size, TickAttribLa m_specialConditions = specialConditions; } - public TickByTick(long time, double bidPrice, long bidSize, double askPrice, long askSize, TickAttribBidAsk tickAttribBidAsk) { + public TickByTick(long time, double bidPrice, Decimal bidSize, double askPrice, Decimal askSize, TickAttribBidAsk tickAttribBidAsk) { m_tickType = 3; m_time = time; m_bidPrice = bidPrice; @@ -56,7 +56,7 @@ public double price() { return m_price; } - public long size() { + public Decimal size() { return m_size; } @@ -94,7 +94,7 @@ public double bidPrice() { return m_bidPrice; } - public long bidSize() { + public Decimal bidSize() { return m_bidSize; } @@ -102,7 +102,7 @@ public double askPrice() { return m_askPrice; } - public long askSize() { + public Decimal askSize() { return m_askSize; } diff --git a/ref/client/TickType.java b/ref/client/TickType.java index a8eb0e11..32b5f998 100644 --- a/ref/client/TickType.java +++ b/ref/client/TickType.java @@ -95,6 +95,19 @@ public enum TickType { AVG_OPT_VOLUME(87, "avgOptVolume"), DELAYED_LAST_TIMESTAMP(88, "delayedLastTimestamp"), SHORTABLE_SHARES(89, "shortableShares"), + DELAYED_HALTED(90, "delayedHalted"), + REUTERS_2_MUTUAL_FUNDS(91, "reuters2MutualFunds"), + ETF_NAV_CLOSE(92, "etfNavClose"), + ETF_NAV_PRIOR_CLOSE(93, "etfNavPriorClose"), + ETF_NAV_BID(94, "etfNavBid"), + ETF_NAV_ASK(95, "etfNavAsk"), + ETF_NAV_LAST(96, "etfNavLast"), + ETF_FROZEN_NAV_LAST(97, "etfFrozenNavLast"), + ETF_NAV_HIGH(98, "etfNavHigh"), + ETF_NAV_LOW(99, "etfNavLow"), + SOCIAL_MARKET_ANALYTICS(100, "socialMarketAnalytics"), + ESTIMATED_IPO_MIDPOINT(101, "estimatedIPOMidpoint"), + FINAL_IPO_LAST(102, "finalIPOLast"), UNKNOWN( Integer.MAX_VALUE , "unknown" ); diff --git a/ref/client/Types.java b/ref/client/Types.java index 00927917..36ac7204 100644 --- a/ref/client/Types.java +++ b/ref/client/Types.java @@ -25,6 +25,8 @@ import static com.ib.client.Types.AlgoParam.timeBetweenOrders; import static com.ib.client.Types.AlgoParam.useOddLots; import static com.ib.client.Types.AlgoParam.waitForFill; +import static com.ib.client.Types.AlgoParam.activeTimeStart; +import static com.ib.client.Types.AlgoParam.activeTimeEnd; public class Types { public enum TickByTickType { @@ -37,7 +39,7 @@ public enum ComboParam { public enum AlgoParam { startTime, endTime, allowPastEndTime, maxPctVol, pctVol, strategyType, noTakeLiq, riskAversion, forceCompletion, displaySize, getDone, noTradeAhead, useOddLots, - componentSize, timeBetweenOrders, randomizeTime20, randomizeSize55, giveUp, catchUp, waitForFill + componentSize, timeBetweenOrders, randomizeTime20, randomizeSize55, giveUp, catchUp, waitForFill, activeTimeStart, activeTimeEnd, } public enum AlgoStrategy implements IApiEnum { @@ -47,7 +49,7 @@ public enum AlgoStrategy implements IApiEnum { ArrivalPx( startTime, endTime, allowPastEndTime, maxPctVol, riskAversion, forceCompletion), DarkIce( startTime, endTime, allowPastEndTime, displaySize), PctVol( startTime, endTime, pctVol, noTakeLiq), - AD( startTime, endTime, componentSize, timeBetweenOrders, randomizeTime20, randomizeSize55, giveUp, catchUp, waitForFill); + AD( activeTimeStart, activeTimeEnd, componentSize, timeBetweenOrders, randomizeTime20, randomizeSize55, giveUp, catchUp, waitForFill); private AlgoParam[] m_params; @@ -191,7 +193,7 @@ public static OcaType get( int ordinal) { } public enum TimeInForce implements IApiEnum { - DAY, GTC, OPG, IOC, GTD, GTT, AUC, FOK, GTX, DTC; + DAY, GTC, OPG, IOC, GTD, GTT, AUC, FOK, GTX, DTC, Minutes; public static TimeInForce get(String apiString) { return getValueOf(apiString, values(), null); @@ -232,7 +234,8 @@ 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 + BID_ASK, HISTORICAL_VOLATILITY, OPTION_IMPLIED_VOLATILITY, YIELD_ASK, YIELD_BID, YIELD_BID_ASK, YIELD_LAST, ADJUSTED_LAST, + SCHEDULE } public enum BarSize { @@ -250,6 +253,7 @@ public enum BarSize { _20_mins("20 mins"), _30_mins("30 mins"), _1_hour("1 hour"), + _2_hours("2 hours"), _4_hours("4 hours"), _1_day("1 day"), _1_week("1 week"), @@ -316,7 +320,7 @@ public static SecIdType get(String str) { } public enum SecType implements IApiEnum { - None, STK, OPT, FUT, CONTFUT, CASH, BOND, CFD, FOP, WAR, IOPT, FWD, BAG, IND, BILL, FUND, FIXED, SLB, NEWS, CMDTY, BSK, ICU, ICS; + None, STK, OPT, FUT, CONTFUT, CASH, BOND, CFD, FOP, WAR, IOPT, FWD, BAG, IND, BILL, FUND, FIXED, SLB, NEWS, CMDTY, BSK, ICU, ICS, CRYPTO; public static SecType get(String str) { return getValueOf(str, values(), None); diff --git a/ref/client/Util.java b/ref/client/Util.java index 67424532..8b3d0f34 100644 --- a/ref/client/Util.java +++ b/ref/client/Util.java @@ -5,6 +5,7 @@ import static com.ib.controller.Formats.fmt; +import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; @@ -18,6 +19,14 @@ public class Util { public static final String SPACE_SYMBOL = " "; public static final String EQUALS_SIGN = "="; + + public static String decimalToStringNoZero(Decimal value) { + return Decimal.isValidNotZeroValue(value) ? value.toString() : ""; + } + + public static boolean isValidValue(double value) { + return value != Double.MAX_VALUE && !Double.isNaN(value) && !Double.isInfinite(value); + } public static boolean StringIsEmpty(String str) { return str == null || str.length() == 0; @@ -79,7 +88,11 @@ public static String IntMaxString(int value) { } public static String DoubleMaxString(double value) { - return (value == Double.MAX_VALUE) ? "" : String.valueOf(value); + return DoubleMaxString(value, ""); + } + + public static String DoubleMaxString(double value, String defValue) { + return (value == Double.MAX_VALUE) ? defValue : new DecimalFormat("0.########").format(value); } public static String UnixMillisecondsToString(long milliseconds, String dateFormat){ @@ -121,9 +134,6 @@ public void contractDetails(List list) { } } - public static String maxDoubleToString(Double value){ - return value != Double.MAX_VALUE ? Double.toString(value) : "N/A"; - } public static void appendNonEmptyString(StringBuilder sb, String name, String value, String excludeValue) { if (!Util.StringIsEmpty(value) && !value.equals(excludeValue)) { @@ -145,7 +155,7 @@ public static void appendPositiveIntValue(StringBuilder sb, String name, int val public static void appendValidIntValue(StringBuilder sb, String name, int value) { if (value != Integer.MAX_VALUE) { - sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(value); + sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(Util.IntMaxString(value)); } } @@ -157,7 +167,7 @@ public static void appendPositiveDoubleValue(StringBuilder sb, String name, doub public static void appendValidDoubleValue(StringBuilder sb, String name, double value) { if (value != Double.MAX_VALUE) { - sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(value); + sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(Util.DoubleMaxString(value)); } } @@ -184,7 +194,7 @@ public static void appendValidDoubleValue(StringBuilder sb, String name, String public static void appendValidLongValue(StringBuilder sb, String name, long value) { if (value != Long.MAX_VALUE) { - sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(value); + sb.append(SPACE_SYMBOL).append(name).append(EQUALS_SIGN).append(Util.LongMaxString(value)); } } diff --git a/ref/client/VolumeCondition.java b/ref/client/VolumeCondition.java index 9059eb80..3d2ef60c 100644 --- a/ref/client/VolumeCondition.java +++ b/ref/client/VolumeCondition.java @@ -31,7 +31,7 @@ public void volume(int m_volume) { @Override protected String valueToString() { - return "" + m_volume; + return Util.IntMaxString(m_volume); } @Override diff --git a/ref/client/WshEventData.java b/ref/client/WshEventData.java new file mode 100644 index 00000000..bba4867b --- /dev/null +++ b/ref/client/WshEventData.java @@ -0,0 +1,50 @@ +/* Copyright (C) 2022 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; + +public class WshEventData { + + private int m_conId; + private String m_filter; + private boolean m_fillWatchlist; + private boolean m_fillPortfolio; + private boolean m_fillCompetitors; + private String m_startDate; + private String m_endDate; + private int m_totalLimit; + + public int conId() { return m_conId; } + public String filter() { return m_filter; } + public boolean fillWatchlist() { return m_fillWatchlist; } + public boolean fillPortfolio() { return m_fillPortfolio; } + public boolean fillCompetitors() { return m_fillCompetitors; } + public String startDate() { return m_startDate; } + public String endDate() { return m_endDate; } + public int totalLimit() { return m_totalLimit; } + + public WshEventData(int conId, boolean fillWatchlist, boolean fillPortfolio, boolean fillCompetitors, + String startDate, String endDate, int totalLimit) { + m_conId = conId; + m_filter = ""; + m_fillWatchlist = fillWatchlist; + m_fillPortfolio = fillPortfolio; + m_fillCompetitors = fillCompetitors; + m_startDate = startDate; + m_endDate = endDate; + m_totalLimit = totalLimit; + } + + public WshEventData(String filter, boolean fillWatchlist, boolean fillPortfolio, boolean fillCompetitors, + String startDate, String endDate, int totalLimit) { + m_conId = Integer.MAX_VALUE; + m_filter = filter; + m_fillWatchlist = fillWatchlist; + m_fillPortfolio = fillPortfolio; + m_fillCompetitors = fillCompetitors; + m_startDate = startDate; + m_endDate = endDate; + m_totalLimit = totalLimit; + } + +} diff --git a/ref/contracts/FutContract.java b/ref/contracts/FutContract.java index de1b3f6f..67e13e5f 100644 --- a/ref/contracts/FutContract.java +++ b/ref/contracts/FutContract.java @@ -10,8 +10,8 @@ public class FutContract extends Contract { public FutContract(String symbol, String lastTradeDateOrContractMonth) { symbol(symbol); secType(SecType.FUT); - exchange("ONE"); - currency("USD"); + exchange("EUREX"); + currency("EUR"); lastTradeDateOrContractMonth(lastTradeDateOrContractMonth); } diff --git a/ref/controller/AccountSummaryTag.java b/ref/controller/AccountSummaryTag.java index f7a8c8c7..508dd6df 100644 --- a/ref/controller/AccountSummaryTag.java +++ b/ref/controller/AccountSummaryTag.java @@ -13,7 +13,7 @@ public enum AccountSummaryTag { AccruedCash, // Net accrued interest BuyingPower, // The maximum amount of marginable US stocks the account can buy EquityWithLoanValue, // Cash + stocks + bonds + mutual funds - PreviousEquityWithLoanValue, + PreviousDayEquityWithLoanValue, GrossPositionValue, // The sum of the absolute value of all stock and equity option positions RegTEquity, RegTMargin, diff --git a/ref/controller/ApiController.java b/ref/controller/ApiController.java index 3175dd42..883585ed 100644 --- a/ref/controller/ApiController.java +++ b/ref/controller/ApiController.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +39,7 @@ public class ApiController implements EWrapper { private IScannerHandler m_scannerHandler; private ITimeHandler m_timeHandler; private IBulletinHandler m_bulletinHandler; + private IUserInfoHandler m_userInfoHandler; private final Map m_contractDetailsMap = new HashMap<>(); private final Map m_optionCompMap = new HashMap<>(); private final Map m_efpMap = new HashMap<>(); @@ -52,6 +52,7 @@ public class ApiController implements EWrapper { private final Map m_histogramDataMap = new HashMap<>(); private final Map m_fundMap = new HashMap<>(); private final Map m_orderHandlers = new HashMap<>(); + private final Map m_orderCancelHandlers = new HashMap<>(); private final Map m_acctSummaryHandlers = new HashMap<>(); private final Map m_mktValSummaryHandlers = new HashMap<>(); private final Set m_positionHandlers = new ConcurrentHashSet<>(); @@ -74,6 +75,9 @@ public class ApiController implements EWrapper { private final Map m_pnlSingleMap = new HashMap<>(); private final Map m_historicalTicksMap = new HashMap<>(); private final Map m_tickByTickDataMap = new HashMap<>(); + private final Map m_wshMetaDataMap = new HashMap<>(); + private final Map m_wshEventDataMap = new HashMap<>(); + private final Map m_historicalScheduleMap = new HashMap<>(); private boolean m_connected = false; public ApiConnection client() { return m_client; } @@ -84,7 +88,7 @@ public interface IConnectionHandler { void disconnected(); void accountList(List list); void error(Exception e); - void message(int id, int errorCode, String errorMsg); + void message(int id, int errorCode, String errorMsg, String advancedOrderRejectJson); void show(String string); } @@ -158,12 +162,17 @@ public void disconnect() { m_connectionHandler.error( e); } - @Override public void error(int id, int errorCode, String errorMsg) { + @Override public void error(int id, int errorCode, String errorMsg, String advancedOrderRejectJson) { IOrderHandler handler = m_orderHandlers.get( id); if (handler != null) { handler.handle( errorCode, errorMsg); } + IOrderCancelHandler orderCancelHandler = m_orderCancelHandlers.get( id); + if (orderCancelHandler != null) { + orderCancelHandler.handle( errorCode, errorMsg); + } + for (ILiveOrderHandler liveHandler : m_liveOrderHandlers) { liveHandler.handle( id, errorCode, errorMsg); } @@ -176,7 +185,7 @@ public void disconnect() { } } - m_connectionHandler.message( id, errorCode, errorMsg); + m_connectionHandler.message( id, errorCode, errorMsg, advancedOrderRejectJson); recEOM(); } @@ -228,7 +237,7 @@ public void reqAccountUpdates(boolean subscribe, String acctCode, IAccountHandle recEOM(); } - @Override public void updatePortfolio(Contract contract, double positionIn, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String account) { + @Override public void updatePortfolio(Contract contract, Decimal positionIn, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String account) { contract.exchange( contract.primaryExch()); Position position = new Position( contract, account, positionIn, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL); @@ -338,7 +347,7 @@ public void cancelMarketValueSummary(IMarketValueSummaryHandler handler) { // ---------------------------------------- Position handling ---------------------------------------- public interface IPositionHandler { - void position( String account, Contract contract, double pos, double avgCost); + void position( String account, Contract contract, Decimal pos, double avgCost); void positionEnd(); } @@ -360,7 +369,7 @@ public void cancelPositions( IPositionHandler handler) { sendEOM(); } - @Override public void position(String account, Contract contract, double pos, double avgCost) { + @Override public void position(String account, Contract contract, Decimal pos, double avgCost) { for (IPositionHandler handler : m_positionHandlers) { handler.position( account, contract, pos, avgCost); } @@ -412,8 +421,8 @@ public void orderState(OrderState orderState) { } @Override - public void orderStatus(OrderStatus status, double filled, - double remaining, double avgFillPrice, int permId, + public void orderStatus(OrderStatus status, Decimal filled, + Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice) { // TODO Auto-generated method stub @@ -459,7 +468,7 @@ public void orderStatus(OrderStatus status, double filled, // ---------------------------------------- Top Market Data handling ---------------------------------------- public interface ITopMktDataHandler { void tickPrice(TickType tickType, double price, TickAttrib attribs); - void tickSize(TickType tickType, int size); + void tickSize(TickType tickType, Decimal size); void tickString(TickType tickType, String value); void tickSnapshotEnd(); void marketDataType(int marketDataType); @@ -471,13 +480,13 @@ public interface IEfpHandler extends ITopMktDataHandler { } public interface IOptHandler extends ITopMktDataHandler { - void tickOptionComputation( TickType tickType, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice); + void tickOptionComputation( TickType tickType, int tickAttrib, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice); } public static class TopMktDataAdapter implements ITopMktDataHandler { @Override public void tickPrice(TickType tickType, double price, TickAttrib attribs) { } - @Override public void tickSize(TickType tickType, int size) { + @Override public void tickSize(TickType tickType, Decimal size) { } @Override public void tickString(TickType tickType, String value) { } @@ -586,7 +595,7 @@ public void reqMktDataType( int mktDataType) { recEOM(); } - @Override public void tickSize(int reqId, int tickType, int size) { + @Override public void tickSize(int reqId, int tickType, Decimal size) { ITopMktDataHandler handler = m_topMktDataMap.get( reqId); if (handler != null) { handler.tickSize( TickType.get( tickType), size); @@ -629,7 +638,7 @@ public void reqMktDataType( int mktDataType) { // ---------------------------------------- Deep Market Data handling ---------------------------------------- public interface IDeepMktDataHandler { - void updateMktDepth(int position, String marketMaker, DeepType operation, DeepSide side, double price, int size); + void updateMktDepth(int position, String marketMaker, DeepType operation, DeepSide side, double price, Decimal size); } public void reqDeepMktData( Contract contract, int numRows, boolean isSmartDepth, IDeepMktDataHandler handler) { @@ -654,7 +663,7 @@ public void cancelDeepMktData( boolean isSmartDepth, IDeepMktDataHandler handler } } - @Override public void updateMktDepth(int reqId, int position, int operation, int side, double price, int size) { + @Override public void updateMktDepth(int reqId, int position, int operation, int side, double price, Decimal size) { IDeepMktDataHandler handler = m_deepMktDataMap.get( reqId); if (handler != null) { handler.updateMktDepth( position, null, DeepType.get( operation), DeepSide.get( side), price, size); @@ -662,7 +671,7 @@ public void cancelDeepMktData( boolean isSmartDepth, IDeepMktDataHandler handler recEOM(); } - @Override public void updateMktDepthL2(int reqId, int position, String marketMaker, int operation, int side, double price, int size, boolean isSmartDepth) { + @Override public void updateMktDepthL2(int reqId, int position, String marketMaker, int operation, int side, double price, Decimal size, boolean isSmartDepth) { IDeepMktDataHandler handler = m_deepMktDataMap.get( reqId); if (handler != null) { handler.updateMktDepth( position, marketMaker, DeepType.get( operation), DeepSide.get( side), price, size); @@ -702,13 +711,13 @@ void cancelOptionComp( IOptHandler handler) { } } - @Override public void tickOptionComputation(int reqId, int tickType, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { + @Override public void tickOptionComputation(int reqId, int tickType, int tickAttrib, double impliedVol, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { IOptHandler handler = m_optionCompMap.get( reqId); if (handler != null) { - handler.tickOptionComputation( TickType.get( tickType), impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice); + handler.tickOptionComputation( TickType.get( tickType), tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice); } else { - System.out.println( String.format( "not handled %s %s %s %s %s %s %s %s %s", tickType, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice) ); + System.out.println( String.format( "not handled %s %s %s %s %s %s %s %s %s %s", tickType, tickAttrib, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice) ); } recEOM(); } @@ -760,7 +769,12 @@ 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()) @@ -775,7 +789,7 @@ public void updateGroups( List groups) { if (!checkConnection()) return; - m_client.replaceFA( FADataType.GROUPS.ordinal(), AdvisorUtil.getGroupsXml( groups) ); + m_client.replaceFA( REPLACE_FA_GROUPS_REQ_ID, FADataType.GROUPS.ordinal(), AdvisorUtil.getGroupsXml( groups) ); sendEOM(); } @@ -783,7 +797,7 @@ public void updateProfiles(List profiles) { if (!checkConnection()) return; - m_client.replaceFA( FADataType.PROFILES.ordinal(), AdvisorUtil.getProfilesXml( profiles) ); + m_client.replaceFA( REPLACE_FA_PROFILES_REQ_ID, FADataType.PROFILES.ordinal(), AdvisorUtil.getProfilesXml( profiles) ); sendEOM(); } @@ -815,16 +829,35 @@ public void updateProfiles(List profiles) { } recEOM(); } + + @Override public final void replaceFAEnd(int reqId, String text) { + switch(reqId) { + case REPLACE_FA_GROUPS_REQ_ID: + m_advisorHandler.updateGroupsEnd(text); + break; + case REPLACE_FA_PROFILES_REQ_ID: + m_advisorHandler.updateProfilesEnd(text); + break; + default: + break; + } + recEOM(); + } // ---------------------------------------- Trading and Option Exercise ---------------------------------------- /** This interface is for receiving events for a specific order placed from the API. * Compare to ILiveOrderHandler. */ public interface IOrderHandler { void orderState(OrderState orderState); - void orderStatus(OrderStatus status, double filled, double remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice); + void orderStatus(OrderStatus status, Decimal filled, Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice); void handle(int errorCode, String errorMsg); } + public interface IOrderCancelHandler { + void orderStatus(String orderStatus); + void handle(int errorCode, String errorMsg); + } + public void placeOrModifyOrder(Contract contract, final Order order, final IOrderHandler handler) { if (!checkConnection()) return; @@ -841,11 +874,15 @@ public void placeOrModifyOrder(Contract contract, final Order order, final IOrde sendEOM(); } - public void cancelOrder(int orderId) { + public void cancelOrder(int orderId, String manualOrderCancelTime, final IOrderCancelHandler orderCancelHandler) { if (!checkConnection()) return; - m_client.cancelOrder( orderId); + if (orderCancelHandler != null) { + m_orderCancelHandlers.put( orderId, orderCancelHandler); + } + + m_client.cancelOrder( orderId, manualOrderCancelTime); sendEOM(); } @@ -869,6 +906,9 @@ public void removeOrderHandler( IOrderHandler handler) { getAndRemoveKey(m_orderHandlers, handler); } + public void removeOrderCancelHandler( IOrderCancelHandler orderCancelHandler) { + getAndRemoveKey(m_orderCancelHandlers, orderCancelHandler); + } // ---------------------------------------- Live order handling ---------------------------------------- /** This interface is for downloading and receiving events for all live orders. @@ -876,7 +916,7 @@ public void removeOrderHandler( IOrderHandler handler) { public interface ILiveOrderHandler { void openOrder(Contract contract, Order order, OrderState orderState); void openOrderEnd(); - void orderStatus(int orderId, OrderStatus status, double filled, double remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice); + void orderStatus(int orderId, OrderStatus status, Decimal filled, Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice); void handle(int orderId, int errorCode, String errorMsg); // add permId? } @@ -932,12 +972,17 @@ public void removeLiveOrderHandler(ILiveOrderHandler handler) { recEOM(); } - @Override public void orderStatus(int orderId, String status, double filled, double remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice) { + @Override public void orderStatus(int orderId, String status, Decimal filled, Decimal remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld, double mktCapPrice) { IOrderHandler handler = m_orderHandlers.get( orderId); if (handler != null) { handler.orderStatus( OrderStatus.valueOf( status), filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice); } + IOrderCancelHandler orderCancelHandler = m_orderCancelHandlers.get( orderId); + if (orderCancelHandler != null) { + orderCancelHandler.orderStatus(status); + } + for (ILiveOrderHandler liveOrderHandler : m_liveOrderHandlers) { liveOrderHandler.orderStatus(orderId, OrderStatus.valueOf( status), filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice); } @@ -1021,7 +1066,7 @@ public void reqHistoricalData(Contract contract, String endDateTime, int duratio int reqId = m_reqId++; m_historicalDataMap.put( reqId, handler); String durationStr = duration + " " + durationUnit.toString().charAt( 0); - m_client.reqHistoricalData(reqId, contract, endDateTime, durationStr, barSize.toString(), whatToShow.toString(), rthOnly ? 1 : 0, 2, keepUpToDate, Collections.emptyList()); + m_client.reqHistoricalData(reqId, contract, endDateTime, durationStr, barSize.toString(), whatToShow.toString(), rthOnly ? 1 : 0, 1, keepUpToDate, Collections.emptyList()); sendEOM(); } @@ -1043,17 +1088,7 @@ public void cancelHistoricalData( IHistoricalDataHandler handler) { handler.historicalDataEnd(); } else { - long longDate; - if (bar.time().length() == 8) { - int year = Integer.parseInt( bar.time().substring( 0, 4) ); - int month = Integer.parseInt( bar.time().substring( 4, 6) ); - int day = Integer.parseInt( bar.time().substring( 6) ); - longDate = new GregorianCalendar( year, month - 1, day).getTimeInMillis() / 1000; - } - else { - longDate = Long.parseLong( bar.time()); - } - Bar bar2 = new Bar( longDate, bar.high(), bar.low(), bar.open(), bar.close(), bar.wap(), bar.volume(), bar.count()); + Bar bar2 = new Bar( bar.time(), bar.high(), bar.low(), bar.open(), bar.close(), bar.wap(), bar.volume(), bar.count()); handler.historicalData(bar2); } } @@ -1088,7 +1123,7 @@ public void cancelRealtimeBars( IRealTimeBarHandler handler) { } } - @Override public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume, double wap, int count) { + @Override public void realtimeBar(int reqId, long time, double open, double high, double low, double close, Decimal volume, Decimal wap, int count) { IRealTimeBarHandler handler = m_realTimeBarMap.get( reqId); if (handler != null) { Bar bar = new Bar( time, high, low, open, close, wap, volume, count); @@ -1136,7 +1171,7 @@ public void reqCurrentTime( ITimeHandler handler) { protected boolean checkConnection() { if (!isConnected()) { - error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED.code(), EClientErrors.NOT_CONNECTED.msg()); + error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED.code(), EClientErrors.NOT_CONNECTED.msg(), null); return false; } @@ -1176,7 +1211,7 @@ public void cancelBulletins() { // ---------------------------------------- Position Multi handling ---------------------------------------- public interface IPositionMultiHandler { - void positionMulti( String account, String modelCode, Contract contract, double pos, double avgCost); + void positionMulti( String account, String modelCode, Contract contract, Decimal pos, double avgCost); void positionMultiEnd(); } @@ -1201,7 +1236,7 @@ public void cancelPositionsMulti( IPositionMultiHandler handler) { } } - @Override public void positionMulti( int reqId, String account, String modelCode, Contract contract, double pos, double avgCost) { + @Override public void positionMulti( int reqId, String account, String modelCode, Contract contract, Decimal pos, double avgCost) { IPositionMultiHandler handler = m_positionMultiMap.get( reqId); if (handler != null) { handler.positionMulti( account, modelCode, contract, pos, avgCost); @@ -1636,7 +1671,7 @@ public void cancelHistogramData(IHistogramDataHandler handler) { Integer reqId = getAndRemoveKey(m_histogramDataMap, handler); if (reqId != null) { - m_client.cancelHistoricalData(reqId); + m_client.cancelHistogramData(reqId); sendEOM(); } } @@ -1729,7 +1764,7 @@ public void pnl(int reqId, double dailyPnL, double unrealizedPnL, double realize public interface IPnLSingleHandler { - void pnlSingle(int reqId, int pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value); + void pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value); } @@ -1757,7 +1792,7 @@ public void cancelPnLSingle(IPnLSingleHandler handler) { } @Override - public void pnlSingle(int reqId, int pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { + public void pnlSingle(int reqId, Decimal pos, double dailyPnL, double unrealizedPnL, double realizedPnL, double value) { IPnLSingleHandler handler = m_pnlSingleMap.get(reqId); if (handler != null) { @@ -1840,8 +1875,8 @@ public void historicalTicksLast(int reqId, List ticks, boole } public interface ITickByTickDataHandler { - void tickByTickAllLast(int reqId, int tickType, long time, double price, int size, TickAttribLast tickAttribLast, String exchange, String specialConditions); - void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, int bidSize, int askSize, TickAttribBidAsk tickAttribBidAsk); + void tickByTickAllLast(int reqId, int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions); + void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, Decimal bidSize, Decimal askSize, TickAttribBidAsk tickAttribBidAsk); void tickByTickMidPoint(int reqId, long time, double midPoint); void tickByTickHistoricalTickAllLast(int reqId, List ticks); void tickByTickHistoricalTickBidAsk(int reqId, List ticks); @@ -1871,7 +1906,7 @@ public void cancelTickByTickData( ITickByTickDataHandler handler) { } @Override - public void tickByTickAllLast(int reqId, int tickType, long time, double price, int size, TickAttribLast tickAttribLast, + public void tickByTickAllLast(int reqId, int tickType, long time, double price, Decimal size, TickAttribLast tickAttribLast, String exchange, String specialConditions) { ITickByTickDataHandler handler = m_tickByTickDataMap.get(reqId); @@ -1883,7 +1918,7 @@ public void tickByTickAllLast(int reqId, int tickType, long time, double price, } @Override - public void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, int bidSize, int askSize, + public void tickByTickBidAsk(int reqId, long time, double bidPrice, double askPrice, Decimal bidSize, Decimal askSize, TickAttribBidAsk tickAttribBidAsk) { ITickByTickDataHandler handler = m_tickByTickDataMap.get(reqId); @@ -1940,4 +1975,136 @@ public void completedOrdersEnd() { } recEOM(); } + + // ---------------------------------------- WSH Meta Data ---------------------------------------- + public interface IWshMetaDataHandler { + void wshMetaData(int reqId, String dataJson); + } + + public void reqWshMetaData(IWshMetaDataHandler handler) { + if (!checkConnection()) + return; + + int reqId = m_reqId++; + m_wshMetaDataMap.put(reqId, handler); + m_client.reqWshMetaData(reqId); + sendEOM();; + } + + public void cancelWshMetaData(IWshMetaDataHandler handler) { + if (!checkConnection()) + return; + + Integer reqId = getAndRemoveKey(m_wshMetaDataMap, handler); + if (reqId != null) { + m_client.cancelWshMetaData(reqId); + sendEOM(); + } + } + + @Override + public void wshMetaData(int reqId, String dataJson) { + IWshMetaDataHandler handler = m_wshMetaDataMap.get(reqId); + + if (handler != null) { + handler.wshMetaData(reqId, dataJson); + } + + recEOM(); + } + + // ---------------------------------------- WSH Event Data ---------------------------------------- + public interface IWshEventDataHandler { + void wshEventData(int reqId, String dataJson); + } + + public void reqWshEventData(WshEventData wshEventData, IWshEventDataHandler handler) { + if (!checkConnection()) + return; + + int reqId = m_reqId++; + m_wshEventDataMap.put(reqId, handler); + m_client.reqWshEventData(reqId, wshEventData); + sendEOM(); + } + + public void cancelWshEventData(IWshEventDataHandler handler) { + if (!checkConnection()) + return; + + Integer reqId = getAndRemoveKey(m_wshEventDataMap, handler); + if (reqId != null) { + m_client.cancelWshMetaData(reqId); + sendEOM(); + } + } + + @Override + public void wshEventData(int reqId, String dataJson) { + IWshEventDataHandler handler = m_wshEventDataMap.get(reqId); + + if (handler != null) { + handler.wshEventData(reqId, dataJson); + } + + recEOM(); + } + + // ---------------------------------------- Historical Schedule ---------------------------------------- + public interface IHistoricalScheduleHandler { + void historicalSchedule(int reqId, String startDateTime, String endDateTime, String timeZone, List sessions); + } + + public void reqHistoricalSchedule(Contract contract, String endDateTime, int duration, DurationUnit durationUnit, boolean rthOnly, IHistoricalScheduleHandler handler) { + if (!checkConnection()) + return; + + int reqId = m_reqId++; + m_historicalScheduleMap.put(reqId, handler); + String durationStr = duration + " " + durationUnit.toString().charAt( 0); + m_client.reqHistoricalData(reqId, contract, endDateTime, durationStr, BarSize._1_day.toString(), WhatToShow.SCHEDULE.name(), rthOnly ? 1 : 0, 2, false, Collections.emptyList()); + + sendEOM(); + } + + public void cancelHistoricalSchedule(IHistoricalScheduleHandler handler) { + if (!checkConnection()) + return; + + Integer reqId = getAndRemoveKey(m_historicalScheduleMap, handler); + if (reqId != null) { + m_client.cancelHistoricalData(reqId); + + sendEOM(); + } + } + + @Override public void historicalSchedule(int reqId, String startDateTime, String endDateTime, String timeZone, List sessions) { + IHistoricalScheduleHandler handler = m_historicalScheduleMap.get(reqId); + + if (handler != null) { + handler.historicalSchedule(reqId, startDateTime, endDateTime, timeZone, sessions); + } + + recEOM(); + } + + // ---------------------------------------- User Info handling ---------------------------------------- + public interface IUserInfoHandler { + void userInfo(int reqId, String whiteBrandingId); + } + + public void reqUserInfo(int reqId, IUserInfoHandler handler) { + if (!checkConnection()) + return; + + m_userInfoHandler = handler; + m_client.reqUserInfo(reqId); + sendEOM(); + } + + @Override public void userInfo(int reqId, String whiteBrandingId) { + m_userInfoHandler.userInfo(reqId, whiteBrandingId); + recEOM(); + } } diff --git a/ref/controller/Bar.java b/ref/controller/Bar.java index 8ee04686..3a19c332 100644 --- a/ref/controller/Bar.java +++ b/ref/controller/Bar.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms +/* Copyright (C) 2021 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,34 @@ import java.text.SimpleDateFormat; import java.util.Date; +import com.ib.client.Decimal; + public class Bar { private static final ThreadLocal FORMAT_CACHE = ThreadLocal.withInitial(() -> new SimpleDateFormat( "yyyyMMdd HH:mm:ss")); private final long m_time; + private final String m_timeStr; private final double m_high; private final double m_low; private final double m_open; private final double m_close; - private final double m_wap; - private final long m_volume; + private final Decimal m_wap; + private final Decimal m_volume; private final int m_count; public long time() { return m_time; } + public String timeStr() { return m_timeStr; } public double high() { return m_high; } public double low() { return m_low; } public double open() { return m_open; } public double close() { return m_close; } - public double wap() { return m_wap; } - public long volume() { return m_volume; } + public Decimal wap() { return m_wap; } + public Decimal volume() { return m_volume; } public int count() { return m_count; } - public Bar( long time, double high, double low, double open, double close, double wap, long volume, int count) { + public Bar( long time, double high, double low, double open, double close, Decimal wap, Decimal volume, int count) { m_time = time; + m_timeStr = null; m_high = high; m_low = low; m_open = open; @@ -38,6 +43,18 @@ public Bar( long time, double high, double low, double open, double close, doubl m_count = count; } + public Bar( String timeStr, double high, double low, double open, double close, Decimal wap, Decimal volume, int count) { + m_time = Long.MAX_VALUE; + m_timeStr = timeStr; + m_high = high; + m_low = low; + m_open = open; + m_close = close; + m_wap = wap; + m_volume = volume; + m_count = count; + } + public String formattedTime() { return Formats.fmtDate( m_time * 1000); } @@ -48,6 +65,6 @@ public static String format( long ms) { } @Override public String toString() { - return String.format( "%s %s %s %s %s", formattedTime(), m_open, m_high, m_low, m_close); + return String.format( "%s %s %s %s %s", m_timeStr != null ? m_timeStr : formattedTime(), m_open, m_high, m_low, m_close); } } diff --git a/ref/controller/Formats.java b/ref/controller/Formats.java index 589df8a8..6087774a 100644 --- a/ref/controller/Formats.java +++ b/ref/controller/Formats.java @@ -11,17 +11,23 @@ import java.util.TimeZone; public class Formats { + private static final Format FMT8 = new DecimalFormat( "#,##0.00000000"); private static final Format FMT2 = new DecimalFormat( "#,##0.00"); private static final Format FMT0 = new DecimalFormat( "#,##0"); private static final Format PCT = new DecimalFormat( "0.0%"); private static final ThreadLocal GMT_DATE_TIME_FORMAT_CACHE = ThreadLocal.withInitial(() -> { - final DateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); + final DateFormat format = new SimpleDateFormat( "yyyyMMdd-HH:mm:ss"); format.setTimeZone(TimeZone.getTimeZone("GMT")); return format; }); - private static final ThreadLocal DATE_TIME_FORMAT_CACHE = ThreadLocal.withInitial(() -> new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss")); + private static final ThreadLocal DATE_TIME_FORMAT_CACHE = ThreadLocal.withInitial(() -> new SimpleDateFormat( "yyyyMMdd-HH:mm:ss")); private static final ThreadLocal TIME_FORMAT_CACHE = ThreadLocal.withInitial(() -> new SimpleDateFormat( "HH:mm:ss")); + /** Format with 8 decimals. */ + public static String fmt8( double v) { + return v == Double.MAX_VALUE ? null : FMT8.format( v); + } + /** Format with two decimals. */ public static String fmt( double v) { return v == Double.MAX_VALUE ? null : FMT2.format( v); diff --git a/ref/controller/LocationCode.java b/ref/controller/LocationCode.java index afb7ce88..68a0b137 100644 --- a/ref/controller/LocationCode.java +++ b/ref/controller/LocationCode.java @@ -6,16 +6,13 @@ public enum LocationCode { BOND_US("BOND.US"), EFP("EFP"), - FUT_ECBOT("FUT.ECBOT"), FUT_EU_BELFOX("FUT.EU.BELFOX"), - FUT_EU_DTB("FUT.EU.DTB"), FUT_EU_FTA("FUT.EU.FTA"), FUT_EU_IDEM("FUT.EU.IDEM"), FUT_EU_LIFFE("FUT.EU.LIFFE"), FUT_EU_MEFFRV("FUT.EU.MEFFRV"), FUT_EU_MONEP("FUT.EU.MONEP"), FUT_EU("FUT.EU"), - FUT_GLOBEX("FUT.GLOBEX"), FUT_HK_HKFE("FUT.HK.HKFE"), FUT_HK_JAPAN("FUT.HK.JAPAN"), FUT_HK_KSE("FUT.HK.KSE"), @@ -29,11 +26,9 @@ public enum LocationCode { FUT_NA_CDE("FUT.NA.CDE"), FUT_NA("FUT.NA"), FUT_NYBOT("FUT.NYBOT"), - FUT_NYMEX("FUT.NYMEX"), FUT_NYSELIFFE("FUT.NYSELIFFE"), FUT_US("FUT.US"), IND_EU_BELFOX("IND.EU.BELFOX"), - IND_EU_DTB("IND.EU.DTB"), IND_EU_FTA("IND.EU.FTA"), IND_EU_LIFFE("IND.EU.LIFFE"), IND_EU_MONEP("IND.EU.MONEP"), diff --git a/ref/controller/Position.java b/ref/controller/Position.java index 25069cfe..6acbc0fe 100644 --- a/ref/controller/Position.java +++ b/ref/controller/Position.java @@ -4,12 +4,13 @@ package com.ib.controller; import com.ib.client.Contract; +import com.ib.client.Decimal; public class Position { private Contract m_contract; private String m_account; - private double m_position; + private Decimal m_position; private double m_marketPrice; private double m_marketValue; private double m_averageCost; @@ -23,10 +24,10 @@ public class Position { public double marketValue() { return m_marketValue;} public double realPnl() { return m_realPnl;} public double unrealPnl() { return m_unrealPnl;} - public double position() { return m_position;} + public Decimal position() { return m_position;} public String account() { return m_account;} - public Position( Contract contract, String account, double position, double marketPrice, double marketValue, double averageCost, double unrealPnl, double realPnl) { + public Position( Contract contract, String account, Decimal position, double marketPrice, double marketValue, double averageCost, double unrealPnl, double realPnl) { m_contract = contract; m_account = account; m_position = position;