/* Copyright (C) 2013 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.DataInputStream; import java.io.DataOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.net.Socket; public class EClientSocket { // Client version history // // 6 = Added parentId to orderStatus // 7 = The new execDetails event returned for an order filled status and // reqExecDetails // Also market depth is available. // 8 = Added lastFillPrice to orderStatus() event and permId to execution // details // 9 = Added 'averageCost', 'unrealizedPNL', and 'unrealizedPNL' to // updatePortfolio event // 10 = Added 'serverId' to the 'open order' & 'order status' events. // We send back all the API open orders upon connection. // Added new methods reqAllOpenOrders, reqAutoOpenOrders() // Added FA support - reqExecution has filter. // - reqAccountUpdates takes acct code. // 11 = Added permId to openOrder event. // 12 = requsting open order attributes ignoreRth, hidden, and discretionary // 13 = added goodAfterTime // 14 = always send size on bid/ask/last tick // 15 = send allocation description string on openOrder // 16 = can receive account name in account and portfolio updates, and fa // params in openOrder // 17 = can receive liquidation field in exec reports, and notAutoAvailable // field in mkt data // 18 = can receive good till date field in open order messages, and request // intraday backfill // 19 = can receive rthOnly flag in ORDER_STATUS // 20 = expects TWS time string on connection after server version >= 20. // 21 = can receive bond contract details. // 22 = can receive price magnifier in version 2 contract details message // 23 = support for scanner // 24 = can receive volatility order parameters in open order messages // 25 = can receive HMDS query start and end times // 26 = can receive option vols in option market data messages // 27 = can receive delta neutral order type and delta neutral aux price in // place order version 20: API 8.85 // 28 = can receive option model computation ticks: API 8.9 // 29 = can receive trail stop limit price in open order and can place them: // API 8.91 // 30 = can receive extended bond contract def, new ticks, and trade count in // bars // 31 = can receive EFP extensions to scanner and market data, and combo legs // on open orders // ; can receive RT bars // 32 = can receive TickType.LAST_TIMESTAMP // ; can receive "whyHeld" in order status messages // 33 = can receive ScaleNumComponents and ScaleComponentSize is open order // messages // 34 = can receive whatIf orders / order state // 35 = can receive contId field for Contract objects // 36 = can receive outsideRth field for Order objects // 37 = can receive clearingAccount and clearingIntent for Order objects // 38 = can receive multiplier and primaryExchange in portfolio updates // ; can receive cumQty and avgPrice in execution // ; can receive fundamental data // ; can receive underComp for Contract objects // ; can receive reqId and end marker in contractDetails/bondContractDetails // ; can receive ScaleInitComponentSize and ScaleSubsComponentSize for Order // objects // 39 = can receive underConId in contractDetails // 40 = can receive algoStrategy/algoParams in openOrder // 41 = can receive end marker for openOrder // ; can receive end marker for account download // ; can receive end marker for executions download // 42 = can receive deltaNeutralValidation // 43 = can receive longName(companyName) // ; can receive listingExchange // ; can receive RTVolume tick // 44 = can receive end market for ticker snapshot // 45 = can receive notHeld field in openOrder // 46 = can receive contractMonth, industry, category, subcategory fields in // contractDetails // ; can receive timeZoneId, tradingHours, liquidHours fields in // contractDetails // 47 = can receive gamma, vega, theta, undPrice fields in // TICK_OPTION_COMPUTATION // 48 = can receive exemptCode in openOrder // 49 = can receive hedgeType and hedgeParam in openOrder // 50 = can receive optOutSmartRouting field in openOrder // 51 = can receive smartComboRoutingParams in openOrder // 52 = can receive deltaNeutralConId, deltaNeutralSettlingFirm, // deltaNeutralClearingAccount and deltaNeutralClearingIntent in openOrder // 53 = can receive orderRef in execution // 54 = can receive scale order fields (PriceAdjustValue, PriceAdjustInterval, // ProfitOffset, AutoReset, // InitPosition, InitFillQty and RandomPercent) in openOrder // 55 = can receive orderComboLegs (price) in openOrder // 56 = can receive trailingPercent in openOrder // 57 = can receive commissionReport message // 58 = can receive CUSIP/ISIN/etc. in // contractDescription/bondContractDescription // 59 = can receive evRule, evMultiplier in // contractDescription/bondContractDescription/executionDetails // can receive multiplier in executionDetails // 60 = can receive deltaNeutralOpenClose, deltaNeutralShortSale, // deltaNeutralShortSaleSlot and deltaNeutralDesignatedLocation in openOrder // 61 = can receive multiplier in openOrder // can receive tradingClass in openOrder, updatePortfolio, execDetails and // position // 62 = can receive avgCost in position message private static final int CLIENT_VERSION = 62; private static final int SERVER_VERSION = 38; private static final byte[] EOL = { 0 }; private static final String BAG_SEC_TYPE = "BAG"; // FA msg data types public static final int GROUPS = 1; public static final int PROFILES = 2; public static final int ALIASES = 3; public static String faMsgTypeName(int faDataType) { switch (faDataType) { case GROUPS: return "GROUPS"; case PROFILES: return "PROFILES"; case ALIASES: return "ALIASES"; } return null; } // outgoing msg id's private static final int REQ_MKT_DATA = 1; private static final int CANCEL_MKT_DATA = 2; private static final int PLACE_ORDER = 3; private static final int CANCEL_ORDER = 4; private static final int REQ_OPEN_ORDERS = 5; private static final int REQ_ACCOUNT_DATA = 6; private static final int REQ_EXECUTIONS = 7; private static final int REQ_IDS = 8; private static final int REQ_CONTRACT_DATA = 9; private static final int REQ_MKT_DEPTH = 10; private static final int CANCEL_MKT_DEPTH = 11; private static final int REQ_NEWS_BULLETINS = 12; private static final int CANCEL_NEWS_BULLETINS = 13; private static final int SET_SERVER_LOGLEVEL = 14; private static final int REQ_AUTO_OPEN_ORDERS = 15; private static final int REQ_ALL_OPEN_ORDERS = 16; private static final int REQ_MANAGED_ACCTS = 17; private static final int REQ_FA = 18; private static final int REPLACE_FA = 19; private static final int REQ_HISTORICAL_DATA = 20; private static final int EXERCISE_OPTIONS = 21; private static final int REQ_SCANNER_SUBSCRIPTION = 22; private static final int CANCEL_SCANNER_SUBSCRIPTION = 23; private static final int REQ_SCANNER_PARAMETERS = 24; private static final int CANCEL_HISTORICAL_DATA = 25; private static final int REQ_CURRENT_TIME = 49; private static final int REQ_REAL_TIME_BARS = 50; private static final int CANCEL_REAL_TIME_BARS = 51; private static final int REQ_FUNDAMENTAL_DATA = 52; private static final int CANCEL_FUNDAMENTAL_DATA = 53; private static final int REQ_CALC_IMPLIED_VOLAT = 54; private static final int REQ_CALC_OPTION_PRICE = 55; private static final int CANCEL_CALC_IMPLIED_VOLAT = 56; private static final int CANCEL_CALC_OPTION_PRICE = 57; private static final int REQ_GLOBAL_CANCEL = 58; private static final int REQ_MARKET_DATA_TYPE = 59; private static final int REQ_POSITIONS = 61; private static final int REQ_ACCOUNT_SUMMARY = 62; private static final int CANCEL_ACCOUNT_SUMMARY = 63; private static final int CANCEL_POSITIONS = 64; private static final int MIN_SERVER_VER_REAL_TIME_BARS = 34; private static final int MIN_SERVER_VER_SCALE_ORDERS = 35; private static final int MIN_SERVER_VER_SNAPSHOT_MKT_DATA = 35; private static final int MIN_SERVER_VER_SSHORT_COMBO_LEGS = 35; private static final int MIN_SERVER_VER_WHAT_IF_ORDERS = 36; private static final int MIN_SERVER_VER_CONTRACT_CONID = 37; private static final int MIN_SERVER_VER_PTA_ORDERS = 39; private static final int MIN_SERVER_VER_FUNDAMENTAL_DATA = 40; private static final int MIN_SERVER_VER_UNDER_COMP = 40; private static final int MIN_SERVER_VER_CONTRACT_DATA_CHAIN = 40; private static final int MIN_SERVER_VER_SCALE_ORDERS2 = 40; private static final int MIN_SERVER_VER_ALGO_ORDERS = 41; private static final int MIN_SERVER_VER_EXECUTION_DATA_CHAIN = 42; private static final int MIN_SERVER_VER_NOT_HELD = 44; private static final int MIN_SERVER_VER_SEC_ID_TYPE = 45; private static final int MIN_SERVER_VER_PLACE_ORDER_CONID = 46; private static final int MIN_SERVER_VER_REQ_MKT_DATA_CONID = 47; private static final int MIN_SERVER_VER_REQ_CALC_IMPLIED_VOLAT = 49; private static final int MIN_SERVER_VER_REQ_CALC_OPTION_PRICE = 50; private static final int MIN_SERVER_VER_CANCEL_CALC_IMPLIED_VOLAT = 50; private static final int MIN_SERVER_VER_CANCEL_CALC_OPTION_PRICE = 50; private static final int MIN_SERVER_VER_SSHORTX_OLD = 51; private static final int MIN_SERVER_VER_SSHORTX = 52; private static final int MIN_SERVER_VER_REQ_GLOBAL_CANCEL = 53; private static final int MIN_SERVER_VER_HEDGE_ORDERS = 54; private static final int MIN_SERVER_VER_REQ_MARKET_DATA_TYPE = 55; private static final int MIN_SERVER_VER_OPT_OUT_SMART_ROUTING = 56; private static final int MIN_SERVER_VER_SMART_COMBO_ROUTING_PARAMS = 57; private static final int MIN_SERVER_VER_DELTA_NEUTRAL_CONID = 58; private static final int MIN_SERVER_VER_SCALE_ORDERS3 = 60; private static final int MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE = 61; private static final int MIN_SERVER_VER_TRAILING_PERCENT = 62; private static final int MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE = 66; private static final int MIN_SERVER_VER_ACCT_SUMMARY = 67; private static final int MIN_SERVER_VER_TRADING_CLASS = 68; private AnyWrapper m_anyWrapper; // msg handler protected DataOutputStream m_dos; // the socket output stream private boolean m_connected; // true if we are connected private EReader m_reader; // thread which reads msgs from socket private int m_serverVersion; private String m_TwsTime; public int serverVersion() { return m_serverVersion; } public String TwsConnectionTime() { return m_TwsTime; } public AnyWrapper wrapper() { return m_anyWrapper; } public EReader reader() { return m_reader; } public boolean isConnected() { return m_connected; } public EClientSocket(AnyWrapper anyWrapper) { m_anyWrapper = anyWrapper; } public synchronized void eConnect(String host, int port, int clientId) { // already connected? host = checkConnected(host); if (host == null) { return; } try { Socket socket = new Socket(host, port); eConnect(socket, clientId); } catch (Exception e) { eDisconnect(); connectionError(); } } protected void connectionError() { m_anyWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.CONNECT_FAIL.code(), EClientErrors.CONNECT_FAIL.msg()); m_reader = null; } protected String checkConnected(String host) { if (m_connected) { m_anyWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.ALREADY_CONNECTED.code(), EClientErrors.ALREADY_CONNECTED.msg()); return null; } if (isNull(host)) { host = "127.0.0.1"; } return host; } public EReader createReader(EClientSocket socket, DataInputStream dis) { return new EReader(socket, dis); } public synchronized void eConnect(Socket socket, int clientId) throws IOException { // create io streams m_dos = new DataOutputStream(socket.getOutputStream()); // set client version send(CLIENT_VERSION); // start reader thread m_reader = createReader(this, new DataInputStream(socket.getInputStream())); // check server version m_serverVersion = m_reader.readInt(); System.out.println("Server Version:" + m_serverVersion); if (m_serverVersion >= 20) { m_TwsTime = m_reader.readStr(); System.out.println("TWS Time at connection:" + m_TwsTime); } if (m_serverVersion < SERVER_VERSION) { eDisconnect(); m_anyWrapper.error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } // Send the client id if (m_serverVersion >= 3) { send(clientId); } m_reader.start(); // set connected flag m_connected = true; } public synchronized void eDisconnect() { // not connected? if (m_dos == null) { return; } m_connected = false; m_serverVersion = 0; m_TwsTime = ""; FilterOutputStream dos = m_dos; m_dos = null; EReader reader = m_reader; m_reader = null; try { // stop reader thread; reader thread will close input stream if (reader != null) { reader.interrupt(); } } catch (Exception e) { } try { // close output stream if (dos != null) { dos.close(); } } catch (Exception e) { } } public synchronized void cancelScannerSubscription(int tickerId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < 24) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support API scanner subscription."); return; } final int VERSION = 1; // send cancel mkt data msg try { send(CANCEL_SCANNER_SUBSCRIPTION); send(VERSION); send(tickerId); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_CANSCANNER, "" + e); close(); } } public synchronized void reqScannerParameters() { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < 24) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support API scanner subscription."); return; } final int VERSION = 1; try { send(REQ_SCANNER_PARAMETERS); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQSCANNERPARAMETERS, "" + e); close(); } } public synchronized void reqScannerSubscription(int tickerId, ScannerSubscription subscription) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < 24) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support API scanner subscription."); return; } final int VERSION = 3; try { send(REQ_SCANNER_SUBSCRIPTION); send(VERSION); send(tickerId); sendMax(subscription.numberOfRows()); send(subscription.instrument()); send(subscription.locationCode()); send(subscription.scanCode()); sendMax(subscription.abovePrice()); sendMax(subscription.belowPrice()); sendMax(subscription.aboveVolume()); sendMax(subscription.marketCapAbove()); sendMax(subscription.marketCapBelow()); send(subscription.moodyRatingAbove()); send(subscription.moodyRatingBelow()); send(subscription.spRatingAbove()); send(subscription.spRatingBelow()); send(subscription.maturityDateAbove()); send(subscription.maturityDateBelow()); sendMax(subscription.couponRateAbove()); sendMax(subscription.couponRateBelow()); send(subscription.excludeConvertible()); if (m_serverVersion >= 25) { sendMax(subscription.averageOptionVolumeAbove()); send(subscription.scannerSettingPairs()); } if (m_serverVersion >= 27) { send(subscription.stockTypeFilter()); } } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQSCANNER, "" + e); close(); } } public synchronized void reqMktData(int tickerId, Contract contract, String genericTickList, boolean snapshot) { if (!m_connected) { error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED, ""); return; } if (m_serverVersion < MIN_SERVER_VER_SNAPSHOT_MKT_DATA && snapshot) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support snapshot market data requests."); return; } if (m_serverVersion < MIN_SERVER_VER_UNDER_COMP) { if (contract.m_underComp != null) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support delta-neutral orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_REQ_MKT_DATA_CONID) { if (contract.m_conId > 0) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support conId parameter."); return; } } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass)) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support tradingClass parameter in reqMarketData."); return; } } final int VERSION = 10; try { // send req mkt data msg send(REQ_MKT_DATA); send(VERSION); send(tickerId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_REQ_MKT_DATA_CONID) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); if (m_serverVersion >= 15) { send(contract.m_multiplier); } send(contract.m_exchange); if (m_serverVersion >= 14) { send(contract.m_primaryExch); } send(contract.m_currency); if (m_serverVersion >= 2) { send(contract.m_localSymbol); } if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } if (m_serverVersion >= 8 && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { if (contract.m_comboLegs == null) { send(0); } else { send(contract.m_comboLegs.size()); ComboLeg comboLeg; for (int i = 0; i < contract.m_comboLegs.size(); i++) { comboLeg = (ComboLeg) contract.m_comboLegs.get(i); send(comboLeg.m_conId); send(comboLeg.m_ratio); send(comboLeg.m_action); send(comboLeg.m_exchange); } } } if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) { if (contract.m_underComp != null) { UnderComp underComp = contract.m_underComp; send(true); send(underComp.m_conId); send(underComp.m_delta); send(underComp.m_price); } else { send(false); } } if (m_serverVersion >= 31) { /* * Note: Even though SHORTABLE tick type supported only starting server * version 33 it would be relatively expensive to expose this * restriction here. * * Therefore we are relying on TWS doing validation. */ send(genericTickList); } if (m_serverVersion >= MIN_SERVER_VER_SNAPSHOT_MKT_DATA) { send(snapshot); } } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQMKT, "" + e); close(); } } public synchronized void cancelHistoricalData(int tickerId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < 24) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support historical data query cancellation."); return; } final int VERSION = 1; // send cancel mkt data msg try { send(CANCEL_HISTORICAL_DATA); send(VERSION); send(tickerId); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_CANHISTDATA, "" + e); close(); } } public void cancelRealTimeBars(int tickerId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REAL_TIME_BARS) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support realtime bar data query cancellation."); return; } final int VERSION = 1; // send cancel mkt data msg try { send(CANCEL_REAL_TIME_BARS); send(VERSION); send(tickerId); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_CANRTBARS, "" + e); close(); } } /** * Note that formatData parameter affects intra-day bars only; 1-day bars * always return with date in YYYYMMDD format. */ public synchronized void reqHistoricalData(int tickerId, Contract contract, String endDateTime, String durationStr, String barSizeSetting, String whatToShow, int useRTH, int formatDate) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 5; try { if (m_serverVersion < 16) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support historical data backfill."); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass) || (contract.m_conId > 0)) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support conId and tradingClass parameters in reqHistroricalData."); return; } } send(REQ_HISTORICAL_DATA); send(VERSION); send(tickerId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); send(contract.m_multiplier); send(contract.m_exchange); send(contract.m_primaryExch); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } if (m_serverVersion >= 31) { send(contract.m_includeExpired ? 1 : 0); } if (m_serverVersion >= 20) { send(endDateTime); send(barSizeSetting); } send(durationStr); send(useRTH); send(whatToShow); if (m_serverVersion > 16) { send(formatDate); } if (BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { if (contract.m_comboLegs == null) { send(0); } else { send(contract.m_comboLegs.size()); ComboLeg comboLeg; for (int i = 0; i < contract.m_comboLegs.size(); i++) { comboLeg = (ComboLeg) contract.m_comboLegs.get(i); send(comboLeg.m_conId); send(comboLeg.m_ratio); send(comboLeg.m_action); send(comboLeg.m_exchange); } } } } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQHISTDATA, "" + e); close(); } } public synchronized void reqRealTimeBars(int tickerId, Contract contract, int barSize, String whatToShow, boolean useRTH) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REAL_TIME_BARS) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support real time bars."); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass) || (contract.m_conId > 0)) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support conId and tradingClass parameters in reqRealTimeBars."); return; } } final int VERSION = 2; try { // send req mkt data msg send(REQ_REAL_TIME_BARS); send(VERSION); send(tickerId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); send(contract.m_multiplier); send(contract.m_exchange); send(contract.m_primaryExch); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } send(barSize); // this parameter is not currently used send(whatToShow); send(useRTH); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQRTBARS, "" + e); close(); } } public synchronized void reqContractDetails(int reqId, Contract contract) { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >=4 if (m_serverVersion < 4) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } if (m_serverVersion < MIN_SERVER_VER_SEC_ID_TYPE) { if (!IsEmpty(contract.m_secIdType) || !IsEmpty(contract.m_secId)) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support secIdType and secId parameters."); return; } } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass)) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support tradingClass parameter in reqContractDetails."); return; } } final int VERSION = 7; try { // send req mkt data msg send(REQ_CONTRACT_DATA); send(VERSION); if (m_serverVersion >= MIN_SERVER_VER_CONTRACT_DATA_CHAIN) { send(reqId); } // send contract fields if (m_serverVersion >= MIN_SERVER_VER_CONTRACT_CONID) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); if (m_serverVersion >= 15) { send(contract.m_multiplier); } send(contract.m_exchange); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } if (m_serverVersion >= 31) { send(contract.m_includeExpired); } if (m_serverVersion >= MIN_SERVER_VER_SEC_ID_TYPE) { send(contract.m_secIdType); send(contract.m_secId); } } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQCONTRACT, "" + e); close(); } } public synchronized void reqMktDepth(int tickerId, Contract contract, int numRows) { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >=6 if (m_serverVersion < 6) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass) || (contract.m_conId > 0)) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support conId and tradingClass parameters in reqMktDepth."); return; } } final int VERSION = 4; try { // send req mkt data msg send(REQ_MKT_DEPTH); send(VERSION); send(tickerId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); if (m_serverVersion >= 15) { send(contract.m_multiplier); } send(contract.m_exchange); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } if (m_serverVersion >= 19) { send(numRows); } } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQMKTDEPTH, "" + e); close(); } } public synchronized void cancelMktData(int tickerId) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send cancel mkt data msg try { send(CANCEL_MKT_DATA); send(VERSION); send(tickerId); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_CANMKT, "" + e); close(); } } public synchronized void cancelMktDepth(int tickerId) { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >=6 if (m_serverVersion < 6) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } final int VERSION = 1; // send cancel mkt data msg try { send(CANCEL_MKT_DEPTH); send(VERSION); send(tickerId); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_CANMKTDEPTH, "" + e); close(); } } public synchronized void exerciseOptions(int tickerId, Contract contract, int exerciseAction, int exerciseQuantity, String account, int override) { // not connected? if (!m_connected) { notConnected(); return; } 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 < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass) || (contract.m_conId > 0)) { error(tickerId, EClientErrors.UPDATE_TWS, " It does not support conId and tradingClass parameters in exerciseOptions."); return; } } send(EXERCISE_OPTIONS); send(VERSION); send(tickerId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); send(contract.m_multiplier); send(contract.m_exchange); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } send(exerciseAction); send(exerciseQuantity); send(account); send(override); } catch (Exception e) { error(tickerId, EClientErrors.FAIL_SEND_REQMKT, "" + e); close(); } } public synchronized void placeOrder(int id, Contract contract, Order order) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS) { if (order.m_scaleInitLevelSize != Integer.MAX_VALUE || order.m_scalePriceIncrement != Double.MAX_VALUE) { error(id, EClientErrors.UPDATE_TWS, " It does not support Scale orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_SSHORT_COMBO_LEGS) { if (!contract.m_comboLegs.isEmpty()) { ComboLeg comboLeg; for (int i = 0; i < contract.m_comboLegs.size(); ++i) { comboLeg = (ComboLeg) contract.m_comboLegs.get(i); if (comboLeg.m_shortSaleSlot != 0 || !IsEmpty(comboLeg.m_designatedLocation)) { error(id, EClientErrors.UPDATE_TWS, " It does not support SSHORT flag for combo legs."); return; } } } } if (m_serverVersion < MIN_SERVER_VER_WHAT_IF_ORDERS) { if (order.m_whatIf) { error(id, EClientErrors.UPDATE_TWS, " It does not support what-if orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_UNDER_COMP) { if (contract.m_underComp != null) { error(id, EClientErrors.UPDATE_TWS, " It does not support delta-neutral orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS2) { if (order.m_scaleSubsLevelSize != Integer.MAX_VALUE) { error(id, EClientErrors.UPDATE_TWS, " It does not support Subsequent Level Size for Scale orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_ALGO_ORDERS) { if (!IsEmpty(order.m_algoStrategy)) { error(id, EClientErrors.UPDATE_TWS, " It does not support algo orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_NOT_HELD) { if (order.m_notHeld) { error(id, EClientErrors.UPDATE_TWS, " It does not support notHeld parameter."); return; } } if (m_serverVersion < MIN_SERVER_VER_SEC_ID_TYPE) { if (!IsEmpty(contract.m_secIdType) || !IsEmpty(contract.m_secId)) { error(id, EClientErrors.UPDATE_TWS, " It does not support secIdType and secId parameters."); return; } } if (m_serverVersion < MIN_SERVER_VER_PLACE_ORDER_CONID) { if (contract.m_conId > 0) { error(id, EClientErrors.UPDATE_TWS, " It does not support conId parameter."); return; } } if (m_serverVersion < MIN_SERVER_VER_SSHORTX) { if (order.m_exemptCode != -1) { error(id, EClientErrors.UPDATE_TWS, " It does not support exemptCode parameter."); return; } } if (m_serverVersion < MIN_SERVER_VER_SSHORTX) { if (!contract.m_comboLegs.isEmpty()) { ComboLeg comboLeg; for (int i = 0; i < contract.m_comboLegs.size(); ++i) { comboLeg = (ComboLeg) contract.m_comboLegs.get(i); if (comboLeg.m_exemptCode != -1) { error(id, EClientErrors.UPDATE_TWS, " It does not support exemptCode parameter."); return; } } } } if (m_serverVersion < MIN_SERVER_VER_HEDGE_ORDERS) { if (!IsEmpty(order.m_hedgeType)) { error(id, EClientErrors.UPDATE_TWS, " It does not support hedge orders."); return; } } if (m_serverVersion < MIN_SERVER_VER_OPT_OUT_SMART_ROUTING) { if (order.m_optOutSmartRouting) { error(id, EClientErrors.UPDATE_TWS, " It does not support optOutSmartRouting parameter."); return; } } if (m_serverVersion < MIN_SERVER_VER_DELTA_NEUTRAL_CONID) { if (order.m_deltaNeutralConId > 0 || !IsEmpty(order.m_deltaNeutralSettlingFirm) || !IsEmpty(order.m_deltaNeutralClearingAccount) || !IsEmpty(order.m_deltaNeutralClearingIntent)) { error(id, EClientErrors.UPDATE_TWS, " It does not support deltaNeutral parameters: ConId, SettlingFirm, ClearingAccount, ClearingIntent"); return; } } if (m_serverVersion < MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE) { if (!IsEmpty(order.m_deltaNeutralOpenClose) || order.m_deltaNeutralShortSale || order.m_deltaNeutralShortSaleSlot > 0 || !IsEmpty(order.m_deltaNeutralDesignatedLocation)) { error(id, EClientErrors.UPDATE_TWS, " It does not support deltaNeutral parameters: OpenClose, ShortSale, ShortSaleSlot, DesignatedLocation"); return; } } if (m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS3) { if (order.m_scalePriceIncrement > 0 && order.m_scalePriceIncrement != Double.MAX_VALUE) { if (order.m_scalePriceAdjustValue != Double.MAX_VALUE || order.m_scalePriceAdjustInterval != Integer.MAX_VALUE || order.m_scaleProfitOffset != Double.MAX_VALUE || order.m_scaleAutoReset || order.m_scaleInitPosition != Integer.MAX_VALUE || order.m_scaleInitFillQty != Integer.MAX_VALUE || order.m_scaleRandomPercent) { error(id, EClientErrors.UPDATE_TWS, " It does not support Scale order parameters: PriceAdjustValue, PriceAdjustInterval, " + "ProfitOffset, AutoReset, InitPosition, InitFillQty and RandomPercent"); return; } } } if (m_serverVersion < MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { if (!order.m_orderComboLegs.isEmpty()) { OrderComboLeg orderComboLeg; for (int i = 0; i < order.m_orderComboLegs.size(); ++i) { orderComboLeg = (OrderComboLeg) order.m_orderComboLegs.get(i); if (orderComboLeg.m_price != Double.MAX_VALUE) { error(id, EClientErrors.UPDATE_TWS, " It does not support per-leg prices for order combo legs."); return; } } } } if (m_serverVersion < MIN_SERVER_VER_TRAILING_PERCENT) { if (order.m_trailingPercent != Double.MAX_VALUE) { error(id, EClientErrors.UPDATE_TWS, " It does not support trailing percent parameter"); return; } } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass)) { error(id, EClientErrors.UPDATE_TWS, " It does not support tradingClass parameters in placeOrder."); return; } } int VERSION = (m_serverVersion < MIN_SERVER_VER_NOT_HELD) ? 27 : 40; // send place order msg try { send(PLACE_ORDER); send(VERSION); send(id); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_PLACE_ORDER_CONID) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); if (m_serverVersion >= 15) { send(contract.m_multiplier); } send(contract.m_exchange); if (m_serverVersion >= 14) { send(contract.m_primaryExch); } send(contract.m_currency); if (m_serverVersion >= 2) { send(contract.m_localSymbol); } if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } if (m_serverVersion >= MIN_SERVER_VER_SEC_ID_TYPE) { send(contract.m_secIdType); send(contract.m_secId); } // send main order fields send(order.m_action); send(order.m_totalQuantity); send(order.m_orderType); if (m_serverVersion < MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE) { send(order.m_lmtPrice == Double.MAX_VALUE ? 0 : order.m_lmtPrice); } else { sendMax(order.m_lmtPrice); } if (m_serverVersion < MIN_SERVER_VER_TRAILING_PERCENT) { send(order.m_auxPrice == Double.MAX_VALUE ? 0 : order.m_auxPrice); } else { sendMax(order.m_auxPrice); } // send extended order fields send(order.m_tif); send(order.m_ocaGroup); send(order.m_account); send(order.m_openClose); send(order.m_origin); send(order.m_orderRef); send(order.m_transmit); if (m_serverVersion >= 4) { send(order.m_parentId); } if (m_serverVersion >= 5) { send(order.m_blockOrder); send(order.m_sweepToFill); send(order.m_displaySize); send(order.m_triggerMethod); if (m_serverVersion < 38) { // will never happen send(/* order.m_ignoreRth */false); } else { send(order.m_outsideRth); } } if (m_serverVersion >= 7) { send(order.m_hidden); } // Send combo legs for BAG requests if (m_serverVersion >= 8 && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { if (contract.m_comboLegs == null) { send(0); } else { send(contract.m_comboLegs.size()); ComboLeg comboLeg; for (int i = 0; i < contract.m_comboLegs.size(); i++) { comboLeg = (ComboLeg) contract.m_comboLegs.get(i); send(comboLeg.m_conId); send(comboLeg.m_ratio); send(comboLeg.m_action); send(comboLeg.m_exchange); send(comboLeg.m_openClose); if (m_serverVersion >= MIN_SERVER_VER_SSHORT_COMBO_LEGS) { send(comboLeg.m_shortSaleSlot); send(comboLeg.m_designatedLocation); } if (m_serverVersion >= MIN_SERVER_VER_SSHORTX_OLD) { send(comboLeg.m_exemptCode); } } } } // Send order combo legs for BAG requests if (m_serverVersion >= MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { if (order.m_orderComboLegs == null) { send(0); } else { send(order.m_orderComboLegs.size()); for (int i = 0; i < order.m_orderComboLegs.size(); i++) { OrderComboLeg orderComboLeg = (OrderComboLeg) order.m_orderComboLegs.get(i); sendMax(orderComboLeg.m_price); } } } if (m_serverVersion >= MIN_SERVER_VER_SMART_COMBO_ROUTING_PARAMS && BAG_SEC_TYPE.equalsIgnoreCase(contract.m_secType)) { java.util.Vector smartComboRoutingParams = order.m_smartComboRoutingParams; int smartComboRoutingParamsCount = smartComboRoutingParams == null ? 0 : smartComboRoutingParams.size(); send(smartComboRoutingParamsCount); if (smartComboRoutingParamsCount > 0) { for (int i = 0; i < smartComboRoutingParamsCount; ++i) { TagValue tagValue = (TagValue) smartComboRoutingParams.get(i); send(tagValue.m_tag); send(tagValue.m_value); } } } if (m_serverVersion >= 9) { // send deprecated sharesAllocation field send(""); } if (m_serverVersion >= 10) { send(order.m_discretionaryAmt); } if (m_serverVersion >= 11) { send(order.m_goodAfterTime); } if (m_serverVersion >= 12) { send(order.m_goodTillDate); } if (m_serverVersion >= 13) { send(order.m_faGroup); send(order.m_faMethod); send(order.m_faPercentage); send(order.m_faProfile); } if (m_serverVersion >= 18) { // institutional short sale slot fields. send(order.m_shortSaleSlot); // 0 only for retail, 1 or 2 only for // institution. send(order.m_designatedLocation); // only populate when // order.m_shortSaleSlot = 2. } if (m_serverVersion >= MIN_SERVER_VER_SSHORTX_OLD) { send(order.m_exemptCode); } if (m_serverVersion >= 19) { send(order.m_ocaType); if (m_serverVersion < 38) { // will never happen send( /* order.m_rthOnly */false); } send(order.m_rule80A); send(order.m_settlingFirm); send(order.m_allOrNone); sendMax(order.m_minQty); sendMax(order.m_percentOffset); send(order.m_eTradeOnly); send(order.m_firmQuoteOnly); sendMax(order.m_nbboPriceCap); sendMax(order.m_auctionStrategy); sendMax(order.m_startingPrice); sendMax(order.m_stockRefPrice); sendMax(order.m_delta); // Volatility orders had specific watermark price attribs in server // version 26 double lower = (m_serverVersion == 26 && order.m_orderType.equals("VOL")) ? Double.MAX_VALUE : order.m_stockRangeLower; double upper = (m_serverVersion == 26 && order.m_orderType.equals("VOL")) ? Double.MAX_VALUE : order.m_stockRangeUpper; sendMax(lower); sendMax(upper); } if (m_serverVersion >= 22) { send(order.m_overridePercentageConstraints); } if (m_serverVersion >= 26) { // Volatility orders sendMax(order.m_volatility); sendMax(order.m_volatilityType); if (m_serverVersion < 28) { send(order.m_deltaNeutralOrderType.equalsIgnoreCase("MKT")); } else { send(order.m_deltaNeutralOrderType); sendMax(order.m_deltaNeutralAuxPrice); if (m_serverVersion >= MIN_SERVER_VER_DELTA_NEUTRAL_CONID && !IsEmpty(order.m_deltaNeutralOrderType)) { send(order.m_deltaNeutralConId); send(order.m_deltaNeutralSettlingFirm); send(order.m_deltaNeutralClearingAccount); send(order.m_deltaNeutralClearingIntent); } if (m_serverVersion >= MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE && !IsEmpty(order.m_deltaNeutralOrderType)) { send(order.m_deltaNeutralOpenClose); send(order.m_deltaNeutralShortSale); send(order.m_deltaNeutralShortSaleSlot); send(order.m_deltaNeutralDesignatedLocation); } } send(order.m_continuousUpdate); if (m_serverVersion == 26) { // Volatility orders had specific watermark price attribs in server // version 26 double lower = order.m_orderType.equals("VOL") ? order.m_stockRangeLower : Double.MAX_VALUE; double upper = order.m_orderType.equals("VOL") ? order.m_stockRangeUpper : Double.MAX_VALUE; sendMax(lower); sendMax(upper); } sendMax(order.m_referencePriceType); } if (m_serverVersion >= 30) { // TRAIL_STOP_LIMIT stop price sendMax(order.m_trailStopPrice); } if (m_serverVersion >= MIN_SERVER_VER_TRAILING_PERCENT) { sendMax(order.m_trailingPercent); } if (m_serverVersion >= MIN_SERVER_VER_SCALE_ORDERS) { if (m_serverVersion >= MIN_SERVER_VER_SCALE_ORDERS2) { sendMax(order.m_scaleInitLevelSize); sendMax(order.m_scaleSubsLevelSize); } else { send(""); sendMax(order.m_scaleInitLevelSize); } sendMax(order.m_scalePriceIncrement); } if (m_serverVersion >= MIN_SERVER_VER_SCALE_ORDERS3 && order.m_scalePriceIncrement > 0.0 && order.m_scalePriceIncrement != Double.MAX_VALUE) { sendMax(order.m_scalePriceAdjustValue); sendMax(order.m_scalePriceAdjustInterval); sendMax(order.m_scaleProfitOffset); send(order.m_scaleAutoReset); sendMax(order.m_scaleInitPosition); sendMax(order.m_scaleInitFillQty); send(order.m_scaleRandomPercent); } if (m_serverVersion >= MIN_SERVER_VER_HEDGE_ORDERS) { send(order.m_hedgeType); if (!IsEmpty(order.m_hedgeType)) { send(order.m_hedgeParam); } } if (m_serverVersion >= MIN_SERVER_VER_OPT_OUT_SMART_ROUTING) { send(order.m_optOutSmartRouting); } if (m_serverVersion >= MIN_SERVER_VER_PTA_ORDERS) { send(order.m_clearingAccount); send(order.m_clearingIntent); } if (m_serverVersion >= MIN_SERVER_VER_NOT_HELD) { send(order.m_notHeld); } if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) { if (contract.m_underComp != null) { UnderComp underComp = contract.m_underComp; send(true); send(underComp.m_conId); send(underComp.m_delta); send(underComp.m_price); } else { send(false); } } if (m_serverVersion >= MIN_SERVER_VER_ALGO_ORDERS) { send(order.m_algoStrategy); if (!IsEmpty(order.m_algoStrategy)) { java.util.Vector algoParams = order.m_algoParams; int algoParamsCount = algoParams == null ? 0 : algoParams.size(); send(algoParamsCount); if (algoParamsCount > 0) { for (int i = 0; i < algoParamsCount; ++i) { TagValue tagValue = (TagValue) algoParams.get(i); send(tagValue.m_tag); send(tagValue.m_value); } } } } if (m_serverVersion >= MIN_SERVER_VER_WHAT_IF_ORDERS) { send(order.m_whatIf); } } catch (Exception e) { error(id, EClientErrors.FAIL_SEND_ORDER, "" + e); close(); } } public synchronized void reqAccountUpdates(boolean subscribe, String acctCode) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 2; // send cancel order msg try { send(REQ_ACCOUNT_DATA); send(VERSION); send(subscribe); // Send the account code. This will only be used for FA clients if (m_serverVersion >= 9) { send(acctCode); } } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_ACCT, "" + e); close(); } } public synchronized void reqExecutions(int reqId, ExecutionFilter filter) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 3; // send cancel order msg try { send(REQ_EXECUTIONS); send(VERSION); if (m_serverVersion >= MIN_SERVER_VER_EXECUTION_DATA_CHAIN) { send(reqId); } // Send the execution rpt filter data if (m_serverVersion >= 9) { send(filter.m_clientId); send(filter.m_acctCode); // Note that the valid format for m_time is "yyyymmdd-hh:mm:ss" send(filter.m_time); send(filter.m_symbol); send(filter.m_secType); send(filter.m_exchange); send(filter.m_side); } } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_EXEC, "" + e); close(); } } public synchronized void cancelOrder(int id) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send cancel order msg try { send(CANCEL_ORDER); send(VERSION); send(id); } catch (Exception e) { error(id, EClientErrors.FAIL_SEND_CORDER, "" + e); close(); } } public synchronized void reqOpenOrders() { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send cancel order msg try { send(REQ_OPEN_ORDERS); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_OORDER, "" + e); close(); } } public synchronized void reqIds(int numIds) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; try { send(REQ_IDS); send(VERSION); send(numIds); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CORDER, "" + e); close(); } } public synchronized void reqNewsBulletins(boolean allMsgs) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; try { send(REQ_NEWS_BULLETINS); send(VERSION); send(allMsgs); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CORDER, "" + e); close(); } } public synchronized void cancelNewsBulletins() { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send cancel order msg try { send(CANCEL_NEWS_BULLETINS); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CORDER, "" + e); close(); } } public synchronized void setServerLogLevel(int logLevel) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send the set server logging level message try { send(SET_SERVER_LOGLEVEL); send(VERSION); send(logLevel); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_SERVER_LOG_LEVEL, "" + e); close(); } } public synchronized void reqAutoOpenOrders(boolean bAutoBind) { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send req open orders msg try { send(REQ_AUTO_OPEN_ORDERS); send(VERSION); send(bAutoBind); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_OORDER, "" + e); close(); } } public synchronized void reqAllOpenOrders() { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send req all open orders msg try { send(REQ_ALL_OPEN_ORDERS); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_OORDER, "" + e); close(); } } public synchronized void reqManagedAccts() { // not connected? if (!m_connected) { notConnected(); return; } final int VERSION = 1; // send req FA managed accounts msg try { send(REQ_MANAGED_ACCTS); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_OORDER, "" + e); close(); } } public synchronized void requestFA(int faDataType) { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >= 13 if (m_serverVersion < 13) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } final int VERSION = 1; try { send(REQ_FA); send(VERSION); send(faDataType); } catch (Exception e) { error(faDataType, EClientErrors.FAIL_SEND_FA_REQUEST, "" + e); close(); } } public synchronized void replaceFA(int faDataType, String xml) { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >= 13 if (m_serverVersion < 13) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS.code(), EClientErrors.UPDATE_TWS.msg()); return; } final int VERSION = 1; try { send(REPLACE_FA); send(VERSION); send(faDataType); send(xml); } catch (Exception e) { error(faDataType, EClientErrors.FAIL_SEND_FA_REPLACE, "" + e); close(); } } public synchronized void reqCurrentTime() { // not connected? if (!m_connected) { notConnected(); return; } // This feature is only available for versions of TWS >= 33 if (m_serverVersion < 33) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support current time requests."); return; } final int VERSION = 1; try { send(REQ_CURRENT_TIME); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQCURRTIME, "" + e); close(); } } public synchronized void reqFundamentalData(int reqId, Contract contract, String reportType) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_FUNDAMENTAL_DATA) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support fundamental data requests."); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (contract.m_conId > 0) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support conId parameter in reqFundamentalData."); return; } } final int VERSION = 2; try { // send req fund data msg send(REQ_FUNDAMENTAL_DATA); send(VERSION); send(reqId); // send contract fields if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_conId); } send(contract.m_symbol); send(contract.m_secType); send(contract.m_exchange); send(contract.m_primaryExch); send(contract.m_currency); send(contract.m_localSymbol); send(reportType); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_REQFUNDDATA, "" + e); close(); } } public synchronized void cancelFundamentalData(int reqId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_FUNDAMENTAL_DATA) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support fundamental data requests."); return; } final int VERSION = 1; try { // send req mkt data msg send(CANCEL_FUNDAMENTAL_DATA); send(VERSION); send(reqId); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_CANFUNDDATA, "" + e); close(); } } public synchronized void calculateImpliedVolatility(int reqId, Contract contract, double optionPrice, double underPrice) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REQ_CALC_IMPLIED_VOLAT) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support calculate implied volatility requests."); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass)) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support tradingClass parameter in calculateImpliedVolatility."); return; } } final int VERSION = 2; try { // send calculate implied volatility msg send(REQ_CALC_IMPLIED_VOLAT); send(VERSION); send(reqId); // send contract fields send(contract.m_conId); send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); send(contract.m_multiplier); send(contract.m_exchange); send(contract.m_primaryExch); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } send(optionPrice); send(underPrice); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_REQCALCIMPLIEDVOLAT, "" + e); close(); } } public synchronized void cancelCalculateImpliedVolatility(int reqId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_CANCEL_CALC_IMPLIED_VOLAT) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support calculate implied volatility cancellation."); return; } final int VERSION = 1; try { // send cancel calculate implied volatility msg send(CANCEL_CALC_IMPLIED_VOLAT); send(VERSION); send(reqId); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_CANCALCIMPLIEDVOLAT, "" + e); close(); } } public synchronized void calculateOptionPrice(int reqId, Contract contract, double volatility, double underPrice) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REQ_CALC_OPTION_PRICE) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support calculate option price requests."); return; } if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { if (!IsEmpty(contract.m_tradingClass)) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support tradingClass parameter in calculateOptionPrice."); return; } } final int VERSION = 2; try { // send calculate option price msg send(REQ_CALC_OPTION_PRICE); send(VERSION); send(reqId); // send contract fields send(contract.m_conId); send(contract.m_symbol); send(contract.m_secType); send(contract.m_expiry); send(contract.m_strike); send(contract.m_right); send(contract.m_multiplier); send(contract.m_exchange); send(contract.m_primaryExch); send(contract.m_currency); send(contract.m_localSymbol); if (m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { send(contract.m_tradingClass); } send(volatility); send(underPrice); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_REQCALCOPTIONPRICE, "" + e); close(); } } public synchronized void cancelCalculateOptionPrice(int reqId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_CANCEL_CALC_OPTION_PRICE) { error(reqId, EClientErrors.UPDATE_TWS, " It does not support calculate option price cancellation."); return; } final int VERSION = 1; try { // send cancel calculate option price msg send(CANCEL_CALC_OPTION_PRICE); send(VERSION); send(reqId); } catch (Exception e) { error(reqId, EClientErrors.FAIL_SEND_CANCALCOPTIONPRICE, "" + e); close(); } } public synchronized void reqGlobalCancel() { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REQ_GLOBAL_CANCEL) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support globalCancel requests."); return; } final int VERSION = 1; // send request global cancel msg try { send(REQ_GLOBAL_CANCEL); send(VERSION); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQGLOBALCANCEL, "" + e); close(); } } public synchronized void reqMarketDataType(int marketDataType) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_REQ_MARKET_DATA_TYPE) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support marketDataType requests."); return; } final int VERSION = 1; // send the reqMarketDataType message try { send(REQ_MARKET_DATA_TYPE); send(VERSION); send(marketDataType); } catch (Exception e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQMARKETDATATYPE, "" + e); close(); } } public synchronized void reqPositions() { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_ACCT_SUMMARY) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support position requests."); return; } final int VERSION = 1; Builder b = new Builder(); b.send(REQ_POSITIONS); b.send(VERSION); try { m_dos.write(b.getBytes()); } catch (IOException e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQPOSITIONS, "" + e); } } public synchronized void cancelPositions() { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_ACCT_SUMMARY) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support position cancellation."); return; } final int VERSION = 1; Builder b = new Builder(); b.send(CANCEL_POSITIONS); b.send(VERSION); try { m_dos.write(b.getBytes()); } catch (IOException e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CANPOSITIONS, "" + e); } } public synchronized void reqAccountSummary(int reqId, String group, String tags) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_ACCT_SUMMARY) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support account summary requests."); return; } final int VERSION = 1; Builder b = new Builder(); b.send(REQ_ACCOUNT_SUMMARY); b.send(VERSION); b.send(reqId); b.send(group); b.send(tags); try { m_dos.write(b.getBytes()); } catch (IOException e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_REQACCOUNTDATA, "" + e); } } public synchronized void cancelAccountSummary(int reqId) { // not connected? if (!m_connected) { notConnected(); return; } if (m_serverVersion < MIN_SERVER_VER_ACCT_SUMMARY) { error(EClientErrors.NO_VALID_ID, EClientErrors.UPDATE_TWS, " It does not support account summary cancellation."); return; } final int VERSION = 1; Builder b = new Builder(); b.send(CANCEL_ACCOUNT_SUMMARY); b.send(VERSION); b.send(reqId); try { m_dos.write(b.getBytes()); } catch (IOException e) { error(EClientErrors.NO_VALID_ID, EClientErrors.FAIL_SEND_CANACCOUNTDATA, "" + e); } } /** @deprecated, never called. */ protected synchronized void error(String err) { m_anyWrapper.error(err); } protected synchronized void error(int id, int errorCode, String errorMsg) { m_anyWrapper.error(id, errorCode, errorMsg); } protected void close() { eDisconnect(); wrapper().connectionClosed(); } private static boolean is(String str) { // return true if the string is not empty return str != null && str.length() > 0; } private static boolean isNull(String str) { // return true if the string is null or empty return !is(str); } protected void error(int id, EClientErrors.CodeMsgPair pair, String tail) { error(id, pair.code(), pair.msg() + tail); } protected void send(String str) throws IOException { // write string to data buffer; writer thread will // write it to socket if (!IsEmpty(str)) { m_dos.write(str.getBytes()); } sendEOL(); } private void sendEOL() throws IOException { m_dos.write(EOL); } protected void send(int val) throws IOException { send(String.valueOf(val)); } protected void send(char val) throws IOException { m_dos.write(val); sendEOL(); } protected void send(double val) throws IOException { send(String.valueOf(val)); } protected void send(long val) throws IOException { send(String.valueOf(val)); } private void sendMax(double val) throws IOException { if (val == Double.MAX_VALUE) { sendEOL(); } else { send(String.valueOf(val)); } } private void sendMax(int val) throws IOException { if (val == Integer.MAX_VALUE) { sendEOL(); } else { send(String.valueOf(val)); } } protected void send(boolean val) throws IOException { send(val ? 1 : 0); } private static boolean IsEmpty(String str) { return Util.StringIsEmpty(str); } protected void notConnected() { error(EClientErrors.NO_VALID_ID, EClientErrors.NOT_CONNECTED, ""); } }