diff --git a/vn.ib/CMakeLists.txt b/vn.ib/CMakeLists.txt new file mode 100644 index 00000000..e24b0646 --- /dev/null +++ b/vn.ib/CMakeLists.txt @@ -0,0 +1,85 @@ +cmake_minimum_required(VERSION 2.8) +project(vn_ib_api) + +# 设置使用的编译器 +set(CMAKE_BUILD_TYPE "Release") +if (CMAKE_COMPILER_IS_GNUC OR CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11") +endif () + +# 设置输出目录 +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) + +# 使用64位编译 +option(USE_64BITS "comiple 64bits" ON) +if (USE_64BITS) + add_definitions(-DUSE_64BITS) + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") +endif() + +# 设置C++ API源文件的所在目录 +if (WIN32) + set(IBAPI_PATH ibapi) +elseif (UNIX) + message("Under unix: " ${CMAKE_SIZEOF_VOID_P}) + if (CMAKE_SIZEOF_VOID_P MATCHES "8") + set(IBAPI_PATH ibapi) + endif() +endif() +include_directories(${IBAPI_PATH}) +#set(IBAPI_LIBRARY ) +#find_library(IBAPI_LIBRARY +# NAMES thostmduserapi +# PATHS ${IBAPI_PATH}) +#find_library(IBAPI_TD_LIBRARY +# NAMES thosttraderapi +# PATHS ${IBAPI_PATH}) + + +# 设置编译源文件 +set (vnib ) + +option(BUILD_IB "build ib" ON) +if (BUILD_IB) + add_definitions(-DBUILD_IB) + set(IB_PATH vnib/vnib) + include_directories(IB_PATH) + set(VN_IB_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/vnib/vnib/vnib.cpp) + add_library(vnib SHARED ${VN_IB_SOURCE}) +endif() + +# 设置Python所在的目录 +set(PYTHON_LIBRARY ) +if (WIN32) +set(PYTHON_INCLUDE_PATH C:/Python27/include) +find_library(PYTHON_LIBRARY + NAMES python27 + PATHS C:/Python27/libs) +include_directories(${PYTHON_INCLUDE_PATH}) +else() +set(PYTHON_INCLUDE_PATH /usr/include/python2.7/) +find_library(PYTHON_LIBRARY + NAMES python2.7 + PATHS /usr/lib/x86_64-linux-gnu) +include_directories(${PYTHON_INCLUDE_PATH}) +endif() + +# 链接boost库,anaconda +if (WIN32) + set(Boost_USE_STATIC_LIBS ON) #链接boost静态库 +endif() +set(Boost_USE_MULTITHREADED ON) +find_package(Boost 1.55.0 COMPONENTS python thread date_time system chrono REQUIRED) # 如果boost库没有完全编译,需要将编译的库明确地指出,否者message(${Boost_LIBRARIES})会出错 +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) +endif() + +# 去掉生成的so文件名中前缀的lib +set_target_properties(vnib PROPERTIES PREFIX "") + +# 链接生成.so文件 +target_link_libraries(vnib ${Boost_LIBRARIES} ${PYTHON_LIBRARY} ${IBAPI_LIBRARY}) + + diff --git a/vn.ib/README.md b/vn.ib/README.md index e097b969..34a396fa 100644 --- a/vn.ib/README.md +++ b/vn.ib/README.md @@ -14,8 +14,13 @@ 4. vn.ib基于较新的IB官方API(9.72 beta)开发,IbPy则是采用了较老的API(9.70 stable) +### 对原生接口的修改部分 +shared_ptr.h和SoftDollerTier.h中加入了对象比较函数的代码,用于实现其对应vector的自动Python封装。 + ### API版本 -版本:IB API for Windows beta 9.72 +版本:IB API for Windows beta 9.72.18 + +日期:2016-09-14 链接:[http://interactivebrokers.github.io/](http://interactivebrokers.github.io/) diff --git a/vn.ib/build.sh b/vn.ib/build.sh new file mode 100644 index 00000000..948b6119 --- /dev/null +++ b/vn.ib/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Written by Suzhengchun on 20160213 + +set -e +BUILDDIR=build +rm -rf $BUILDDIR +if [ ! -f $BUILDDIR ]; then + mkdir -p $BUILDDIR +fi +pushd $BUILDDIR +cmake .. +make VERBOSE=1 -j 1 +popd diff --git a/vn.ib/ibapi/client/EClient.h b/vn.ib/ibapi/client/EClient.h deleted file mode 100644 index 2aa9d607..00000000 --- a/vn.ib/ibapi/client/EClient.h +++ /dev/null @@ -1,224 +0,0 @@ -/* 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. */ - -#pragma once -#ifndef eclient_h__INCLUDED -#define eclient_h__INCLUDED - - -#include -#include -#include -#include -#include "CommonDefs.h" -#include "TagValue.h" - -struct Contract; -struct Order; -struct ExecutionFilter; -struct ScannerSubscription; -struct ETransport; - -class EWrapper; -typedef std::vector BytesVec; - - -class TWSAPIDLLEXP EClient -{ -public: - - explicit EClient(EWrapper *ptr, ETransport *pTransport); - ~EClient(); - - virtual void eDisconnect() = 0; - - int clientId() const { return m_clientId; } - - const std::string& optionalCapabilities() const; - void setOptionalCapabilities(const std::string& optCapts); - - void setConnectOptions(const std::string& connectOptions); - void disableUseV100Plus(); - bool usingV100Plus(); - -protected: - - void eConnectBase(); - void eDisconnectBase(); - -public: - - enum ConnState { - CS_DISCONNECTED, - CS_CONNECTING, - CS_CONNECTED, - CS_REDIRECT - }; - - // connection state - ConnState connState() const; - bool isConnected() const; - - const std::string& host() const { return m_host; } - unsigned port() const { return m_port; } - -public: - - // access to protected variables - EWrapper * getWrapper() const; -protected: - void setClientId( int clientId); - void setExtraAuth( bool extraAuth); - void setHost( const std::string& host); - void setPort( unsigned port); - -public: - - bool isInBufferEmpty() const; - - // override virtual funcs from EClient - int serverVersion(); - std::string TwsConnectionTime(); - void reqMktData(TickerId id, const Contract& contract, - const std::string& genericTicks, bool snapshot, const TagValueListSPtr& mktDataOptions); - void cancelMktData(TickerId id); - void placeOrder(OrderId id, const Contract& contract, const Order& order); - void cancelOrder(OrderId id) ; - void reqOpenOrders(); - void reqAccountUpdates(bool subscribe, const std::string& acctCode); - void reqExecutions(int reqId, const ExecutionFilter& filter); - void reqIds(int numIds); - void reqContractDetails(int reqId, const Contract& contract); - void reqMktDepth(TickerId tickerId, const Contract& contract, int numRows, const TagValueListSPtr& mktDepthOptions); - void cancelMktDepth(TickerId tickerId); - void reqNewsBulletins(bool allMsgs); - void cancelNewsBulletins(); - void setServerLogLevel(int level); - void reqAutoOpenOrders(bool bAutoBind); - void reqAllOpenOrders(); - void reqManagedAccts(); - void requestFA(faDataType pFaDataType); - void replaceFA(faDataType pFaDataType, const std::string& cxml); - void reqHistoricalData( TickerId id, const Contract& contract, - const std::string& endDateTime, const std::string& durationStr, - const std::string& barSizeSetting, const std::string& whatToShow, - int useRTH, int formatDate, const TagValueListSPtr& chartOptions); - void exerciseOptions(TickerId tickerId, const Contract& contract, - int exerciseAction, int exerciseQuantity, - const std::string& account, int override); - void cancelHistoricalData(TickerId tickerId ); - void reqRealTimeBars(TickerId id, const Contract& contract, int barSize, - const std::string& whatToShow, bool useRTH, const TagValueListSPtr& realTimeBarsOptions); - void cancelRealTimeBars(TickerId tickerId ); - void cancelScannerSubscription(int tickerId); - void reqScannerParameters(); - void reqScannerSubscription(int tickerId, const ScannerSubscription& subscription, const TagValueListSPtr& scannerSubscriptionOptions); - void reqCurrentTime(); - void reqFundamentalData(TickerId reqId, const Contract&, const std::string& reportType); - void cancelFundamentalData(TickerId reqId); - void calculateImpliedVolatility(TickerId reqId, const Contract& contract, double optionPrice, double underPrice); - void calculateOptionPrice(TickerId reqId, const Contract& contract, double volatility, double underPrice); - void cancelCalculateImpliedVolatility(TickerId reqId); - void cancelCalculateOptionPrice(TickerId reqId); - void reqGlobalCancel(); - void reqMarketDataType(int marketDataType); - void reqPositions(); - void cancelPositions(); - void reqAccountSummary( int reqId, const std::string& groupName, const std::string& tags); - void cancelAccountSummary( int reqId); - void verifyRequest( const std::string& apiName, const std::string& apiVersion); - void verifyMessage( const std::string& apiData); - void verifyAndAuthRequest( const std::string& apiName, const std::string& apiVersion, const std::string& opaqueIsvKey); - void verifyAndAuthMessage( const std::string& apiData, const std::string& xyzResponse); - void queryDisplayGroups( int reqId); - void subscribeToGroupEvents( int reqId, int groupId); - void updateDisplayGroup( int reqId, const std::string& contractInfo); - void unsubscribeFromGroupEvents( int reqId); - void reqPositionsMulti( int reqId, const std::string& account, const std::string& modelCode); - void cancelPositionsMulti( int reqId); - void reqAccountUpdatessMulti( int reqId, const std::string& account, const std::string& modelCode, bool ledgerAndNLV); - void cancelAccountUpdatesMulti( int reqId); - void reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, const std::string& futFopExchange, const std::string& underlyingSecType, int underlyingConId); - -private: - - virtual int receive(char* buf, size_t sz) = 0; - -protected: - - virtual void prepareBufferImpl(std::ostream&) const = 0; - virtual void prepareBuffer(std::ostream&) const = 0; - virtual bool closeAndSend(std::string msg, unsigned offset = 0) = 0; - virtual int bufferedSend(const std::string& msg); - -protected: - int bufferedRead(); - - // try to process connection request ack -private: - // try to process single msg - int processMsgImpl(const char*& ptr, const char* endPtr); - int processMsg(const char*& ptr, const char* endPtr); - - typedef int (EClient::*messageHandler)(const char*& ptr, const char* endPtr); - int processOnePrefixedMsg(const char*& ptr, const char* endPtr, messageHandler); - -public: - void startApi(); - - - // encoders - template static void EncodeField(std::ostream&, T); - - // "max" encoders - static void EncodeFieldMax(std::ostream& os, int); - static void EncodeFieldMax(std::ostream& os, double); - - // socket state -private: - virtual bool isSocketOK() const = 0; - -protected: - - bool isConnecting() const; - int sendConnectRequest(); - bool extraAuth(); - -protected: - - EWrapper *m_pEWrapper; - std::auto_ptr m_transport; - -private: - BytesVec m_inBuffer; - - std::string m_host; - int m_port; - - int m_clientId; - - ConnState m_connState; - bool m_extraAuth; - -protected: - int m_serverVersion; - std::string m_TwsTime; - -private: - std::string m_optionalCapabilities; - - std::string m_connectOptions; - -protected: - bool m_useV100Plus; - -}; - -template<> void EClient::EncodeField(std::ostream& os, bool); -template<> void EClient::EncodeField(std::ostream& os, double); - -#define ENCODE_FIELD(x) EClient::EncodeField(msg, x); -#define ENCODE_FIELD_MAX(x) EClient::EncodeFieldMax(msg, x); - - -#endif diff --git a/vn.ib/ibapi/lib/TwsSocketClient.lib b/vn.ib/ibapi/lib/TwsSocketClient.lib deleted file mode 100644 index 61cc526f..00000000 Binary files a/vn.ib/ibapi/lib/TwsSocketClient.lib and /dev/null differ diff --git a/vn.ib/ibapi/client/CommissionReport.h b/vn.ib/ibapi/linux/client/CommissionReport.h similarity index 100% rename from vn.ib/ibapi/client/CommissionReport.h rename to vn.ib/ibapi/linux/client/CommissionReport.h diff --git a/vn.ib/ibapi/client/CommonDefs.h b/vn.ib/ibapi/linux/client/CommonDefs.h similarity index 100% rename from vn.ib/ibapi/client/CommonDefs.h rename to vn.ib/ibapi/linux/client/CommonDefs.h diff --git a/vn.ib/ibapi/client/Contract.h b/vn.ib/ibapi/linux/client/Contract.h similarity index 100% rename from vn.ib/ibapi/client/Contract.h rename to vn.ib/ibapi/linux/client/Contract.h diff --git a/vn.ib/ibapi/client/ContractCondition.cpp b/vn.ib/ibapi/linux/client/ContractCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/ContractCondition.cpp rename to vn.ib/ibapi/linux/client/ContractCondition.cpp diff --git a/vn.ib/ibapi/client/ContractCondition.h b/vn.ib/ibapi/linux/client/ContractCondition.h similarity index 100% rename from vn.ib/ibapi/client/ContractCondition.h rename to vn.ib/ibapi/linux/client/ContractCondition.h diff --git a/vn.ib/ibapi/client/DefaultEWrapper.cpp b/vn.ib/ibapi/linux/client/DefaultEWrapper.cpp similarity index 98% rename from vn.ib/ibapi/client/DefaultEWrapper.cpp rename to vn.ib/ibapi/linux/client/DefaultEWrapper.cpp index d72d96fd..6e49ad33 100644 --- a/vn.ib/ibapi/client/DefaultEWrapper.cpp +++ b/vn.ib/ibapi/linux/client/DefaultEWrapper.cpp @@ -72,5 +72,6 @@ void DefaultEWrapper::accountUpdateMulti( int reqId, const std::string& account, void DefaultEWrapper::accountUpdateMultiEnd( int reqId) { } void DefaultEWrapper::securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes) { } void DefaultEWrapper::securityDefinitionOptionalParameterEnd(int reqId) { } +void DefaultEWrapper::softDollarTiers(int reqId, const std::vector &tiers) { } diff --git a/vn.ib/ibapi/client/DefaultEWrapper.h b/vn.ib/ibapi/linux/client/DefaultEWrapper.h similarity index 98% rename from vn.ib/ibapi/client/DefaultEWrapper.h rename to vn.ib/ibapi/linux/client/DefaultEWrapper.h index be542dc3..bf88d4d7 100644 --- a/vn.ib/ibapi/client/DefaultEWrapper.h +++ b/vn.ib/ibapi/linux/client/DefaultEWrapper.h @@ -76,5 +76,6 @@ public: virtual void accountUpdateMultiEnd( int reqId); virtual void securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes); virtual void securityDefinitionOptionalParameterEnd(int reqId); + virtual void softDollarTiers(int reqId, const std::vector &tiers); }; diff --git a/vn.ib/ibapi/client/EClient.cpp b/vn.ib/ibapi/linux/client/EClient.cpp similarity index 89% rename from vn.ib/ibapi/client/EClient.cpp rename to vn.ib/ibapi/linux/client/EClient.cpp index e88a9301..c295cf54 100644 --- a/vn.ib/ibapi/client/EClient.cpp +++ b/vn.ib/ibapi/linux/client/EClient.cpp @@ -27,157 +27,7 @@ #include #include -///////////////////////////////////////////////////////////////////////////////// -// SOCKET CLIENT VERSION CHANGE LOG : Incremented when the format of incomming -// server responses change -///////////////////////////////////////////////////////////////////////////////// -// constants -// 6 = Added parentId to orderStatus -// 7 = The new execDetails event returned for an order filled status and reqExecDetails -// Also added market depth support. -// 8 = Added 'lastFillPrice' to orderStatus and 'permId' to execDetails -// 9 = Added 'avgCost', '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 = Added IgnoreRth, hidden, and discretionaryAmt -// 13 = Added GoodAfterTime -// 14 = always send size on bid/ask/last tick -// 15 = send allocation string with open order -// 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 send backfill requests -// 19 = can receive new extended order attributes in OPEN_ORDER -// 20 = expects TWS time string on connection after server version >= 20, and parentId in open order -// 21 = can receive bond contract details. -// 22 = can receive price magnifier in contract details -// 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 -// 28 = can receive option model computation ticks -// 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 -// 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 multipier 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 -// can receive position, positionEnd, accountSummary and accountSummaryEnd -// 61 = can receive multiplier in openOrder -// can receive tradingClass in openOrder, updatePortfolio, execDetails and position -// 62 = can receive avgCost in position message -// 63 = can receive verifyMessageAPI, verifyCompleted, displayGroupList and displayGroupUpdated messages -// 64 = can receive solicited attrib in openOrder message -// 65 = can receive verifyAndAuthMessageAPI and verifyAndAuthCompleted messages -// 66 = can receive randomize size and randomize price order fields - -const int CLIENT_VERSION = 66; - - -// outgoing msg id's -const int REQ_MKT_DATA = 1; -const int CANCEL_MKT_DATA = 2; -const int PLACE_ORDER = 3; -const int CANCEL_ORDER = 4; -const int REQ_OPEN_ORDERS = 5; -const int REQ_ACCT_DATA = 6; -const int REQ_EXECUTIONS = 7; -const int REQ_IDS = 8; -const int REQ_CONTRACT_DATA = 9; -const int REQ_MKT_DEPTH = 10; -const int CANCEL_MKT_DEPTH = 11; -const int REQ_NEWS_BULLETINS = 12; -const int CANCEL_NEWS_BULLETINS = 13; -const int SET_SERVER_LOGLEVEL = 14; -const int REQ_AUTO_OPEN_ORDERS = 15; -const int REQ_ALL_OPEN_ORDERS = 16; -const int REQ_MANAGED_ACCTS = 17; -const int REQ_FA = 18; -const int REPLACE_FA = 19; -const int REQ_HISTORICAL_DATA = 20; -const int EXERCISE_OPTIONS = 21; -const int REQ_SCANNER_SUBSCRIPTION = 22; -const int CANCEL_SCANNER_SUBSCRIPTION = 23; -const int REQ_SCANNER_PARAMETERS = 24; -const int CANCEL_HISTORICAL_DATA = 25; -const int REQ_CURRENT_TIME = 49; -const int REQ_REAL_TIME_BARS = 50; -const int CANCEL_REAL_TIME_BARS = 51; -const int REQ_FUNDAMENTAL_DATA = 52; -const int CANCEL_FUNDAMENTAL_DATA = 53; -const int REQ_CALC_IMPLIED_VOLAT = 54; -const int REQ_CALC_OPTION_PRICE = 55; -const int CANCEL_CALC_IMPLIED_VOLAT = 56; -const int CANCEL_CALC_OPTION_PRICE = 57; -const int REQ_GLOBAL_CANCEL = 58; -const int REQ_MARKET_DATA_TYPE = 59; -const int REQ_POSITIONS = 61; -const int REQ_ACCOUNT_SUMMARY = 62; -const int CANCEL_ACCOUNT_SUMMARY = 63; -const int CANCEL_POSITIONS = 64; -const int VERIFY_REQUEST = 65; -const int VERIFY_MESSAGE = 66; -const int QUERY_DISPLAY_GROUPS = 67; -const int SUBSCRIBE_TO_GROUP_EVENTS = 68; -const int UPDATE_DISPLAY_GROUP = 69; -const int UNSUBSCRIBE_FROM_GROUP_EVENTS = 70; -const int START_API = 71; -const int VERIFY_AND_AUTH_REQUEST = 72; -const int VERIFY_AND_AUTH_MESSAGE = 73; -const int REQ_POSITIONS_MULTI = 74; -const int CANCEL_POSITIONS_MULTI = 75; -const int REQ_ACCOUNT_UPDATES_MULTI = 76; -const int CANCEL_ACCOUNT_UPDATES_MULTI = 77; -const int REQ_SEC_DEF_OPT_PARAMS = 78; - -// TWS New Bulletins constants -const int NEWS_MSG = 1; // standard IB news bulleting message -const int EXCHANGE_AVAIL_MSG = 2; // control message specifing that an exchange is available for trading -const int EXCHANGE_UNAVAIL_MSG = 3; // control message specifing that an exchange is unavailable for trading +using namespace ibapi::client_constants; /////////////////////////////////////////////////////////// // encoders @@ -1507,6 +1357,17 @@ void EClient::placeOrder( OrderId id, const Contract& contract, const Order& ord } } + if (m_serverVersion < MIN_SERVER_VER_SOFT_DOLLAR_TIER) + { + if (!order.softDollarTier.name().empty() || !order.softDollarTier.val().empty()) + { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support soft dollar tier"); + return; + } + } + + std::stringstream msg; prepareBuffer( msg); @@ -1896,6 +1757,11 @@ void EClient::placeOrder( OrderId id, const Contract& contract, const Order& ord ENCODE_FIELD( order.extOperator); } + if (m_serverVersion >= MIN_SERVER_VER_SOFT_DOLLAR_TIER) { + ENCODE_FIELD(order.softDollarTier.name()); + ENCODE_FIELD(order.softDollarTier.val()); + } + closeAndSend( msg.str()); } @@ -2820,6 +2686,23 @@ void EClient::reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, closeAndSend(msg.str()); } +void EClient::reqSoftDollarTiers(int reqId) +{ + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer(msg); + + + ENCODE_FIELD(REQ_SOFT_DOLLAR_TIERS); + ENCODE_FIELD(reqId); + + closeAndSend(msg.str()); +} + int EClient::processMsgImpl(const char*& beginPtr, const char* endPtr) { EDecoder decoder(serverVersion(), m_pEWrapper); diff --git a/vn.ib/ibapi/linux/client/EClient.h b/vn.ib/ibapi/linux/client/EClient.h new file mode 100644 index 00000000..15c96d15 --- /dev/null +++ b/vn.ib/ibapi/linux/client/EClient.h @@ -0,0 +1,384 @@ +/* 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. */ + +#pragma once +#ifndef eclient_h__INCLUDED +#define eclient_h__INCLUDED + + +#include +#include +#include +#include +#include "CommonDefs.h" +#include "TagValue.h" + +namespace ibapi { +namespace client_constants { + +///////////////////////////////////////////////////////////////////////////////// +// SOCKET CLIENT VERSION CHANGE LOG : Incremented when the format of incomming +// server responses change +///////////////////////////////////////////////////////////////////////////////// +// constants +// 6 = Added parentId to orderStatus +// 7 = The new execDetails event returned for an order filled status and reqExecDetails +// Also added market depth support. +// 8 = Added 'lastFillPrice' to orderStatus and 'permId' to execDetails +// 9 = Added 'avgCost', '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 = Added IgnoreRth, hidden, and discretionaryAmt +// 13 = Added GoodAfterTime +// 14 = always send size on bid/ask/last tick +// 15 = send allocation string with open order +// 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 send backfill requests +// 19 = can receive new extended order attributes in OPEN_ORDER +// 20 = expects TWS time string on connection after server version >= 20, and parentId in open order +// 21 = can receive bond contract details. +// 22 = can receive price magnifier in contract details +// 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 +// 28 = can receive option model computation ticks +// 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 +// 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 multipier 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 +// can receive position, positionEnd, accountSummary and accountSummaryEnd +// 61 = can receive multiplier in openOrder +// can receive tradingClass in openOrder, updatePortfolio, execDetails and position +// 62 = can receive avgCost in position message +// 63 = can receive verifyMessageAPI, verifyCompleted, displayGroupList and displayGroupUpdated messages +// 64 = can receive solicited attrib in openOrder message +// 65 = can receive verifyAndAuthMessageAPI and verifyAndAuthCompleted messages +// 66 = can receive randomize size and randomize price order fields + +const int CLIENT_VERSION = 66; + + +// outgoing msg id's +const int REQ_MKT_DATA = 1; +const int CANCEL_MKT_DATA = 2; +const int PLACE_ORDER = 3; +const int CANCEL_ORDER = 4; +const int REQ_OPEN_ORDERS = 5; +const int REQ_ACCT_DATA = 6; +const int REQ_EXECUTIONS = 7; +const int REQ_IDS = 8; +const int REQ_CONTRACT_DATA = 9; +const int REQ_MKT_DEPTH = 10; +const int CANCEL_MKT_DEPTH = 11; +const int REQ_NEWS_BULLETINS = 12; +const int CANCEL_NEWS_BULLETINS = 13; +const int SET_SERVER_LOGLEVEL = 14; +const int REQ_AUTO_OPEN_ORDERS = 15; +const int REQ_ALL_OPEN_ORDERS = 16; +const int REQ_MANAGED_ACCTS = 17; +const int REQ_FA = 18; +const int REPLACE_FA = 19; +const int REQ_HISTORICAL_DATA = 20; +const int EXERCISE_OPTIONS = 21; +const int REQ_SCANNER_SUBSCRIPTION = 22; +const int CANCEL_SCANNER_SUBSCRIPTION = 23; +const int REQ_SCANNER_PARAMETERS = 24; +const int CANCEL_HISTORICAL_DATA = 25; +const int REQ_CURRENT_TIME = 49; +const int REQ_REAL_TIME_BARS = 50; +const int CANCEL_REAL_TIME_BARS = 51; +const int REQ_FUNDAMENTAL_DATA = 52; +const int CANCEL_FUNDAMENTAL_DATA = 53; +const int REQ_CALC_IMPLIED_VOLAT = 54; +const int REQ_CALC_OPTION_PRICE = 55; +const int CANCEL_CALC_IMPLIED_VOLAT = 56; +const int CANCEL_CALC_OPTION_PRICE = 57; +const int REQ_GLOBAL_CANCEL = 58; +const int REQ_MARKET_DATA_TYPE = 59; +const int REQ_POSITIONS = 61; +const int REQ_ACCOUNT_SUMMARY = 62; +const int CANCEL_ACCOUNT_SUMMARY = 63; +const int CANCEL_POSITIONS = 64; +const int VERIFY_REQUEST = 65; +const int VERIFY_MESSAGE = 66; +const int QUERY_DISPLAY_GROUPS = 67; +const int SUBSCRIBE_TO_GROUP_EVENTS = 68; +const int UPDATE_DISPLAY_GROUP = 69; +const int UNSUBSCRIBE_FROM_GROUP_EVENTS = 70; +const int START_API = 71; +const int VERIFY_AND_AUTH_REQUEST = 72; +const int VERIFY_AND_AUTH_MESSAGE = 73; +const int REQ_POSITIONS_MULTI = 74; +const int CANCEL_POSITIONS_MULTI = 75; +const int REQ_ACCOUNT_UPDATES_MULTI = 76; +const int CANCEL_ACCOUNT_UPDATES_MULTI = 77; +const int REQ_SEC_DEF_OPT_PARAMS = 78; +const int REQ_SOFT_DOLLAR_TIERS = 79; + +// TWS New Bulletins constants +const int NEWS_MSG = 1; // standard IB news bulleting message +const int EXCHANGE_AVAIL_MSG = 2; // control message specifing that an exchange is available for trading +const int EXCHANGE_UNAVAIL_MSG = 3; // control message specifing that an exchange is unavailable for trading + +} // namespace client_constants +} // namespace ibapi + +struct Contract; +struct Order; +struct ExecutionFilter; +struct ScannerSubscription; +struct ETransport; + +class EWrapper; +typedef std::vector BytesVec; + + +class TWSAPIDLLEXP EClient +{ +public: + + explicit EClient(EWrapper *ptr, ETransport *pTransport); + ~EClient(); + + virtual void eDisconnect() = 0; + + int clientId() const { return m_clientId; } + + const std::string& optionalCapabilities() const; + void setOptionalCapabilities(const std::string& optCapts); + + void setConnectOptions(const std::string& connectOptions); + void disableUseV100Plus(); + bool usingV100Plus(); + +protected: + + void eConnectBase(); + void eDisconnectBase(); + +public: + + enum ConnState { + CS_DISCONNECTED, + CS_CONNECTING, + CS_CONNECTED, + CS_REDIRECT + }; + + // connection state + ConnState connState() const; + bool isConnected() const; + + const std::string& host() const { return m_host; } + unsigned port() const { return m_port; } + +public: + + // access to protected variables + EWrapper * getWrapper() const; +protected: + void setClientId( int clientId); + void setExtraAuth( bool extraAuth); + void setHost( const std::string& host); + void setPort( unsigned port); + +public: + + bool isInBufferEmpty() const; + + // override virtual funcs from EClient + int serverVersion(); + std::string TwsConnectionTime(); + void reqMktData(TickerId id, const Contract& contract, + const std::string& genericTicks, bool snapshot, const TagValueListSPtr& mktDataOptions); + void cancelMktData(TickerId id); + void placeOrder(OrderId id, const Contract& contract, const Order& order); + void cancelOrder(OrderId id) ; + void reqOpenOrders(); + void reqAccountUpdates(bool subscribe, const std::string& acctCode); + void reqExecutions(int reqId, const ExecutionFilter& filter); + void reqIds(int numIds); + void reqContractDetails(int reqId, const Contract& contract); + void reqMktDepth(TickerId tickerId, const Contract& contract, int numRows, const TagValueListSPtr& mktDepthOptions); + void cancelMktDepth(TickerId tickerId); + void reqNewsBulletins(bool allMsgs); + void cancelNewsBulletins(); + void setServerLogLevel(int level); + void reqAutoOpenOrders(bool bAutoBind); + void reqAllOpenOrders(); + void reqManagedAccts(); + void requestFA(faDataType pFaDataType); + void replaceFA(faDataType pFaDataType, const std::string& cxml); + void reqHistoricalData( TickerId id, const Contract& contract, + const std::string& endDateTime, const std::string& durationStr, + const std::string& barSizeSetting, const std::string& whatToShow, + int useRTH, int formatDate, const TagValueListSPtr& chartOptions); + void exerciseOptions(TickerId tickerId, const Contract& contract, + int exerciseAction, int exerciseQuantity, + const std::string& account, int override); + void cancelHistoricalData(TickerId tickerId ); + void reqRealTimeBars(TickerId id, const Contract& contract, int barSize, + const std::string& whatToShow, bool useRTH, const TagValueListSPtr& realTimeBarsOptions); + void cancelRealTimeBars(TickerId tickerId ); + void cancelScannerSubscription(int tickerId); + void reqScannerParameters(); + void reqScannerSubscription(int tickerId, const ScannerSubscription& subscription, const TagValueListSPtr& scannerSubscriptionOptions); + void reqCurrentTime(); + void reqFundamentalData(TickerId reqId, const Contract&, const std::string& reportType); + void cancelFundamentalData(TickerId reqId); + void calculateImpliedVolatility(TickerId reqId, const Contract& contract, double optionPrice, double underPrice); + void calculateOptionPrice(TickerId reqId, const Contract& contract, double volatility, double underPrice); + void cancelCalculateImpliedVolatility(TickerId reqId); + void cancelCalculateOptionPrice(TickerId reqId); + void reqGlobalCancel(); + void reqMarketDataType(int marketDataType); + void reqPositions(); + void cancelPositions(); + void reqAccountSummary( int reqId, const std::string& groupName, const std::string& tags); + void cancelAccountSummary( int reqId); + void verifyRequest( const std::string& apiName, const std::string& apiVersion); + void verifyMessage( const std::string& apiData); + void verifyAndAuthRequest( const std::string& apiName, const std::string& apiVersion, const std::string& opaqueIsvKey); + void verifyAndAuthMessage( const std::string& apiData, const std::string& xyzResponse); + void queryDisplayGroups( int reqId); + void subscribeToGroupEvents( int reqId, int groupId); + void updateDisplayGroup( int reqId, const std::string& contractInfo); + void unsubscribeFromGroupEvents( int reqId); + void reqPositionsMulti( int reqId, const std::string& account, const std::string& modelCode); + void cancelPositionsMulti( int reqId); + void reqAccountUpdatessMulti( int reqId, const std::string& account, const std::string& modelCode, bool ledgerAndNLV); + void cancelAccountUpdatesMulti( int reqId); + void reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, const std::string& futFopExchange, const std::string& underlyingSecType, int underlyingConId); + void reqSoftDollarTiers(int reqId); + +private: + + virtual int receive(char* buf, size_t sz) = 0; + +protected: + + virtual void prepareBufferImpl(std::ostream&) const = 0; + virtual void prepareBuffer(std::ostream&) const = 0; + virtual bool closeAndSend(std::string msg, unsigned offset = 0) = 0; + virtual int bufferedSend(const std::string& msg); + +protected: + int bufferedRead(); + + // try to process connection request ack +private: + // try to process single msg + int processMsgImpl(const char*& ptr, const char* endPtr); + int processMsg(const char*& ptr, const char* endPtr); + + typedef int (EClient::*messageHandler)(const char*& ptr, const char* endPtr); + int processOnePrefixedMsg(const char*& ptr, const char* endPtr, messageHandler); + +public: + void startApi(); + + + // encoders + template static void EncodeField(std::ostream&, T); + + // "max" encoders + static void EncodeFieldMax(std::ostream& os, int); + static void EncodeFieldMax(std::ostream& os, double); + + // socket state +private: + virtual bool isSocketOK() const = 0; + +protected: + + bool isConnecting() const; + int sendConnectRequest(); + bool extraAuth(); + +protected: + + EWrapper *m_pEWrapper; + std::auto_ptr m_transport; + +private: + BytesVec m_inBuffer; + + std::string m_host; + int m_port; + + int m_clientId; + + ConnState m_connState; + bool m_extraAuth; + +protected: + int m_serverVersion; + std::string m_TwsTime; + +private: + std::string m_optionalCapabilities; + + std::string m_connectOptions; + +protected: + bool m_useV100Plus; + +}; + +template<> void EClient::EncodeField(std::ostream& os, bool); +template<> void EClient::EncodeField(std::ostream& os, double); + +#define ENCODE_FIELD(x) EClient::EncodeField(msg, x); +#define ENCODE_FIELD_MAX(x) EClient::EncodeFieldMax(msg, x); + + +#endif diff --git a/vn.ib/ibapi/client/EClientMsgSink.h b/vn.ib/ibapi/linux/client/EClientMsgSink.h similarity index 100% rename from vn.ib/ibapi/client/EClientMsgSink.h rename to vn.ib/ibapi/linux/client/EClientMsgSink.h diff --git a/vn.ib/ibapi/client/EClientSocket.cpp b/vn.ib/ibapi/linux/client/EClientSocket.cpp similarity index 100% rename from vn.ib/ibapi/client/EClientSocket.cpp rename to vn.ib/ibapi/linux/client/EClientSocket.cpp diff --git a/vn.ib/ibapi/client/EClientSocket.h b/vn.ib/ibapi/linux/client/EClientSocket.h similarity index 100% rename from vn.ib/ibapi/client/EClientSocket.h rename to vn.ib/ibapi/linux/client/EClientSocket.h diff --git a/vn.ib/ibapi/client/EDecoder.cpp b/vn.ib/ibapi/linux/client/EDecoder.cpp similarity index 98% rename from vn.ib/ibapi/client/EDecoder.cpp rename to vn.ib/ibapi/linux/client/EDecoder.cpp index 59f686a5..63964c13 100644 --- a/vn.ib/ibapi/client/EDecoder.cpp +++ b/vn.ib/ibapi/linux/client/EDecoder.cpp @@ -642,6 +642,16 @@ const char* EDecoder::processOpenOrderMsg(const char* ptr, const char* endPtr) { DECODE_FIELD(order.adjustableTrailingUnit); } + if (m_serverVersion >= MIN_SERVER_VER_SOFT_DOLLAR_TIER) { + std::string name, value, displayName; + + DECODE_FIELD(name); + DECODE_FIELD(value); + DECODE_FIELD(displayName); + + order.softDollarTier = SoftDollarTier(name, value, displayName); + } + m_pEWrapper->openOrder( (OrderId)order.orderId, contract, order, orderState); return ptr; @@ -1585,7 +1595,7 @@ const char* EDecoder::processAccountUpdateMultiEndMsg(const char* ptr, const cha return ptr; } -const char* EDecoder::processSecurityDefinitionOptionalParameter(const char* ptr, const char* endPtr) { +const char* EDecoder::processSecurityDefinitionOptionalParameterMsg(const char* ptr, const char* endPtr) { int reqId; std::string exchange; int underlyingConId; @@ -1625,7 +1635,7 @@ const char* EDecoder::processSecurityDefinitionOptionalParameter(const char* ptr return ptr; } -const char* EDecoder::processSecurityDefinitionOptionalParameterEnd(const char* ptr, const char* endPtr) { +const char* EDecoder::processSecurityDefinitionOptionalParameterEndMsg(const char* ptr, const char* endPtr) { int reqId; DECODE_FIELD(reqId); @@ -1635,6 +1645,31 @@ const char* EDecoder::processSecurityDefinitionOptionalParameterEnd(const char* return ptr; } +const char* EDecoder::processSoftDollarTiersMsg(const char* ptr, const char* endPtr) +{ + int reqId; + int nTiers; + + DECODE_FIELD(reqId); + DECODE_FIELD(nTiers); + + std::vector tiers(nTiers); + + for (int i = 0; i < nTiers; i++) { + std::string name, value, dislplayName; + + DECODE_FIELD(name); + DECODE_FIELD(value); + DECODE_FIELD(dislplayName); + + tiers[i] = SoftDollarTier(name, value, value); + } + + m_pEWrapper->softDollarTiers(reqId, tiers); + + return ptr; +} + int EDecoder::processConnectAck(const char*& beginPtr, const char* endPtr) { @@ -1910,11 +1945,15 @@ int EDecoder::parseAndProcessMsg(const char*& beginPtr, const char* endPtr) { break; case SECURITY_DEFINITION_OPTION_PARAMETER: - ptr = processSecurityDefinitionOptionalParameter(ptr, endPtr); + ptr = processSecurityDefinitionOptionalParameterMsg(ptr, endPtr); break; case SECURITY_DEFINITION_OPTION_PARAMETER_END: - ptr = processSecurityDefinitionOptionalParameterEnd(ptr, endPtr); + ptr = processSecurityDefinitionOptionalParameterEndMsg(ptr, endPtr); + break; + + case SOFT_DOLLAR_TIERS: + ptr = processSoftDollarTiersMsg(ptr, endPtr); break; default: diff --git a/vn.ib/ibapi/client/EDecoder.h b/vn.ib/ibapi/linux/client/EDecoder.h similarity index 96% rename from vn.ib/ibapi/client/EDecoder.h rename to vn.ib/ibapi/linux/client/EDecoder.h index a19ed514..eb4e586f 100644 --- a/vn.ib/ibapi/client/EDecoder.h +++ b/vn.ib/ibapi/linux/client/EDecoder.h @@ -55,12 +55,13 @@ const int MIN_SERVER_VER_PEGGED_TO_BENCHMARK = 102; const int MIN_SERVER_VER_MODELS_SUPPORT = 103; const int MIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ = 104; const int MIN_SERVER_VER_EXT_OPERATOR = 105; +const int MIN_SERVER_VER_SOFT_DOLLAR_TIER = 106; /* 100+ messaging */ // 100 = enhanced handshake, msg length prefixes const int MIN_CLIENT_VER = 100; -const int MAX_CLIENT_VER = MIN_SERVER_VER_EXT_OPERATOR; +const int MAX_CLIENT_VER = MIN_SERVER_VER_SOFT_DOLLAR_TIER; // incoming msg id's @@ -115,6 +116,7 @@ const int ACCOUNT_UPDATE_MULTI = 73; const int ACCOUNT_UPDATE_MULTI_END = 74; const int SECURITY_DEFINITION_OPTION_PARAMETER = 75; const int SECURITY_DEFINITION_OPTION_PARAMETER_END = 76; +const int SOFT_DOLLAR_TIERS = 77; const int HEADER_LEN = 4; // 4 bytes for msg length const int MAX_MSG_LEN = 0xFFFFFF; // 16Mb - 1byte @@ -213,8 +215,9 @@ class TWSAPIDLLEXP EDecoder const char* processPositionMultiEndMsg(const char* ptr, const char* endPtr); const char* processAccountUpdateMultiMsg(const char* ptr, const char* endPtr); const char* processAccountUpdateMultiEndMsg(const char* ptr, const char* endPtr); - const char* processSecurityDefinitionOptionalParameter(const char* ptr, const char* endPtr); - const char* processSecurityDefinitionOptionalParameterEnd(const char* ptr, const char* endPtr); + const char* processSecurityDefinitionOptionalParameterMsg(const char* ptr, const char* endPtr); + const char* processSecurityDefinitionOptionalParameterEndMsg(const char* ptr, const char* endPtr); + const char* processSoftDollarTiersMsg(const char* ptr, const char* endPtr); int processConnectAck(const char*& beginPtr, const char* endPtr); diff --git a/vn.ib/ibapi/client/EMessage.cpp b/vn.ib/ibapi/linux/client/EMessage.cpp similarity index 100% rename from vn.ib/ibapi/client/EMessage.cpp rename to vn.ib/ibapi/linux/client/EMessage.cpp diff --git a/vn.ib/ibapi/client/EMessage.h b/vn.ib/ibapi/linux/client/EMessage.h similarity index 100% rename from vn.ib/ibapi/client/EMessage.h rename to vn.ib/ibapi/linux/client/EMessage.h diff --git a/vn.ib/ibapi/client/EMutex.cpp b/vn.ib/ibapi/linux/client/EMutex.cpp similarity index 100% rename from vn.ib/ibapi/client/EMutex.cpp rename to vn.ib/ibapi/linux/client/EMutex.cpp diff --git a/vn.ib/ibapi/client/EMutex.h b/vn.ib/ibapi/linux/client/EMutex.h similarity index 100% rename from vn.ib/ibapi/client/EMutex.h rename to vn.ib/ibapi/linux/client/EMutex.h diff --git a/vn.ib/ibapi/client/EPosixClientSocketPlatform.h b/vn.ib/ibapi/linux/client/EPosixClientSocketPlatform.h similarity index 100% rename from vn.ib/ibapi/client/EPosixClientSocketPlatform.h rename to vn.ib/ibapi/linux/client/EPosixClientSocketPlatform.h diff --git a/vn.ib/ibapi/client/EReader.cpp b/vn.ib/ibapi/linux/client/EReader.cpp similarity index 93% rename from vn.ib/ibapi/client/EReader.cpp rename to vn.ib/ibapi/linux/client/EReader.cpp index 27956350..5bc00630 100644 --- a/vn.ib/ibapi/client/EReader.cpp +++ b/vn.ib/ibapi/linux/client/EReader.cpp @@ -178,13 +178,20 @@ void EReader::onReceive() { } bool EReader::bufferedRead(char *buf, int size) { - while (m_buf.size() < size) - if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) - return false; + while (size > 0) { + while (m_buf.size() < size && m_buf.size() < m_nMaxBufSize) + if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) + return false; - std::copy(m_buf.begin(), m_buf.begin() + size, buf); - std::copy(m_buf.begin() + size, m_buf.end(), m_buf.begin()); - m_buf.resize(m_buf.size() - size); + int nBytes = min(m_nMaxBufSize, size); + + std::copy(m_buf.begin(), m_buf.begin() + nBytes, buf); + std::copy(m_buf.begin() + nBytes, m_buf.end(), m_buf.begin()); + m_buf.resize(m_buf.size() - nBytes); + + size -= nBytes; + buf += nBytes; + } return true; } diff --git a/vn.ib/ibapi/client/EReader.h b/vn.ib/ibapi/linux/client/EReader.h similarity index 100% rename from vn.ib/ibapi/client/EReader.h rename to vn.ib/ibapi/linux/client/EReader.h diff --git a/vn.ib/ibapi/client/EReaderOSSignal.cpp b/vn.ib/ibapi/linux/client/EReaderOSSignal.cpp similarity index 100% rename from vn.ib/ibapi/client/EReaderOSSignal.cpp rename to vn.ib/ibapi/linux/client/EReaderOSSignal.cpp diff --git a/vn.ib/ibapi/client/EReaderOSSignal.h b/vn.ib/ibapi/linux/client/EReaderOSSignal.h similarity index 97% rename from vn.ib/ibapi/client/EReaderOSSignal.h rename to vn.ib/ibapi/linux/client/EReaderOSSignal.h index c3d4acd4..a87d4659 100644 --- a/vn.ib/ibapi/client/EReaderOSSignal.h +++ b/vn.ib/ibapi/linux/client/EReaderOSSignal.h @@ -4,6 +4,7 @@ #pragma once #include "EReaderSignal.h" #include "StdAfx.h" +#include #if !defined(INFINITE) #define INFINITE ((unsigned long)-1) diff --git a/vn.ib/ibapi/client/EReaderSignal.h b/vn.ib/ibapi/linux/client/EReaderSignal.h similarity index 100% rename from vn.ib/ibapi/client/EReaderSignal.h rename to vn.ib/ibapi/linux/client/EReaderSignal.h diff --git a/vn.ib/ibapi/client/EReaderWMSignal.cpp b/vn.ib/ibapi/linux/client/EReaderWMSignal.cpp similarity index 100% rename from vn.ib/ibapi/client/EReaderWMSignal.cpp rename to vn.ib/ibapi/linux/client/EReaderWMSignal.cpp diff --git a/vn.ib/ibapi/client/EReaderWMSignal.h b/vn.ib/ibapi/linux/client/EReaderWMSignal.h similarity index 100% rename from vn.ib/ibapi/client/EReaderWMSignal.h rename to vn.ib/ibapi/linux/client/EReaderWMSignal.h diff --git a/vn.ib/ibapi/client/ESocket.cpp b/vn.ib/ibapi/linux/client/ESocket.cpp similarity index 100% rename from vn.ib/ibapi/client/ESocket.cpp rename to vn.ib/ibapi/linux/client/ESocket.cpp diff --git a/vn.ib/ibapi/client/ESocket.h b/vn.ib/ibapi/linux/client/ESocket.h similarity index 100% rename from vn.ib/ibapi/client/ESocket.h rename to vn.ib/ibapi/linux/client/ESocket.h diff --git a/vn.ib/ibapi/client/ETransport.h b/vn.ib/ibapi/linux/client/ETransport.h similarity index 100% rename from vn.ib/ibapi/client/ETransport.h rename to vn.ib/ibapi/linux/client/ETransport.h diff --git a/vn.ib/ibapi/client/EWrapper.h b/vn.ib/ibapi/linux/client/EWrapper.h similarity index 97% rename from vn.ib/ibapi/client/EWrapper.h rename to vn.ib/ibapi/linux/client/EWrapper.h index 77a663a1..ce6b70dd 100644 --- a/vn.ib/ibapi/client/EWrapper.h +++ b/vn.ib/ibapi/linux/client/EWrapper.h @@ -6,6 +6,7 @@ #define ewrapper_def #include "CommonDefs.h" +#include "SoftDollarTier.h" #include #include @@ -78,6 +79,9 @@ enum TickType { BID_SIZE, BID, ASK, ASK_SIZE, LAST, LAST_SIZE, DELAYED_VOLUME, DELAYED_CLOSE, DELAYED_OPEN, + RT_TRD_VOLUME, + CREDITMAN_MARK_PRICE, + CREDITMAN_SLOW_MARK_PRICE, NOT_SET }; inline bool isPrice( TickType tickType) { @@ -165,6 +169,7 @@ public: virtual void accountUpdateMultiEnd( int reqId) = 0; virtual void securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes) = 0; virtual void securityDefinitionOptionalParameterEnd(int reqId) = 0; + virtual void softDollarTiers(int reqId, const std::vector &tiers) = 0; }; diff --git a/vn.ib/ibapi/client/Execution.h b/vn.ib/ibapi/linux/client/Execution.h similarity index 100% rename from vn.ib/ibapi/client/Execution.h rename to vn.ib/ibapi/linux/client/Execution.h diff --git a/vn.ib/ibapi/client/IExternalizable.h b/vn.ib/ibapi/linux/client/IExternalizable.h similarity index 100% rename from vn.ib/ibapi/client/IExternalizable.h rename to vn.ib/ibapi/linux/client/IExternalizable.h diff --git a/vn.ib/ibapi/client/MarginCondition.cpp b/vn.ib/ibapi/linux/client/MarginCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/MarginCondition.cpp rename to vn.ib/ibapi/linux/client/MarginCondition.cpp diff --git a/vn.ib/ibapi/client/MarginCondition.h b/vn.ib/ibapi/linux/client/MarginCondition.h similarity index 100% rename from vn.ib/ibapi/client/MarginCondition.h rename to vn.ib/ibapi/linux/client/MarginCondition.h diff --git a/vn.ib/ibapi/client/OperatorCondition.cpp b/vn.ib/ibapi/linux/client/OperatorCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/OperatorCondition.cpp rename to vn.ib/ibapi/linux/client/OperatorCondition.cpp diff --git a/vn.ib/ibapi/client/OperatorCondition.h b/vn.ib/ibapi/linux/client/OperatorCondition.h similarity index 100% rename from vn.ib/ibapi/client/OperatorCondition.h rename to vn.ib/ibapi/linux/client/OperatorCondition.h diff --git a/vn.ib/ibapi/client/Order.h b/vn.ib/ibapi/linux/client/Order.h similarity index 98% rename from vn.ib/ibapi/client/Order.h rename to vn.ib/ibapi/linux/client/Order.h index e4b277ad..d92cec8d 100644 --- a/vn.ib/ibapi/client/Order.h +++ b/vn.ib/ibapi/linux/client/Order.h @@ -7,6 +7,7 @@ #include "TagValue.h" #include "OrderCondition.h" +#include "SoftDollarTier.h" #include #include @@ -42,7 +43,8 @@ typedef ibapi::shared_ptr OrderComboLegSPtr; struct Order { - Order() + Order() : + softDollarTier("", "", "") { // order identifier orderId = 0; @@ -307,6 +309,8 @@ struct Order // ext operator std::string extOperator; + SoftDollarTier softDollarTier; + public: // Helpers diff --git a/vn.ib/ibapi/client/OrderCondition.cpp b/vn.ib/ibapi/linux/client/OrderCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/OrderCondition.cpp rename to vn.ib/ibapi/linux/client/OrderCondition.cpp diff --git a/vn.ib/ibapi/client/OrderCondition.h b/vn.ib/ibapi/linux/client/OrderCondition.h similarity index 100% rename from vn.ib/ibapi/client/OrderCondition.h rename to vn.ib/ibapi/linux/client/OrderCondition.h diff --git a/vn.ib/ibapi/client/OrderState.h b/vn.ib/ibapi/linux/client/OrderState.h similarity index 100% rename from vn.ib/ibapi/client/OrderState.h rename to vn.ib/ibapi/linux/client/OrderState.h diff --git a/vn.ib/ibapi/client/PercentChangeCondition.cpp b/vn.ib/ibapi/linux/client/PercentChangeCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/PercentChangeCondition.cpp rename to vn.ib/ibapi/linux/client/PercentChangeCondition.cpp diff --git a/vn.ib/ibapi/client/PercentChangeCondition.h b/vn.ib/ibapi/linux/client/PercentChangeCondition.h similarity index 100% rename from vn.ib/ibapi/client/PercentChangeCondition.h rename to vn.ib/ibapi/linux/client/PercentChangeCondition.h diff --git a/vn.ib/ibapi/client/PriceCondition.cpp b/vn.ib/ibapi/linux/client/PriceCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/PriceCondition.cpp rename to vn.ib/ibapi/linux/client/PriceCondition.cpp diff --git a/vn.ib/ibapi/client/PriceCondition.h b/vn.ib/ibapi/linux/client/PriceCondition.h similarity index 100% rename from vn.ib/ibapi/client/PriceCondition.h rename to vn.ib/ibapi/linux/client/PriceCondition.h diff --git a/vn.ib/ibapi/client/Resource.h b/vn.ib/ibapi/linux/client/Resource.h similarity index 100% rename from vn.ib/ibapi/client/Resource.h rename to vn.ib/ibapi/linux/client/Resource.h diff --git a/vn.ib/ibapi/client/ScannerSubscription.h b/vn.ib/ibapi/linux/client/ScannerSubscription.h similarity index 100% rename from vn.ib/ibapi/client/ScannerSubscription.h rename to vn.ib/ibapi/linux/client/ScannerSubscription.h diff --git a/vn.ib/ibapi/linux/client/SoftDollarTier.cpp b/vn.ib/ibapi/linux/client/SoftDollarTier.cpp new file mode 100644 index 00000000..daf20233 --- /dev/null +++ b/vn.ib/ibapi/linux/client/SoftDollarTier.cpp @@ -0,0 +1,22 @@ +#include "StdAfx.h" +#include "SoftDollarTier.h" + +SoftDollarTier::SoftDollarTier(const std::string& name, const std::string& val, const std::string& displayName) : + m_name(name), m_val(val), m_displayName(displayName) +{ +} + +std::string SoftDollarTier::name() const +{ + return m_name; +} + +std::string SoftDollarTier::val() const +{ + return m_val; +} + +std::string SoftDollarTier::displayName() const +{ + return m_displayName; +} \ No newline at end of file diff --git a/vn.ib/ibapi/linux/client/SoftDollarTier.h b/vn.ib/ibapi/linux/client/SoftDollarTier.h new file mode 100644 index 00000000..c53fca5e --- /dev/null +++ b/vn.ib/ibapi/linux/client/SoftDollarTier.h @@ -0,0 +1,14 @@ +#pragma once + +class TWSAPIDLLEXP SoftDollarTier +{ + std::string m_name, m_val, m_displayName; + +public: + SoftDollarTier(const std::string& name = "", const std::string& val = "", const std::string& displayName = ""); + + std::string name() const; + std::string val() const; + std::string displayName() const; +}; + diff --git a/vn.ib/ibapi/client/StdAfx.cpp b/vn.ib/ibapi/linux/client/StdAfx.cpp similarity index 100% rename from vn.ib/ibapi/client/StdAfx.cpp rename to vn.ib/ibapi/linux/client/StdAfx.cpp diff --git a/vn.ib/ibapi/client/StdAfx.h b/vn.ib/ibapi/linux/client/StdAfx.h similarity index 100% rename from vn.ib/ibapi/client/StdAfx.h rename to vn.ib/ibapi/linux/client/StdAfx.h diff --git a/vn.ib/ibapi/client/TagValue.h b/vn.ib/ibapi/linux/client/TagValue.h similarity index 100% rename from vn.ib/ibapi/client/TagValue.h rename to vn.ib/ibapi/linux/client/TagValue.h diff --git a/vn.ib/ibapi/client/TimeCondition.cpp b/vn.ib/ibapi/linux/client/TimeCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/TimeCondition.cpp rename to vn.ib/ibapi/linux/client/TimeCondition.cpp diff --git a/vn.ib/ibapi/client/TimeCondition.h b/vn.ib/ibapi/linux/client/TimeCondition.h similarity index 100% rename from vn.ib/ibapi/client/TimeCondition.h rename to vn.ib/ibapi/linux/client/TimeCondition.h diff --git a/vn.ib/ibapi/client/TwsSocketClientErrors.h b/vn.ib/ibapi/linux/client/TwsSocketClientErrors.h similarity index 100% rename from vn.ib/ibapi/client/TwsSocketClientErrors.h rename to vn.ib/ibapi/linux/client/TwsSocketClientErrors.h diff --git a/vn.ib/ibapi/client/VolumeCondition.cpp b/vn.ib/ibapi/linux/client/VolumeCondition.cpp similarity index 100% rename from vn.ib/ibapi/client/VolumeCondition.cpp rename to vn.ib/ibapi/linux/client/VolumeCondition.cpp diff --git a/vn.ib/ibapi/client/VolumeCondition.h b/vn.ib/ibapi/linux/client/VolumeCondition.h similarity index 100% rename from vn.ib/ibapi/client/VolumeCondition.h rename to vn.ib/ibapi/linux/client/VolumeCondition.h diff --git a/vn.ib/ibapi/client/executioncondition.cpp b/vn.ib/ibapi/linux/client/executioncondition.cpp similarity index 100% rename from vn.ib/ibapi/client/executioncondition.cpp rename to vn.ib/ibapi/linux/client/executioncondition.cpp diff --git a/vn.ib/ibapi/client/executioncondition.h b/vn.ib/ibapi/linux/client/executioncondition.h similarity index 100% rename from vn.ib/ibapi/client/executioncondition.h rename to vn.ib/ibapi/linux/client/executioncondition.h diff --git a/vn.ib/ibapi/linux/client/shared_ptr.h b/vn.ib/ibapi/linux/client/shared_ptr.h new file mode 100644 index 00000000..c1bea151 --- /dev/null +++ b/vn.ib/ibapi/linux/client/shared_ptr.h @@ -0,0 +1,106 @@ +/* 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. */ + +#pragma once +#ifndef shared_ptr_h_INCLUDED +#define shared_ptr_h_INCLUDED + +// +// Implements a subset of shared_prt found at www.boost.org. +// Uses a singly linked circular list instead of a reference counter. +// Avoids extra heap allocation needed to get a shared reference counter, +// but sizeof(shared_ptr) == sizeof(void*) * 3 compared to sizeof(void*) * 2 +// +// See "Handles and Exception Safety, Part 4: Tracking References without Counters" +// by Andrew Koenig and Barbara E. Moo, Feb. 2003 C++ Users Journal +// + +namespace ibapi { + +namespace shared_ptr_defs { + +class Use { +public: + + Use() { forward_ = this; back_ = this; } + ~Use() { remove(); } + + Use(const Use& u) { insert(u); } + Use& operator=(const Use& u) + { + if (this != &u) { + remove(); + insert(u); + } + return *this; + } + bool only() const { return this == this->forward_; } +private: + mutable const Use *forward_; + mutable const Use *back_; + + void insert(const Use& u) const { + this->back_ = &u; + this->forward_ = u.forward_; + u.forward_->back_ = this; + u.forward_ = this; + } + + void remove() const { + this->forward_->back_ = this->back_; + this->back_->forward_ = this->forward_; + } +}; + +} // end of namespace shared_ptr_defs + +template class shared_ptr { +public: + + typedef shared_ptr_defs::Use Use; + + template friend class shared_ptr; + + explicit shared_ptr(X* ptr = 0) : ptr_(ptr) {} + + ~shared_ptr() { if (use_.only()) delete ptr_; } + + template + shared_ptr(const shared_ptr& other) + : ptr_(other.ptr_), + use_(other.use_) + {} + + shared_ptr& operator=(const shared_ptr& other) { + if ( &use_ == &other.use_ ) { return *this; } + if ( use_.only() ) { delete ptr_; } + use_ = other.use_; + ptr_ = other.ptr_; + return *this; + } + + X& operator*() const { return *ptr_; } + X* operator->() const { return ptr_; } + X* get() const { return ptr_; } + bool only() const { return use_.only(); } + + void reset(X* ptr = 0) { + if ( use_.only() ) { delete ptr_; } + ptr_ = ptr; + use_ = Use(); + } + +private: + + X *ptr_; + Use use_; +}; + + +} //end of namespace ibapi + + +#else +//#include +//using std::shared_ptr; +#endif /* shared_ptr_h_INCLUDED */ \ No newline at end of file diff --git a/vn.ib/ibapi/ssl/EClientSocketSSL.cpp b/vn.ib/ibapi/linux/ssl/EClientSocketSSL.cpp similarity index 100% rename from vn.ib/ibapi/ssl/EClientSocketSSL.cpp rename to vn.ib/ibapi/linux/ssl/EClientSocketSSL.cpp diff --git a/vn.ib/ibapi/ssl/EClientSocketSSL.h b/vn.ib/ibapi/linux/ssl/EClientSocketSSL.h similarity index 100% rename from vn.ib/ibapi/ssl/EClientSocketSSL.h rename to vn.ib/ibapi/linux/ssl/EClientSocketSSL.h diff --git a/vn.ib/ibapi/ssl/EReaderSSL.cpp b/vn.ib/ibapi/linux/ssl/EReaderSSL.cpp similarity index 100% rename from vn.ib/ibapi/ssl/EReaderSSL.cpp rename to vn.ib/ibapi/linux/ssl/EReaderSSL.cpp diff --git a/vn.ib/ibapi/ssl/EReaderSSL.h b/vn.ib/ibapi/linux/ssl/EReaderSSL.h similarity index 100% rename from vn.ib/ibapi/ssl/EReaderSSL.h rename to vn.ib/ibapi/linux/ssl/EReaderSSL.h diff --git a/vn.ib/ibapi/ssl/ESocketSSL.cpp b/vn.ib/ibapi/linux/ssl/ESocketSSL.cpp similarity index 100% rename from vn.ib/ibapi/ssl/ESocketSSL.cpp rename to vn.ib/ibapi/linux/ssl/ESocketSSL.cpp diff --git a/vn.ib/ibapi/ssl/ESocketSSL.h b/vn.ib/ibapi/linux/ssl/ESocketSSL.h similarity index 100% rename from vn.ib/ibapi/ssl/ESocketSSL.h rename to vn.ib/ibapi/linux/ssl/ESocketSSL.h diff --git a/vn.ib/ibapi/ssl/StdAfx.cpp b/vn.ib/ibapi/linux/ssl/StdAfx.cpp similarity index 100% rename from vn.ib/ibapi/ssl/StdAfx.cpp rename to vn.ib/ibapi/linux/ssl/StdAfx.cpp diff --git a/vn.ib/ibapi/ssl/StdAfx.h b/vn.ib/ibapi/linux/ssl/StdAfx.h similarity index 100% rename from vn.ib/ibapi/ssl/StdAfx.h rename to vn.ib/ibapi/linux/ssl/StdAfx.h diff --git a/vn.ib/ibapi/client/.gitignore b/vn.ib/ibapi/windows/client/.gitignore similarity index 100% rename from vn.ib/ibapi/client/.gitignore rename to vn.ib/ibapi/windows/client/.gitignore diff --git a/vn.ib/ibapi/windows/client/CommissionReport.h b/vn.ib/ibapi/windows/client/CommissionReport.h new file mode 100644 index 00000000..9997b2be --- /dev/null +++ b/vn.ib/ibapi/windows/client/CommissionReport.h @@ -0,0 +1,27 @@ +/* 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. */ + +#pragma once +#ifndef commissionreport_def +#define commissionreport_def + +struct CommissionReport +{ + CommissionReport() + { + commission = 0; + realizedPNL = 0; + yield = 0; + yieldRedemptionDate = 0; + } + + // commission report fields + std::string execId; + double commission; + std::string currency; + double realizedPNL; + double yield; + int yieldRedemptionDate; // YYYYMMDD format +}; + +#endif // commissionreport_def diff --git a/vn.ib/ibapi/windows/client/CommonDefs.h b/vn.ib/ibapi/windows/client/CommonDefs.h new file mode 100644 index 00000000..fd1ccead --- /dev/null +++ b/vn.ib/ibapi/windows/client/CommonDefs.h @@ -0,0 +1,33 @@ +/* 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. */ + +#pragma once +#ifndef common_defs_h_INCLUDED +#define common_defs_h_INCLUDED + +typedef long TickerId; +typedef long OrderId; + +enum faDataType { GROUPS=1, PROFILES, ALIASES } ; + +inline const char* faDataTypeStr ( faDataType pFaDataType ) +{ + switch (pFaDataType) { + case GROUPS: + return "GROUPS"; + case PROFILES: + return "PROFILES"; + case ALIASES: + return "ALIASES"; + } + return 0 ; +} + +enum MarketDataType { + REALTIME = 1, + FROZEN = 2, + DELAYED = 3, + DELAYED_FROZEN = 4 +}; + +#endif /* common_defs_h_INCLUDED */ diff --git a/vn.ib/ibapi/windows/client/Contract.h b/vn.ib/ibapi/windows/client/Contract.h new file mode 100644 index 00000000..524fe039 --- /dev/null +++ b/vn.ib/ibapi/windows/client/Contract.h @@ -0,0 +1,187 @@ +/* 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. */ + +#pragma once +#ifndef contract_def +#define contract_def + +#include "TagValue.h" + +/* + SAME_POS = open/close leg value is same as combo + OPEN_POS = open + CLOSE_POS = close + UNKNOWN_POS = unknown +*/ +enum LegOpenClose { SAME_POS, OPEN_POS, CLOSE_POS, UNKNOWN_POS }; + +struct ComboLeg +{ + ComboLeg() + : conId(0) + , ratio(0) + , openClose(0) + , shortSaleSlot(0) + , exemptCode(-1) + { + } + + long conId; + long ratio; + std::string action; //BUY/SELL/SSHORT + + std::string exchange; + long openClose; // LegOpenClose enum values + + // for stock legs when doing short sale + long shortSaleSlot; // 1 = clearing broker, 2 = third party + std::string designatedLocation; + int exemptCode; + + bool operator==( const ComboLeg& other) const + { + return (conId == other.conId && + ratio == other.ratio && + openClose == other.openClose && + shortSaleSlot == other.shortSaleSlot && + exemptCode == other.exemptCode && + action == other.action && + exchange == other.exchange && + designatedLocation == other.designatedLocation); + } +}; + +struct UnderComp +{ + UnderComp() + : conId(0) + , delta(0) + , price(0) + {} + + long conId; + double delta; + double price; +}; + +typedef ibapi::shared_ptr ComboLegSPtr; + +struct Contract +{ + Contract() + : conId(0) + , strike(0) + , includeExpired(false) + , comboLegs(NULL) + , underComp(NULL) + { + } + + long conId; + std::string symbol; + std::string secType; + std::string lastTradeDateOrContractMonth; + double strike; + std::string right; + std::string multiplier; + std::string exchange; + std::string primaryExchange; // pick an actual (ie non-aggregate) exchange that the contract trades on. DO NOT SET TO SMART. + std::string currency; + std::string localSymbol; + std::string tradingClass; + bool includeExpired; + std::string secIdType; // CUSIP;SEDOL;ISIN;RIC + std::string secId; + + // COMBOS + std::string comboLegsDescrip; // received in open order 14 and up for all combos + + // combo legs + typedef std::vector ComboLegList; + typedef ibapi::shared_ptr ComboLegListSPtr; + + ComboLegListSPtr comboLegs; + + // delta neutral + UnderComp* underComp; + +public: + + // Helpers + static void CloneComboLegs(ComboLegListSPtr& dst, const ComboLegListSPtr& src); +}; + +struct ContractDetails +{ + ContractDetails() + : minTick(0) + , priceMagnifier(0) + , underConId(0) + , evMultiplier(0) + , callable(false) + , putable(false) + , coupon(0) + , convertible(false) + , nextOptionPartial(false) + { + } + + Contract summary; + std::string marketName; + double minTick; + std::string orderTypes; + std::string validExchanges; + long priceMagnifier; + int underConId; + std::string longName; + std::string contractMonth; + std::string industry; + std::string category; + std::string subcategory; + std::string timeZoneId; + std::string tradingHours; + std::string liquidHours; + std::string evRule; + double evMultiplier; + + TagValueListSPtr secIdList; + + // BOND values + std::string cusip; + std::string ratings; + std::string descAppend; + std::string bondType; + std::string couponType; + bool callable; + bool putable; + double coupon; + bool convertible; + std::string maturity; + std::string issueDate; + std::string nextOptionDate; + std::string nextOptionType; + bool nextOptionPartial; + std::string notes; +}; + +inline void +Contract::CloneComboLegs(ComboLegListSPtr& dst, const ComboLegListSPtr& src) +{ + if (!src.get()) + return; + + dst->reserve(src->size()); + + ComboLegList::const_iterator iter = src->begin(); + const ComboLegList::const_iterator iterEnd = src->end(); + + for (; iter != iterEnd; ++iter) { + const ComboLeg* leg = iter->get(); + if (!leg) + continue; + dst->push_back(ComboLegSPtr(new ComboLeg(*leg))); + } +} + + +#endif diff --git a/vn.ib/ibapi/windows/client/ContractCondition.cpp b/vn.ib/ibapi/windows/client/ContractCondition.cpp new file mode 100644 index 00000000..cf460aaa --- /dev/null +++ b/vn.ib/ibapi/windows/client/ContractCondition.cpp @@ -0,0 +1,43 @@ +#include "StdAfx.h" +#include "ContractCondition.h" +#include "EDecoder.h" +#include "EClient.h" + +std::string ContractCondition::toString() { + std::string strContract = conId() + ""; + + return type() + " of " + strContract + OperatorCondition::toString(); +} + +const char* ContractCondition::readExternal(const char* ptr, const char* endPtr) { + if (!(ptr = OperatorCondition::readExternal(ptr, endPtr))) + return 0; + + DECODE_FIELD(m_conId); + DECODE_FIELD(m_exchange); + + return ptr; +} + +void ContractCondition::writeExternal(std::ostream & msg) const { + OperatorCondition::writeExternal(msg); + + ENCODE_FIELD(m_conId); + ENCODE_FIELD(m_exchange); +} + +int ContractCondition::conId() { + return m_conId; +} + +void ContractCondition::conId(int conId) { + m_conId = conId; +} + +std::string ContractCondition::exchange() { + return m_exchange; +} + +void ContractCondition::exchange(const std::string & exchange) { + m_exchange = exchange; +} diff --git a/vn.ib/ibapi/windows/client/ContractCondition.h b/vn.ib/ibapi/windows/client/ContractCondition.h new file mode 100644 index 00000000..65da71d0 --- /dev/null +++ b/vn.ib/ibapi/windows/client/ContractCondition.h @@ -0,0 +1,17 @@ +#pragma once +#include "OperatorCondition.h" + +class TWSAPIDLLEXP ContractCondition : public OperatorCondition { + int m_conId; + std::string m_exchange; + +public: + virtual std::string toString(); + virtual const char* readExternal(const char* ptr, const char* endPtr); + virtual void writeExternal(std::ostream &out) const; + + int conId(); + void conId(int conId); + std::string exchange(); + void exchange(const std::string &exchange); +}; diff --git a/vn.ib/ibapi/windows/client/DefaultEWrapper.cpp b/vn.ib/ibapi/windows/client/DefaultEWrapper.cpp new file mode 100644 index 00000000..6e49ad33 --- /dev/null +++ b/vn.ib/ibapi/windows/client/DefaultEWrapper.cpp @@ -0,0 +1,77 @@ +/* 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. */ + +#include "StdAfx.h" +#include "DefaultEWrapper.h" + +void DefaultEWrapper::tickPrice( TickerId tickerId, TickType field, double price, int canAutoExecute) { } +void DefaultEWrapper::tickSize( TickerId tickerId, TickType field, int size) { } +void DefaultEWrapper::tickOptionComputation( TickerId tickerId, TickType tickType, double impliedVol, double delta, + double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { } +void DefaultEWrapper::tickGeneric(TickerId tickerId, TickType tickType, double value) { } +void DefaultEWrapper::tickString(TickerId tickerId, TickType tickType, const std::string& value) { } +void DefaultEWrapper::tickEFP(TickerId tickerId, TickType tickType, double basisPoints, const std::string& formattedBasisPoints, + double totalDividends, int holdDays, const std::string& futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate) { } +void DefaultEWrapper::orderStatus( OrderId orderId, const std::string& status, double filled, + double remaining, double avgFillPrice, int permId, int parentId, + double lastFillPrice, int clientId, const std::string& whyHeld) { } +void DefaultEWrapper::openOrder( OrderId orderId, const Contract&, const Order&, const OrderState&) { } +void DefaultEWrapper::openOrderEnd() { } +void DefaultEWrapper::winError( const std::string& str, int lastError) { } +void DefaultEWrapper::connectionClosed() { } +void DefaultEWrapper::updateAccountValue(const std::string& key, const std::string& val, + const std::string& currency, const std::string& accountName) { } +void DefaultEWrapper::updatePortfolio( const Contract& contract, double position, + double marketPrice, double marketValue, double averageCost, + double unrealizedPNL, double realizedPNL, const std::string& accountName) { } +void DefaultEWrapper::updateAccountTime(const std::string& timeStamp) { } +void DefaultEWrapper::accountDownloadEnd(const std::string& accountName) { } +void DefaultEWrapper::nextValidId( OrderId orderId) { } +void DefaultEWrapper::contractDetails( int reqId, const ContractDetails& contractDetails) { } +void DefaultEWrapper::bondContractDetails( int reqId, const ContractDetails& contractDetails) { } +void DefaultEWrapper::contractDetailsEnd( int reqId) { } +void DefaultEWrapper::execDetails( int reqId, const Contract& contract, const Execution& execution) { } +void DefaultEWrapper::execDetailsEnd( int reqId) { } +void DefaultEWrapper::error(const int id, const int errorCode, const std::string errorString) { } +void DefaultEWrapper::updateMktDepth(TickerId id, int position, int operation, int side, + double price, int size) { } +void DefaultEWrapper::updateMktDepthL2(TickerId id, int position, std::string marketMaker, int operation, + int side, double price, int size) { } +void DefaultEWrapper::updateNewsBulletin(int msgId, int msgType, const std::string& newsMessage, const std::string& originExch) { } +void DefaultEWrapper::managedAccounts( const std::string& accountsList) { } +void DefaultEWrapper::receiveFA(faDataType pFaDataType, const std::string& cxml) { } +void DefaultEWrapper::historicalData(TickerId reqId, const std::string& date, double open, double high, + double low, double close, int volume, int barCount, double WAP, int hasGaps) { } +void DefaultEWrapper::scannerParameters(const std::string& xml) { } +void DefaultEWrapper::scannerData(int reqId, int rank, const ContractDetails& contractDetails, + const std::string& distance, const std::string& benchmark, const std::string& projection, + const std::string& legsStr) { } +void DefaultEWrapper::scannerDataEnd(int reqId) { } +void DefaultEWrapper::realtimeBar(TickerId reqId, long time, double open, double high, double low, double close, + long volume, double wap, int count) { } +void DefaultEWrapper::currentTime(long time) { } +void DefaultEWrapper::fundamentalData(TickerId reqId, const std::string& data) { } +void DefaultEWrapper::deltaNeutralValidation(int reqId, const UnderComp& underComp) { } +void DefaultEWrapper::tickSnapshotEnd( int reqId) { } +void DefaultEWrapper::marketDataType( TickerId reqId, int marketDataType) { } +void DefaultEWrapper::commissionReport( const CommissionReport& commissionReport) { } +void DefaultEWrapper::position( const std::string& account, const Contract& contract, double position, double avgCost) { } +void DefaultEWrapper::positionEnd() { } +void DefaultEWrapper::accountSummary( int reqId, const std::string& account, const std::string& tag, const std::string& value, const std::string& curency) { } +void DefaultEWrapper::accountSummaryEnd( int reqId) { } +void DefaultEWrapper::verifyMessageAPI( const std::string& apiData) { } +void DefaultEWrapper::verifyCompleted( bool isSuccessful, const std::string& errorText) { } +void DefaultEWrapper::displayGroupList( int reqId, const std::string& groups) { } +void DefaultEWrapper::displayGroupUpdated( int reqId, const std::string& contractInfo) { } +void DefaultEWrapper::verifyAndAuthMessageAPI( const std::string& apiData, const std::string& xyzChallange) { } +void DefaultEWrapper::verifyAndAuthCompleted( bool isSuccessful, const std::string& errorText) { } +void DefaultEWrapper::connectAck() { } +void DefaultEWrapper::positionMulti( int reqId, const std::string& account,const std::string& modelCode, const Contract& contract, double pos, double avgCost) { } +void DefaultEWrapper::positionMultiEnd( int reqId) { } +void DefaultEWrapper::accountUpdateMulti( int reqId, const std::string& account, const std::string& modelCode, const std::string& key, const std::string& value, const std::string& currency) { } +void DefaultEWrapper::accountUpdateMultiEnd( int reqId) { } +void DefaultEWrapper::securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes) { } +void DefaultEWrapper::securityDefinitionOptionalParameterEnd(int reqId) { } +void DefaultEWrapper::softDollarTiers(int reqId, const std::vector &tiers) { } + + diff --git a/vn.ib/ibapi/windows/client/DefaultEWrapper.h b/vn.ib/ibapi/windows/client/DefaultEWrapper.h new file mode 100644 index 00000000..bf88d4d7 --- /dev/null +++ b/vn.ib/ibapi/windows/client/DefaultEWrapper.h @@ -0,0 +1,81 @@ +/* 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. */ + +#pragma once +#include "EWrapper.h" + +class TWSAPIDLLEXP DefaultEWrapper : + public EWrapper +{ +public: + virtual void tickPrice( TickerId tickerId, TickType field, double price, int canAutoExecute); + virtual void tickSize( TickerId tickerId, TickType field, int size); + virtual void tickOptionComputation( TickerId tickerId, TickType tickType, double impliedVol, double delta, + double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice); + virtual void tickGeneric(TickerId tickerId, TickType tickType, double value); + virtual void tickString(TickerId tickerId, TickType tickType, const std::string& value); + virtual void tickEFP(TickerId tickerId, TickType tickType, double basisPoints, const std::string& formattedBasisPoints, + double totalDividends, int holdDays, const std::string& futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate); + virtual void orderStatus( OrderId orderId, const std::string& status, double filled, + double remaining, double avgFillPrice, int permId, int parentId, + double lastFillPrice, int clientId, const std::string& whyHeld); + virtual void openOrder( OrderId orderId, const Contract&, const Order&, const OrderState&); + virtual void openOrderEnd(); + virtual void winError( const std::string& str, int lastError); + virtual void connectionClosed(); + virtual void updateAccountValue(const std::string& key, const std::string& val, + const std::string& currency, const std::string& accountName); + virtual void updatePortfolio( const Contract& contract, double position, + double marketPrice, double marketValue, double averageCost, + double unrealizedPNL, double realizedPNL, const std::string& accountName); + virtual void updateAccountTime(const std::string& timeStamp); + virtual void accountDownloadEnd(const std::string& accountName); + virtual void nextValidId( OrderId orderId); + virtual void contractDetails( int reqId, const ContractDetails& contractDetails); + virtual void bondContractDetails( int reqId, const ContractDetails& contractDetails); + virtual void contractDetailsEnd( int reqId); + virtual void execDetails( int reqId, const Contract& contract, const Execution& execution); + virtual void execDetailsEnd( int reqId); + virtual void error(const int id, const int errorCode, const std::string errorString); + virtual void updateMktDepth(TickerId id, int position, int operation, int side, + double price, int size); + virtual void updateMktDepthL2(TickerId id, int position, std::string marketMaker, int operation, + int side, double price, int size); + virtual void updateNewsBulletin(int msgId, int msgType, const std::string& newsMessage, const std::string& originExch); + virtual void managedAccounts( const std::string& accountsList); + virtual void receiveFA(faDataType pFaDataType, const std::string& cxml); + virtual void historicalData(TickerId reqId, const std::string& date, double open, double high, + double low, double close, int volume, int barCount, double WAP, int hasGaps); + virtual void scannerParameters(const std::string& xml); + virtual void scannerData(int reqId, int rank, const ContractDetails& contractDetails, + const std::string& distance, const std::string& benchmark, const std::string& projection, + const std::string& legsStr); + virtual void scannerDataEnd(int reqId); + virtual void realtimeBar(TickerId reqId, long time, double open, double high, double low, double close, + long volume, double wap, int count); + virtual void currentTime(long time); + virtual void fundamentalData(TickerId reqId, const std::string& data); + virtual void deltaNeutralValidation(int reqId, const UnderComp& underComp); + virtual void tickSnapshotEnd( int reqId); + virtual void marketDataType( TickerId reqId, int marketDataType); + virtual void commissionReport( const CommissionReport& commissionReport); + virtual void position( const std::string& account, const Contract& contract, double position, double avgCost); + virtual void positionEnd(); + virtual void accountSummary( int reqId, const std::string& account, const std::string& tag, const std::string& value, const std::string& curency); + virtual void accountSummaryEnd( int reqId); + virtual void verifyMessageAPI( const std::string& apiData); + virtual void verifyCompleted( bool isSuccessful, const std::string& errorText); + virtual void displayGroupList( int reqId, const std::string& groups); + virtual void displayGroupUpdated( int reqId, const std::string& contractInfo); + virtual void verifyAndAuthMessageAPI( const std::string& apiData, const std::string& xyzChallange); + virtual void verifyAndAuthCompleted( bool isSuccessful, const std::string& errorText); + virtual void connectAck(); + virtual void positionMulti( int reqId, const std::string& account,const std::string& modelCode, const Contract& contract, double pos, double avgCost); + virtual void positionMultiEnd( int reqId); + virtual void accountUpdateMulti( int reqId, const std::string& account, const std::string& modelCode, const std::string& key, const std::string& value, const std::string& currency); + virtual void accountUpdateMultiEnd( int reqId); + virtual void securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes); + virtual void securityDefinitionOptionalParameterEnd(int reqId); + virtual void softDollarTiers(int reqId, const std::vector &tiers); +}; + diff --git a/vn.ib/ibapi/windows/client/EClient.cpp b/vn.ib/ibapi/windows/client/EClient.cpp new file mode 100644 index 00000000..c295cf54 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EClient.cpp @@ -0,0 +1,2840 @@ +/* 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. */ + +#include "StdAfx.h" + +#include "EPosixClientSocketPlatform.h" + +#include "EClient.h" + +#include "EWrapper.h" +#include "TwsSocketClientErrors.h" +#include "Contract.h" +#include "Order.h" +#include "OrderState.h" +#include "Execution.h" +#include "ScannerSubscription.h" +#include "CommissionReport.h" +#include "EDecoder.h" +#include "EMessage.h" +#include "ETransport.h" + +#include +#include +#include + +#include +#include +#include + +using namespace ibapi::client_constants; + +/////////////////////////////////////////////////////////// +// encoders +template +void EClient::EncodeField(std::ostream& os, T value) +{ + os << value << '\0'; +} + +template<> +void EClient::EncodeField(std::ostream& os, bool boolValue) +{ + EncodeField(os, boolValue ? 1 : 0); +} + +template<> +void EClient::EncodeField(std::ostream& os, double doubleValue) +{ + char str[128]; + + snprintf(str, sizeof(str), "%.10g", doubleValue); + + EncodeField(os, str); +} + +/////////////////////////////////////////////////////////// +// "max" encoders +void EClient::EncodeFieldMax(std::ostream& os, int intValue) +{ + if( intValue == INT_MAX) { + EncodeField(os, ""); + return; + } + EncodeField(os, intValue); +} + +void EClient::EncodeFieldMax(std::ostream& os, double doubleValue) +{ + if( doubleValue == DBL_MAX) { + EncodeField(os, ""); + return; + } + EncodeField(os, doubleValue); +} + + +/////////////////////////////////////////////////////////// +// member funcs +EClient::EClient( EWrapper *ptr, ETransport *pTransport) + : m_pEWrapper(ptr) + , m_clientId(-1) + , m_connState(CS_DISCONNECTED) + , m_extraAuth(false) + , m_serverVersion(0) + , m_useV100Plus(true) + , m_transport(pTransport) +{ +} + +EClient::~EClient() +{ +} + +EClient::ConnState EClient::connState() const +{ + return m_connState; +} + +bool EClient::isConnected() const +{ + return m_connState == CS_CONNECTED; +} + +bool EClient::isConnecting() const +{ + return m_connState == CS_CONNECTING; +} + +void EClient::eConnectBase() +{ +} + +void EClient::eDisconnectBase() +{ + m_TwsTime.clear(); + m_serverVersion = 0; + m_connState = CS_DISCONNECTED; + m_extraAuth = false; + m_clientId = -1; + m_inBuffer.clear(); +} + +int EClient::serverVersion() +{ + return m_serverVersion; +} + +std::string EClient::TwsConnectionTime() +{ + return m_TwsTime; +} + +const std::string& EClient::optionalCapabilities() const +{ + return m_optionalCapabilities; +} + +void EClient::setOptionalCapabilities(const std::string& optCapts) +{ + m_optionalCapabilities = optCapts; +} + +void EClient::setConnectOptions(const std::string& connectOptions) +{ + if( isSocketOK()) { + m_pEWrapper->error( NO_VALID_ID, ALREADY_CONNECTED.code(), ALREADY_CONNECTED.msg()); + return; + } + + m_connectOptions = connectOptions; +} + +void EClient::disableUseV100Plus() +{ + if( isSocketOK()) { + m_pEWrapper->error( NO_VALID_ID, ALREADY_CONNECTED.code(), ALREADY_CONNECTED.msg()); + return; + } + + m_useV100Plus = false; + m_connectOptions = ""; +} + +bool EClient::usingV100Plus() { + return m_useV100Plus; +} + +int EClient::bufferedSend(const std::string& msg) { + EMessage emsg(std::vector(msg.begin(), msg.end())); + + return m_transport->send(&emsg); +} + +void EClient::reqMktData(TickerId tickerId, const Contract& contract, + const std::string& genericTicks, bool snapshot, const TagValueListSPtr& mktDataOptions) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // not needed anymore validation + //if( m_serverVersion < MIN_SERVER_VER_SNAPSHOT_MKT_DATA && snapshot) { + // m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support snapshot market data requests."); + // return; + //} + + if( m_serverVersion < MIN_SERVER_VER_UNDER_COMP) { + if( contract.underComp) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support delta-neutral orders."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_REQ_MKT_DATA_CONID) { + if( contract.conId > 0) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty() ) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support tradingClass parameter in reqMktData."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 11; + + // send req mkt data msg + ENCODE_FIELD( REQ_MKT_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_REQ_MKT_DATA_CONID) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); // srv v15 and above + + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); // srv v14 and above + ENCODE_FIELD( contract.currency); + + ENCODE_FIELD( contract.localSymbol); // srv v2 and above + + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + + // Send combo legs for BAG requests (srv v8 and above) + if( contract.secType == "BAG") + { + const Contract::ComboLegList* const comboLegs = contract.comboLegs.get(); + const int comboLegsCount = comboLegs ? comboLegs->size() : 0; + ENCODE_FIELD( comboLegsCount); + if( comboLegsCount > 0) { + for( int i = 0; i < comboLegsCount; ++i) { + const ComboLeg* comboLeg = ((*comboLegs)[i]).get(); + assert( comboLeg); + ENCODE_FIELD( comboLeg->conId); + ENCODE_FIELD( comboLeg->ratio); + ENCODE_FIELD( comboLeg->action); + ENCODE_FIELD( comboLeg->exchange); + } + } + } + + if( m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) { + if( contract.underComp) { + const UnderComp& underComp = *contract.underComp; + ENCODE_FIELD( true); + ENCODE_FIELD( underComp.conId); + ENCODE_FIELD( underComp.delta); + ENCODE_FIELD( underComp.price); + } + else { + ENCODE_FIELD( false); + } + } + + ENCODE_FIELD( genericTicks); // srv v31 and above + ENCODE_FIELD( snapshot); // srv v35 and above + + // send mktDataOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string mktDataOptionsStr(""); + const int mktDataOptionsCount = mktDataOptions.get() ? mktDataOptions->size() : 0; + if( mktDataOptionsCount > 0) { + for( int i = 0; i < mktDataOptionsCount; ++i) { + const TagValue* tagValue = ((*mktDataOptions)[i]).get(); + mktDataOptionsStr += tagValue->tag; + mktDataOptionsStr += "="; + mktDataOptionsStr += tagValue->value; + mktDataOptionsStr += ";"; + } + } + ENCODE_FIELD( mktDataOptionsStr); + } + + closeAndSend( msg.str()); +} + +void EClient::cancelMktData(TickerId tickerId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + // send cancel mkt data msg + ENCODE_FIELD( CANCEL_MKT_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + closeAndSend( msg.str()); +} + +void EClient::reqMktDepth( TickerId tickerId, const Contract& contract, int numRows, const TagValueListSPtr& mktDepthOptions) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + // This feature is only available for versions of TWS >=6 + //if( m_serverVersion < 6) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty() || (contract.conId > 0)) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId and tradingClass parameters in reqMktDepth."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 5; + + // send req mkt data msg + ENCODE_FIELD( REQ_MKT_DEPTH); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); // srv v15 and above + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + + ENCODE_FIELD( numRows); // srv v19 and above + + // send mktDepthOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string mktDepthOptionsStr(""); + const int mktDepthOptionsCount = mktDepthOptions.get() ? mktDepthOptions->size() : 0; + if( mktDepthOptionsCount > 0) { + for( int i = 0; i < mktDepthOptionsCount; ++i) { + const TagValue* tagValue = ((*mktDepthOptions)[i]).get(); + mktDepthOptionsStr += tagValue->tag; + mktDepthOptionsStr += "="; + mktDepthOptionsStr += tagValue->value; + mktDepthOptionsStr += ";"; + } + } + ENCODE_FIELD( mktDepthOptionsStr); + } + + closeAndSend( msg.str()); +} + + +void EClient::cancelMktDepth( TickerId tickerId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + // This feature is only available for versions of TWS >=6 + //if( m_serverVersion < 6) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send cancel mkt data msg + ENCODE_FIELD( CANCEL_MKT_DEPTH); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + closeAndSend( msg.str()); +} + +void EClient::reqHistoricalData( TickerId tickerId, const Contract& contract, + const std::string& endDateTime, const std::string& durationStr, + const std::string& barSizeSetting, const std::string& whatToShow, + int useRTH, int formatDate, const TagValueListSPtr& chartOptions) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 16) { + // m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty() || (contract.conId > 0)) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId and tradingClass parameters in reqHistoricalData."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 6; + + ENCODE_FIELD( REQ_HISTORICAL_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + ENCODE_FIELD( contract.includeExpired); // srv v31 and above + + ENCODE_FIELD( endDateTime); // srv v20 and above + ENCODE_FIELD( barSizeSetting); // srv v20 and above + + ENCODE_FIELD( durationStr); + ENCODE_FIELD( useRTH); + ENCODE_FIELD( whatToShow); + ENCODE_FIELD( formatDate); // srv v16 and above + + // Send combo legs for BAG requests + if( contract.secType == "BAG") + { + const Contract::ComboLegList* const comboLegs = contract.comboLegs.get(); + const int comboLegsCount = comboLegs ? comboLegs->size() : 0; + ENCODE_FIELD( comboLegsCount); + if( comboLegsCount > 0) { + for( int i = 0; i < comboLegsCount; ++i) { + const ComboLeg* comboLeg = ((*comboLegs)[i]).get(); + assert( comboLeg); + ENCODE_FIELD( comboLeg->conId); + ENCODE_FIELD( comboLeg->ratio); + ENCODE_FIELD( comboLeg->action); + ENCODE_FIELD( comboLeg->exchange); + } + } + } + + // send chartOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string chartOptionsStr(""); + const int chartOptionsCount = chartOptions.get() ? chartOptions->size() : 0; + if( chartOptionsCount > 0) { + for( int i = 0; i < chartOptionsCount; ++i) { + const TagValue* tagValue = ((*chartOptions)[i]).get(); + chartOptionsStr += tagValue->tag; + chartOptionsStr += "="; + chartOptionsStr += tagValue->value; + chartOptionsStr += ";"; + } + } + ENCODE_FIELD( chartOptionsStr); + } + + closeAndSend( msg.str()); +} + +void EClient::cancelHistoricalData(TickerId tickerId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 24) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support historical data query cancellation."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_HISTORICAL_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + closeAndSend( msg.str()); +} + +void EClient::reqRealTimeBars(TickerId tickerId, const Contract& contract, + int barSize, const std::string& whatToShow, bool useRTH, + const TagValueListSPtr& realTimeBarsOptions) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < MIN_SERVER_VER_REAL_TIME_BARS) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support real time bars."); + // return; + //} + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty() || (contract.conId > 0)) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId and tradingClass parameters in reqRealTimeBars."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 3; + + ENCODE_FIELD( REQ_REAL_TIME_BARS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + ENCODE_FIELD( barSize); + ENCODE_FIELD( whatToShow); + ENCODE_FIELD( useRTH); + + // send realTimeBarsOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string realTimeBarsOptionsStr(""); + const int realTimeBarsOptionsCount = realTimeBarsOptions.get() ? realTimeBarsOptions->size() : 0; + if( realTimeBarsOptionsCount > 0) { + for( int i = 0; i < realTimeBarsOptionsCount; ++i) { + const TagValue* tagValue = ((*realTimeBarsOptions)[i]).get(); + realTimeBarsOptionsStr += tagValue->tag; + realTimeBarsOptionsStr += "="; + realTimeBarsOptionsStr += tagValue->value; + realTimeBarsOptionsStr += ";"; + } + } + ENCODE_FIELD( realTimeBarsOptionsStr); + } + + closeAndSend( msg.str()); +} + + +void EClient::cancelRealTimeBars(TickerId tickerId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < MIN_SERVER_VER_REAL_TIME_BARS) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support realtime bar data query cancellation."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_REAL_TIME_BARS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + closeAndSend( msg.str()); +} + + +void EClient::reqScannerParameters() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 24) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support API scanner subscription."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_SCANNER_PARAMETERS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + + +void EClient::reqScannerSubscription(int tickerId, + const ScannerSubscription& subscription, const TagValueListSPtr& scannerSubscriptionOptions) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 24) { + // m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support API scanner subscription."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 4; + + ENCODE_FIELD( REQ_SCANNER_SUBSCRIPTION); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + ENCODE_FIELD_MAX( subscription.numberOfRows); + ENCODE_FIELD( subscription.instrument); + ENCODE_FIELD( subscription.locationCode); + ENCODE_FIELD( subscription.scanCode); + ENCODE_FIELD_MAX( subscription.abovePrice); + ENCODE_FIELD_MAX( subscription.belowPrice); + ENCODE_FIELD_MAX( subscription.aboveVolume); + ENCODE_FIELD_MAX( subscription.marketCapAbove); + ENCODE_FIELD_MAX( subscription.marketCapBelow); + ENCODE_FIELD( subscription.moodyRatingAbove); + ENCODE_FIELD( subscription.moodyRatingBelow); + ENCODE_FIELD( subscription.spRatingAbove); + ENCODE_FIELD( subscription.spRatingBelow); + ENCODE_FIELD( subscription.maturityDateAbove); + ENCODE_FIELD( subscription.maturityDateBelow); + ENCODE_FIELD_MAX( subscription.couponRateAbove); + ENCODE_FIELD_MAX( subscription.couponRateBelow); + ENCODE_FIELD_MAX( subscription.excludeConvertible); + ENCODE_FIELD_MAX( subscription.averageOptionVolumeAbove); // srv v25 and above + ENCODE_FIELD( subscription.scannerSettingPairs); // srv v25 and above + ENCODE_FIELD( subscription.stockTypeFilter); // srv v27 and above + + // send scannerSubscriptionOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string scannerSubscriptionOptionsStr(""); + const int scannerSubscriptionOptionsCount = scannerSubscriptionOptions.get() ? scannerSubscriptionOptions->size() : 0; + if( scannerSubscriptionOptionsCount > 0) { + for( int i = 0; i < scannerSubscriptionOptionsCount; ++i) { + const TagValue* tagValue = ((*scannerSubscriptionOptions)[i]).get(); + scannerSubscriptionOptionsStr += tagValue->tag; + scannerSubscriptionOptionsStr += "="; + scannerSubscriptionOptionsStr += tagValue->value; + scannerSubscriptionOptionsStr += ";"; + } + } + ENCODE_FIELD( scannerSubscriptionOptionsStr); + } + + closeAndSend( msg.str()); +} + +void EClient::cancelScannerSubscription(int tickerId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( tickerId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 24) { + // m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support API scanner subscription."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_SCANNER_SUBSCRIPTION); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + closeAndSend( msg.str()); +} + +void EClient::reqFundamentalData(TickerId reqId, const Contract& contract, + const std::string& reportType) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( reqId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_FUNDAMENTAL_DATA) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support fundamental data requests."); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( contract.conId > 0) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId parameter in reqFundamentalData."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + ENCODE_FIELD( REQ_FUNDAMENTAL_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + + ENCODE_FIELD( reportType); + + closeAndSend( msg.str()); +} + +void EClient::cancelFundamentalData( TickerId reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( reqId, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_FUNDAMENTAL_DATA) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support fundamental data requests."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_FUNDAMENTAL_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::calculateImpliedVolatility(TickerId reqId, const Contract& contract, double optionPrice, double underPrice) { + + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_REQ_CALC_IMPLIED_VOLAT) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support calculate implied volatility requests."); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty()) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support tradingClass parameter in calculateImpliedVolatility."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + ENCODE_FIELD( REQ_CALC_IMPLIED_VOLAT); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + // send contract fields + ENCODE_FIELD( contract.conId); + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + + ENCODE_FIELD( optionPrice); + ENCODE_FIELD( underPrice); + + closeAndSend( msg.str()); +} + +void EClient::cancelCalculateImpliedVolatility(TickerId reqId) { + + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_CANCEL_CALC_IMPLIED_VOLAT) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support calculate implied volatility cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_CALC_IMPLIED_VOLAT); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::calculateOptionPrice(TickerId reqId, const Contract& contract, double volatility, double underPrice) { + + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_REQ_CALC_OPTION_PRICE) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support calculate option price requests."); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty()) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support tradingClass parameter in calculateOptionPrice."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + ENCODE_FIELD( REQ_CALC_OPTION_PRICE); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + // send contract fields + ENCODE_FIELD( contract.conId); + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + + ENCODE_FIELD( volatility); + ENCODE_FIELD( underPrice); + + closeAndSend( msg.str()); +} + +void EClient::cancelCalculateOptionPrice(TickerId reqId) { + + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_CANCEL_CALC_OPTION_PRICE) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support calculate option price cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_CALC_OPTION_PRICE); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::reqContractDetails( int reqId, const Contract& contract) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + // This feature is only available for versions of TWS >=4 + //if( m_serverVersion < 4) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + if (m_serverVersion < MIN_SERVER_VER_SEC_ID_TYPE) { + if( !contract.secIdType.empty() || !contract.secId.empty()) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support secIdType and secId parameters."); + return; + } + } + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty()) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support tradingClass parameter in reqContractDetails."); + return; + } + } + if (m_serverVersion < MIN_SERVER_VER_LINKING) { + if (!contract.primaryExchange.empty()) { + m_pEWrapper->error( reqId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support primaryExchange parameter in reqContractDetails."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 8; + + // send req mkt data msg + ENCODE_FIELD( REQ_CONTRACT_DATA); + ENCODE_FIELD( VERSION); + + if( m_serverVersion >= MIN_SERVER_VER_CONTRACT_DATA_CHAIN) { + ENCODE_FIELD( reqId); + } + + // send contract fields + ENCODE_FIELD( contract.conId); // srv v37 and above + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); // srv v15 and above + + if (m_serverVersion >= MIN_SERVER_VER_PRIMARYEXCH) + { + ENCODE_FIELD(contract.exchange); + ENCODE_FIELD(contract.primaryExchange); + } + else if (m_serverVersion >= MIN_SERVER_VER_LINKING) + { + if (!contract.primaryExchange.empty() && (contract.exchange == "BEST" || contract.exchange == "SMART")) + { + ENCODE_FIELD( contract.exchange + ":" + contract.primaryExchange); + } + else + { + ENCODE_FIELD(contract.exchange); + } + } + + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + ENCODE_FIELD( contract.includeExpired); // srv v31 and above + + if( m_serverVersion >= MIN_SERVER_VER_SEC_ID_TYPE){ + ENCODE_FIELD( contract.secIdType); + ENCODE_FIELD( contract.secId); + } + + closeAndSend( msg.str()); +} + +void EClient::reqCurrentTime() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + // This feature is only available for versions of TWS >= 33 + //if( m_serverVersion < 33) { + // m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support current time requests."); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send current time req + ENCODE_FIELD( REQ_CURRENT_TIME); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::placeOrder( OrderId id, const Contract& contract, const Order& order) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( id, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS) { + // if( order.scaleNumComponents != UNSET_INTEGER || + // order.scaleComponentSize != UNSET_INTEGER || + // order.scalePriceIncrement != UNSET_DOUBLE) { + // m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support Scale orders."); + // return; + // } + //} + // + //if( m_serverVersion < MIN_SERVER_VER_SSHORT_COMBO_LEGS) { + // if( contract.comboLegs && !contract.comboLegs->empty()) { + // typedef Contract::ComboLegList ComboLegList; + // const ComboLegList& comboLegs = *contract.comboLegs; + // ComboLegList::const_iterator iter = comboLegs.begin(); + // const ComboLegList::const_iterator iterEnd = comboLegs.end(); + // for( ; iter != iterEnd; ++iter) { + // const ComboLeg* comboLeg = *iter; + // assert( comboLeg); + // if( comboLeg->shortSaleSlot != 0 || + // !comboLeg->designatedLocation.IsEmpty()) { + // m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support SSHORT flag for combo legs."); + // return; + // } + // } + // } + //} + // + //if( m_serverVersion < MIN_SERVER_VER_WHAT_IF_ORDERS) { + // if( order.whatIf) { + // m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + // " It does not support what-if orders."); + // return; + // } + //} + + if( m_serverVersion < MIN_SERVER_VER_UNDER_COMP) { + if( contract.underComp) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support delta-neutral orders."); + return; + } + } + + if( m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS2) { + if( order.scaleSubsLevelSize != UNSET_INTEGER) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support Subsequent Level Size for Scale orders."); + return; + } + } + + if( m_serverVersion < MIN_SERVER_VER_ALGO_ORDERS) { + + if( !order.algoStrategy.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support algo orders."); + return; + } + } + + if( m_serverVersion < MIN_SERVER_VER_NOT_HELD) { + if (order.notHeld) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support notHeld parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SEC_ID_TYPE) { + if( !contract.secIdType.empty() || !contract.secId.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support secIdType and secId parameters."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_PLACE_ORDER_CONID) { + if( contract.conId > 0) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SSHORTX) { + if( order.exemptCode != -1) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support exemptCode parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SSHORTX) { + const Contract::ComboLegList* const comboLegs = contract.comboLegs.get(); + const int comboLegsCount = comboLegs ? comboLegs->size() : 0; + for( int i = 0; i < comboLegsCount; ++i) { + const ComboLeg* comboLeg = ((*comboLegs)[i]).get(); + assert( comboLeg); + if( comboLeg->exemptCode != -1 ){ + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support exemptCode parameter."); + return; + } + } + } + + if( m_serverVersion < MIN_SERVER_VER_HEDGE_ORDERS) { + if( !order.hedgeType.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support hedge orders."); + return; + } + } + + if( m_serverVersion < MIN_SERVER_VER_OPT_OUT_SMART_ROUTING) { + if (order.optOutSmartRouting) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support optOutSmartRouting parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_DELTA_NEUTRAL_CONID) { + if (order.deltaNeutralConId > 0 + || !order.deltaNeutralSettlingFirm.empty() + || !order.deltaNeutralClearingAccount.empty() + || !order.deltaNeutralClearingIntent.empty() + ) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support deltaNeutral parameters: ConId, SettlingFirm, ClearingAccount, ClearingIntent."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE) { + if (!order.deltaNeutralOpenClose.empty() + || order.deltaNeutralShortSale + || order.deltaNeutralShortSaleSlot > 0 + || !order.deltaNeutralDesignatedLocation.empty() + ) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support deltaNeutral parameters: OpenClose, ShortSale, ShortSaleSlot, DesignatedLocation."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SCALE_ORDERS3) { + if (order.scalePriceIncrement > 0 && order.scalePriceIncrement != UNSET_DOUBLE) { + if (order.scalePriceAdjustValue != UNSET_DOUBLE + || order.scalePriceAdjustInterval != UNSET_INTEGER + || order.scaleProfitOffset != UNSET_DOUBLE + || order.scaleAutoReset + || order.scaleInitPosition != UNSET_INTEGER + || order.scaleInitFillQty != UNSET_INTEGER + || order.scaleRandomPercent) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " 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 && contract.secType == "BAG") { + const Order::OrderComboLegList* const orderComboLegs = order.orderComboLegs.get(); + const int orderComboLegsCount = orderComboLegs ? orderComboLegs->size() : 0; + for( int i = 0; i < orderComboLegsCount; ++i) { + const OrderComboLeg* orderComboLeg = ((*orderComboLegs)[i]).get(); + assert( orderComboLeg); + if( orderComboLeg->price != UNSET_DOUBLE) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support per-leg prices for order combo legs."); + return; + } + } + } + + if (m_serverVersion < MIN_SERVER_VER_TRAILING_PERCENT) { + if (order.trailingPercent != UNSET_DOUBLE) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support trailing percent parameter"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support tradingClass parameter in placeOrder."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SCALE_TABLE) { + if( !order.scaleTable.empty() || !order.activeStartTime.empty() || !order.activeStopTime.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support scaleTable, activeStartTime and activeStopTime parameters"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_ALGO_ID) { + if( !order.algoId.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support algoId parameter"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_ORDER_SOLICITED) { + if (order.solicited) { + m_pEWrapper->error(id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support order solicited parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_MODELS_SUPPORT) { + if( !order.modelCode.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support model code parameter."); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_EXT_OPERATOR) { + if( !order.extOperator.empty()) { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support ext operator parameter"); + return; + } + } + + if (m_serverVersion < MIN_SERVER_VER_SOFT_DOLLAR_TIER) + { + if (!order.softDollarTier.name().empty() || !order.softDollarTier.val().empty()) + { + m_pEWrapper->error( id, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support soft dollar tier"); + return; + } + } + + + std::stringstream msg; + prepareBuffer( msg); + + int VERSION = (m_serverVersion < MIN_SERVER_VER_NOT_HELD) ? 27 : 45; + + // send place order msg + ENCODE_FIELD( PLACE_ORDER); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( id); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_PLACE_ORDER_CONID) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); // srv v15 and above + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.primaryExchange); // srv v14 and above + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); // srv v2 and above + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + + if( m_serverVersion >= MIN_SERVER_VER_SEC_ID_TYPE){ + ENCODE_FIELD( contract.secIdType); + ENCODE_FIELD( contract.secId); + } + + // send main order fields + ENCODE_FIELD( order.action); + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + ENCODE_FIELD(order.totalQuantity) + else + ENCODE_FIELD((long)order.totalQuantity) + + ENCODE_FIELD( order.orderType); + if( m_serverVersion < MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE) { + ENCODE_FIELD( order.lmtPrice == UNSET_DOUBLE ? 0 : order.lmtPrice); + } + else { + ENCODE_FIELD_MAX( order.lmtPrice); + } + if( m_serverVersion < MIN_SERVER_VER_TRAILING_PERCENT) { + ENCODE_FIELD( order.auxPrice == UNSET_DOUBLE ? 0 : order.auxPrice); + } + else { + ENCODE_FIELD_MAX( order.auxPrice); + } + + // send extended order fields + ENCODE_FIELD( order.tif); + ENCODE_FIELD( order.ocaGroup); + ENCODE_FIELD( order.account); + ENCODE_FIELD( order.openClose); + ENCODE_FIELD( order.origin); + ENCODE_FIELD( order.orderRef); + ENCODE_FIELD( order.transmit); + ENCODE_FIELD( order.parentId); // srv v4 and above + + ENCODE_FIELD( order.blockOrder); // srv v5 and above + ENCODE_FIELD( order.sweepToFill); // srv v5 and above + ENCODE_FIELD( order.displaySize); // srv v5 and above + ENCODE_FIELD( order.triggerMethod); // srv v5 and above + + //if( m_serverVersion < 38) { + // will never happen + // ENCODE_FIELD(/* order.ignoreRth */ false); + //} + //else { + ENCODE_FIELD( order.outsideRth); // srv v5 and above + //} + + ENCODE_FIELD( order.hidden); // srv v7 and above + + // Send combo legs for BAG requests (srv v8 and above) + if( contract.secType == "BAG") + { + const Contract::ComboLegList* const comboLegs = contract.comboLegs.get(); + const int comboLegsCount = comboLegs ? comboLegs->size() : 0; + ENCODE_FIELD( comboLegsCount); + if( comboLegsCount > 0) { + for( int i = 0; i < comboLegsCount; ++i) { + const ComboLeg* comboLeg = ((*comboLegs)[i]).get(); + assert( comboLeg); + ENCODE_FIELD( comboLeg->conId); + ENCODE_FIELD( comboLeg->ratio); + ENCODE_FIELD( comboLeg->action); + ENCODE_FIELD( comboLeg->exchange); + ENCODE_FIELD( comboLeg->openClose); + + ENCODE_FIELD( comboLeg->shortSaleSlot); // srv v35 and above + ENCODE_FIELD( comboLeg->designatedLocation); // srv v35 and above + if (m_serverVersion >= MIN_SERVER_VER_SSHORTX_OLD) { + ENCODE_FIELD( comboLeg->exemptCode); + } + } + } + } + + // Send order combo legs for BAG requests + if( m_serverVersion >= MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE && contract.secType == "BAG") + { + const Order::OrderComboLegList* const orderComboLegs = order.orderComboLegs.get(); + const int orderComboLegsCount = orderComboLegs ? orderComboLegs->size() : 0; + ENCODE_FIELD( orderComboLegsCount); + if( orderComboLegsCount > 0) { + for( int i = 0; i < orderComboLegsCount; ++i) { + const OrderComboLeg* orderComboLeg = ((*orderComboLegs)[i]).get(); + assert( orderComboLeg); + ENCODE_FIELD_MAX( orderComboLeg->price); + } + } + } + + if( m_serverVersion >= MIN_SERVER_VER_SMART_COMBO_ROUTING_PARAMS && contract.secType == "BAG") { + const TagValueList* const smartComboRoutingParams = order.smartComboRoutingParams.get(); + const int smartComboRoutingParamsCount = smartComboRoutingParams ? smartComboRoutingParams->size() : 0; + ENCODE_FIELD( smartComboRoutingParamsCount); + if( smartComboRoutingParamsCount > 0) { + for( int i = 0; i < smartComboRoutingParamsCount; ++i) { + const TagValue* tagValue = ((*smartComboRoutingParams)[i]).get(); + ENCODE_FIELD( tagValue->tag); + ENCODE_FIELD( tagValue->value); + } + } + } + + ///////////////////////////////////////////////////////////////////////////// + // Send the shares allocation. + // + // This specifies the number of order shares allocated to each Financial + // Advisor managed account. The format of the allocation string is as + // follows: + // /,/,...N + // E.g. + // To allocate 20 shares of a 100 share order to account 'U101' and the + // residual 80 to account 'U203' enter the following share allocation string: + // U101/20,U203/80 + ///////////////////////////////////////////////////////////////////////////// + { + // send deprecated sharesAllocation field + ENCODE_FIELD( ""); // srv v9 and above + } + + ENCODE_FIELD( order.discretionaryAmt); // srv v10 and above + ENCODE_FIELD( order.goodAfterTime); // srv v11 and above + ENCODE_FIELD( order.goodTillDate); // srv v12 and above + + ENCODE_FIELD( order.faGroup); // srv v13 and above + ENCODE_FIELD( order.faMethod); // srv v13 and above + ENCODE_FIELD( order.faPercentage); // srv v13 and above + ENCODE_FIELD( order.faProfile); // srv v13 and above + + if (m_serverVersion >= MIN_SERVER_VER_MODELS_SUPPORT) { + ENCODE_FIELD( order.modelCode); + } + + // institutional short saleslot data (srv v18 and above) + ENCODE_FIELD( order.shortSaleSlot); // 0 for retail, 1 or 2 for institutions + ENCODE_FIELD( order.designatedLocation); // populate only when shortSaleSlot = 2. + if (m_serverVersion >= MIN_SERVER_VER_SSHORTX_OLD) { + ENCODE_FIELD( order.exemptCode); + } + + // not needed anymore + //bool isVolOrder = (order.orderType.CompareNoCase("VOL") == 0); + + // srv v19 and above fields + ENCODE_FIELD( order.ocaType); + //if( m_serverVersion < 38) { + // will never happen + // send( /* order.rthOnly */ false); + //} + ENCODE_FIELD( order.rule80A); + ENCODE_FIELD( order.settlingFirm); + ENCODE_FIELD( order.allOrNone); + ENCODE_FIELD_MAX( order.minQty); + ENCODE_FIELD_MAX( order.percentOffset); + ENCODE_FIELD( order.eTradeOnly); + ENCODE_FIELD( order.firmQuoteOnly); + ENCODE_FIELD_MAX( order.nbboPriceCap); + ENCODE_FIELD( order.auctionStrategy); // AUCTION_MATCH, AUCTION_IMPROVEMENT, AUCTION_TRANSPARENT + ENCODE_FIELD_MAX( order.startingPrice); + ENCODE_FIELD_MAX( order.stockRefPrice); + ENCODE_FIELD_MAX( order.delta); + // Volatility orders had specific watermark price attribs in server version 26 + //double lower = (m_serverVersion == 26 && isVolOrder) ? DBL_MAX : order.stockRangeLower; + //double upper = (m_serverVersion == 26 && isVolOrder) ? DBL_MAX : order.stockRangeUpper; + ENCODE_FIELD_MAX( order.stockRangeLower); + ENCODE_FIELD_MAX( order.stockRangeUpper); + + ENCODE_FIELD( order.overridePercentageConstraints); // srv v22 and above + + // Volatility orders (srv v26 and above) + ENCODE_FIELD_MAX( order.volatility); + ENCODE_FIELD_MAX( order.volatilityType); + // will never happen + //if( m_serverVersion < 28) { + // send( order.deltaNeutralOrderType.CompareNoCase("MKT") == 0); + //} + //else { + ENCODE_FIELD( order.deltaNeutralOrderType); // srv v28 and above + ENCODE_FIELD_MAX( order.deltaNeutralAuxPrice); // srv v28 and above + + if (m_serverVersion >= MIN_SERVER_VER_DELTA_NEUTRAL_CONID && !order.deltaNeutralOrderType.empty()){ + ENCODE_FIELD( order.deltaNeutralConId); + ENCODE_FIELD( order.deltaNeutralSettlingFirm); + ENCODE_FIELD( order.deltaNeutralClearingAccount); + ENCODE_FIELD( order.deltaNeutralClearingIntent); + } + + if (m_serverVersion >= MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE && !order.deltaNeutralOrderType.empty()){ + ENCODE_FIELD( order.deltaNeutralOpenClose); + ENCODE_FIELD( order.deltaNeutralShortSale); + ENCODE_FIELD( order.deltaNeutralShortSaleSlot); + ENCODE_FIELD( order.deltaNeutralDesignatedLocation); + } + + //} + ENCODE_FIELD( order.continuousUpdate); + //if( m_serverVersion == 26) { + // // Volatility orders had specific watermark price attribs in server version 26 + // double lower = (isVolOrder ? order.stockRangeLower : DBL_MAX); + // double upper = (isVolOrder ? order.stockRangeUpper : DBL_MAX); + // ENCODE_FIELD_MAX( lower); + // ENCODE_FIELD_MAX( upper); + //} + ENCODE_FIELD_MAX( order.referencePriceType); + + ENCODE_FIELD_MAX( order.trailStopPrice); // srv v30 and above + + if( m_serverVersion >= MIN_SERVER_VER_TRAILING_PERCENT) { + ENCODE_FIELD_MAX( order.trailingPercent); + } + + // SCALE orders + if( m_serverVersion >= MIN_SERVER_VER_SCALE_ORDERS2) { + ENCODE_FIELD_MAX( order.scaleInitLevelSize); + ENCODE_FIELD_MAX( order.scaleSubsLevelSize); + } + else { + // srv v35 and above) + ENCODE_FIELD( ""); // for not supported scaleNumComponents + ENCODE_FIELD_MAX( order.scaleInitLevelSize); // for scaleComponentSize + } + + ENCODE_FIELD_MAX( order.scalePriceIncrement); + + if( m_serverVersion >= MIN_SERVER_VER_SCALE_ORDERS3 + && order.scalePriceIncrement > 0.0 && order.scalePriceIncrement != UNSET_DOUBLE) { + ENCODE_FIELD_MAX( order.scalePriceAdjustValue); + ENCODE_FIELD_MAX( order.scalePriceAdjustInterval); + ENCODE_FIELD_MAX( order.scaleProfitOffset); + ENCODE_FIELD( order.scaleAutoReset); + ENCODE_FIELD_MAX( order.scaleInitPosition); + ENCODE_FIELD_MAX( order.scaleInitFillQty); + ENCODE_FIELD( order.scaleRandomPercent); + } + + if( m_serverVersion >= MIN_SERVER_VER_SCALE_TABLE) { + ENCODE_FIELD( order.scaleTable); + ENCODE_FIELD( order.activeStartTime); + ENCODE_FIELD( order.activeStopTime); + } + + // HEDGE orders + if( m_serverVersion >= MIN_SERVER_VER_HEDGE_ORDERS) { + ENCODE_FIELD( order.hedgeType); + if ( !order.hedgeType.empty()) { + ENCODE_FIELD( order.hedgeParam); + } + } + + if( m_serverVersion >= MIN_SERVER_VER_OPT_OUT_SMART_ROUTING){ + ENCODE_FIELD( order.optOutSmartRouting); + } + + if( m_serverVersion >= MIN_SERVER_VER_PTA_ORDERS) { + ENCODE_FIELD( order.clearingAccount); + ENCODE_FIELD( order.clearingIntent); + } + + if( m_serverVersion >= MIN_SERVER_VER_NOT_HELD){ + ENCODE_FIELD( order.notHeld); + } + + if( m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) { + if( contract.underComp) { + const UnderComp& underComp = *contract.underComp; + ENCODE_FIELD( true); + ENCODE_FIELD( underComp.conId); + ENCODE_FIELD( underComp.delta); + ENCODE_FIELD( underComp.price); + } + else { + ENCODE_FIELD( false); + } + } + + if( m_serverVersion >= MIN_SERVER_VER_ALGO_ORDERS) { + ENCODE_FIELD( order.algoStrategy); + + if( !order.algoStrategy.empty()) { + const TagValueList* const algoParams = order.algoParams.get(); + const int algoParamsCount = algoParams ? algoParams->size() : 0; + ENCODE_FIELD( algoParamsCount); + if( algoParamsCount > 0) { + for( int i = 0; i < algoParamsCount; ++i) { + const TagValue* tagValue = ((*algoParams)[i]).get(); + ENCODE_FIELD( tagValue->tag); + ENCODE_FIELD( tagValue->value); + } + } + } + + } + + if( m_serverVersion >= MIN_SERVER_VER_ALGO_ID) { + ENCODE_FIELD( order.algoId); + } + + ENCODE_FIELD( order.whatIf); // srv v36 and above + + // send miscOptions parameter + if( m_serverVersion >= MIN_SERVER_VER_LINKING) { + std::string miscOptionsStr(""); + const TagValueList* const orderMiscOptions = order.orderMiscOptions.get(); + const int orderMiscOptionsCount = orderMiscOptions ? orderMiscOptions->size() : 0; + if( orderMiscOptionsCount > 0) { + for( int i = 0; i < orderMiscOptionsCount; ++i) { + const TagValue* tagValue = ((*orderMiscOptions)[i]).get(); + miscOptionsStr += tagValue->tag; + miscOptionsStr += "="; + miscOptionsStr += tagValue->value; + miscOptionsStr += ";"; + } + } + ENCODE_FIELD( miscOptionsStr); + } + + if (m_serverVersion >= MIN_SERVER_VER_ORDER_SOLICITED) { + ENCODE_FIELD(order.solicited); + } + + if (m_serverVersion >= MIN_SERVER_VER_RANDOMIZE_SIZE_AND_PRICE) { + ENCODE_FIELD(order.randomizeSize); + ENCODE_FIELD(order.randomizePrice); + } + + if (m_serverVersion >= MIN_SERVER_VER_PEGGED_TO_BENCHMARK) { + if (order.orderType == "PEG BENCH") { + ENCODE_FIELD(order.referenceContractId); + ENCODE_FIELD(order.isPeggedChangeAmountDecrease); + ENCODE_FIELD(order.peggedChangeAmount); + ENCODE_FIELD(order.referenceChangeAmount); + ENCODE_FIELD(order.referenceExchangeId); + } + + ENCODE_FIELD(order.conditions.size()); + + if (order.conditions.size() > 0) { + for (ibapi::shared_ptr item : order.conditions) { + ENCODE_FIELD(item->type()); + item->writeExternal(msg); + } + + ENCODE_FIELD(order.conditionsIgnoreRth); + ENCODE_FIELD(order.conditionsCancelOrder); + } + + ENCODE_FIELD(order.adjustedOrderType); + ENCODE_FIELD(order.triggerPrice); + ENCODE_FIELD(order.lmtPriceOffset); + ENCODE_FIELD(order.adjustedStopPrice); + ENCODE_FIELD(order.adjustedStopLimitPrice); + ENCODE_FIELD(order.adjustedTrailingAmount); + ENCODE_FIELD(order.adjustableTrailingUnit); + } + + if( m_serverVersion >= MIN_SERVER_VER_EXT_OPERATOR) { + ENCODE_FIELD( order.extOperator); + } + + if (m_serverVersion >= MIN_SERVER_VER_SOFT_DOLLAR_TIER) { + ENCODE_FIELD(order.softDollarTier.name()); + ENCODE_FIELD(order.softDollarTier.val()); + } + + closeAndSend( msg.str()); +} + +void EClient::cancelOrder( OrderId id) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( id, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + const int VERSION = 1; + + // send cancel order msg + std::stringstream msg; + prepareBuffer( msg); + + ENCODE_FIELD( CANCEL_ORDER); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( id); + + closeAndSend( msg.str()); +} + +void EClient::reqAccountUpdates(bool subscribe, const std::string& acctCode) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + // send req acct msg + ENCODE_FIELD( REQ_ACCT_DATA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( subscribe); // TRUE = subscribe, FALSE = unsubscribe. + + // Send the account code. This will only be used for FA clients + ENCODE_FIELD( acctCode); // srv v9 and above + + closeAndSend( msg.str()); +} + +void EClient::reqOpenOrders() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req open orders msg + ENCODE_FIELD( REQ_OPEN_ORDERS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::reqAutoOpenOrders(bool bAutoBind) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req open orders msg + ENCODE_FIELD( REQ_AUTO_OPEN_ORDERS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( bAutoBind); + + closeAndSend( msg.str()); +} + +void EClient::reqAllOpenOrders() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req open orders msg + ENCODE_FIELD( REQ_ALL_OPEN_ORDERS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::reqExecutions(int reqId, const ExecutionFilter& filter) +{ + //NOTE: Time format must be 'yyyymmdd-hh:mm:ss' E.g. '20030702-14:55' + + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 3; + + // send req open orders msg + ENCODE_FIELD( REQ_EXECUTIONS); + ENCODE_FIELD( VERSION); + + if( m_serverVersion >= MIN_SERVER_VER_EXECUTION_DATA_CHAIN) { + ENCODE_FIELD( reqId); + } + + // Send the execution rpt filter data (srv v9 and above) + ENCODE_FIELD( filter.m_clientId); + ENCODE_FIELD( filter.m_acctCode); + ENCODE_FIELD( filter.m_time); + ENCODE_FIELD( filter.m_symbol); + ENCODE_FIELD( filter.m_secType); + ENCODE_FIELD( filter.m_exchange); + ENCODE_FIELD( filter.m_side); + + closeAndSend( msg.str()); +} + +void EClient::reqIds( int numIds) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( numIds, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req open orders msg + ENCODE_FIELD( REQ_IDS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( numIds); + + closeAndSend( msg.str()); +} + +void EClient::reqNewsBulletins(bool allMsgs) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req news bulletins msg + ENCODE_FIELD( REQ_NEWS_BULLETINS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( allMsgs); + + closeAndSend( msg.str()); +} + +void EClient::cancelNewsBulletins() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req news bulletins msg + ENCODE_FIELD( CANCEL_NEWS_BULLETINS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::setServerLogLevel(int logLevel) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send the set server logging level message + ENCODE_FIELD( SET_SERVER_LOGLEVEL); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( logLevel); + + closeAndSend( msg.str()); +} + +void EClient::reqManagedAccts() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send req FA managed accounts msg + ENCODE_FIELD( REQ_MANAGED_ACCTS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + + +void EClient::requestFA(faDataType pFaDataType) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 13) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_FA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( (int)pFaDataType); + + closeAndSend( msg.str()); +} + +void EClient::replaceFA(faDataType pFaDataType, const std::string& cxml) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 13) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REPLACE_FA); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( (int)pFaDataType); + ENCODE_FIELD( cxml); + + closeAndSend( msg.str()); +} + + + +void EClient::exerciseOptions( TickerId tickerId, const Contract& contract, + int exerciseAction, int exerciseQuantity, + const std::string& account, int override) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + // Not needed anymore validation + //if( m_serverVersion < 21) { + // m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg()); + // return; + //} + + if (m_serverVersion < MIN_SERVER_VER_TRADING_CLASS) { + if( !contract.tradingClass.empty() || (contract.conId > 0)) { + m_pEWrapper->error( tickerId, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support conId, multiplier and tradingClass parameters in exerciseOptions."); + return; + } + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + ENCODE_FIELD( EXERCISE_OPTIONS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( tickerId); + + // send contract fields + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.conId); + } + ENCODE_FIELD( contract.symbol); + ENCODE_FIELD( contract.secType); + ENCODE_FIELD( contract.lastTradeDateOrContractMonth); + ENCODE_FIELD( contract.strike); + ENCODE_FIELD( contract.right); + ENCODE_FIELD( contract.multiplier); + ENCODE_FIELD( contract.exchange); + ENCODE_FIELD( contract.currency); + ENCODE_FIELD( contract.localSymbol); + if( m_serverVersion >= MIN_SERVER_VER_TRADING_CLASS) { + ENCODE_FIELD( contract.tradingClass); + } + ENCODE_FIELD( exerciseAction); + ENCODE_FIELD( exerciseQuantity); + ENCODE_FIELD( account); + ENCODE_FIELD( override); + + closeAndSend( msg.str()); +} + +void EClient::reqGlobalCancel() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if (m_serverVersion < MIN_SERVER_VER_REQ_GLOBAL_CANCEL) { + m_pEWrapper->error( NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support globalCancel requests."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + // send current time req + ENCODE_FIELD( REQ_GLOBAL_CANCEL); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::reqMarketDataType( int marketDataType) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_REQ_MARKET_DATA_TYPE) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support market data type requests."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_MARKET_DATA_TYPE); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( marketDataType); + + closeAndSend( msg.str()); +} + +int EClient::bufferedRead() +{ + char buf[8192]; + int nResult = receive( buf, sizeof(buf)); + + if( nResult > 0) { + m_inBuffer.insert( m_inBuffer.end(), &buf[0], &buf[0] + nResult); + } + + return nResult; +} + +void EClient::reqPositions() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_POSITIONS) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support positions request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_POSITIONS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::cancelPositions() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_POSITIONS) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support positions cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_POSITIONS); + ENCODE_FIELD( VERSION); + + closeAndSend( msg.str()); +} + +void EClient::reqAccountSummary( int reqId, const std::string& groupName, const std::string& tags) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_ACCOUNT_SUMMARY) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support account summary request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_ACCOUNT_SUMMARY); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + ENCODE_FIELD( groupName); + ENCODE_FIELD( tags); + + closeAndSend( msg.str()); +} + +void EClient::cancelAccountSummary( int reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_ACCOUNT_SUMMARY) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support account summary cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_ACCOUNT_SUMMARY); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::verifyRequest(const std::string& apiName, const std::string& apiVersion) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support verification request."); + return; + } + + if( !m_extraAuth) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " Intent to authenticate needs to be expressed during initial connect request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( VERIFY_REQUEST); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( apiName); + ENCODE_FIELD( apiVersion); + + closeAndSend( msg.str()); +} + +void EClient::verifyMessage(const std::string& apiData) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support verification message sending."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( VERIFY_MESSAGE); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( apiData); + + closeAndSend( msg.str()); +} + +void EClient::verifyAndAuthRequest(const std::string& apiName, const std::string& apiVersion, const std::string& opaqueIsvKey) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING_AUTH) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support verification request."); + return; + } + + if( !m_extraAuth) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " Intent to authenticate needs to be expressed during initial connect request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( VERIFY_AND_AUTH_REQUEST); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( apiName); + ENCODE_FIELD( apiVersion); + ENCODE_FIELD( opaqueIsvKey); + + closeAndSend( msg.str()); +} + +void EClient::verifyAndAuthMessage(const std::string& apiData, const std::string& xyzResponse) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING_AUTH) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support verification message sending."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( VERIFY_AND_AUTH_MESSAGE); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( apiData); + ENCODE_FIELD( xyzResponse); + + closeAndSend( msg.str()); +} + +void EClient::queryDisplayGroups( int reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support queryDisplayGroups request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( QUERY_DISPLAY_GROUPS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::subscribeToGroupEvents( int reqId, int groupId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support subscribeToGroupEvents request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( SUBSCRIBE_TO_GROUP_EVENTS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + ENCODE_FIELD( groupId); + + closeAndSend( msg.str()); +} + +void EClient::updateDisplayGroup( int reqId, const std::string& contractInfo) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support updateDisplayGroup request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( UPDATE_DISPLAY_GROUP); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + ENCODE_FIELD( contractInfo); + + closeAndSend( msg.str()); +} + +void EClient::startApi() +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion >= 3) { + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + std::stringstream msg; + ENCODE_FIELD( m_clientId); + bufferedSend( msg.str()); + } + else + { + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 2; + + ENCODE_FIELD( START_API); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( m_clientId); + + if (m_serverVersion >= MIN_SERVER_VER_OPTIONAL_CAPABILITIES) + ENCODE_FIELD(m_optionalCapabilities); + + closeAndSend( msg.str()); + } + } +} + +void EClient::unsubscribeFromGroupEvents( int reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_LINKING) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support unsubscribeFromGroupEvents request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( UNSUBSCRIBE_FROM_GROUP_EVENTS); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::reqPositionsMulti( int reqId, const std::string& account, const std::string& modelCode) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_MODELS_SUPPORT) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support positions multi request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_POSITIONS_MULTI); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + ENCODE_FIELD( account); + ENCODE_FIELD( modelCode); + + closeAndSend( msg.str()); +} + +void EClient::cancelPositionsMulti( int reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_MODELS_SUPPORT) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support positions multi cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_POSITIONS_MULTI); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::reqAccountUpdatessMulti( int reqId, const std::string& account, const std::string& modelCode, bool ledgerAndNLV) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_MODELS_SUPPORT) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support account updates multi request."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( REQ_ACCOUNT_UPDATES_MULTI); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + ENCODE_FIELD( account); + ENCODE_FIELD( modelCode); + ENCODE_FIELD( ledgerAndNLV); + + closeAndSend( msg.str()); +} + +void EClient::cancelAccountUpdatesMulti( int reqId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_MODELS_SUPPORT) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support account updates multi cancellation."); + return; + } + + std::stringstream msg; + prepareBuffer( msg); + + const int VERSION = 1; + + ENCODE_FIELD( CANCEL_ACCOUNT_UPDATES_MULTI); + ENCODE_FIELD( VERSION); + ENCODE_FIELD( reqId); + + closeAndSend( msg.str()); +} + +void EClient::reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, const std::string& futFopExchange, const std::string& underlyingSecType, int underlyingConId) +{ + // not connected? + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + if( m_serverVersion < MIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ) { + m_pEWrapper->error(NO_VALID_ID, UPDATE_TWS.code(), UPDATE_TWS.msg() + + " It does not support security definiton option requests."); + return; + } + + std::stringstream msg; + prepareBuffer(msg); + + + ENCODE_FIELD(REQ_SEC_DEF_OPT_PARAMS); + ENCODE_FIELD(reqId); + ENCODE_FIELD(underlyingSymbol); + ENCODE_FIELD(futFopExchange); + ENCODE_FIELD(underlyingSecType); + ENCODE_FIELD(underlyingConId); + + closeAndSend(msg.str()); +} + +void EClient::reqSoftDollarTiers(int reqId) +{ + if( !isConnected()) { + m_pEWrapper->error( NO_VALID_ID, NOT_CONNECTED.code(), NOT_CONNECTED.msg()); + return; + } + + std::stringstream msg; + prepareBuffer(msg); + + + ENCODE_FIELD(REQ_SOFT_DOLLAR_TIERS); + ENCODE_FIELD(reqId); + + closeAndSend(msg.str()); +} + +int EClient::processMsgImpl(const char*& beginPtr, const char* endPtr) +{ + EDecoder decoder(serverVersion(), m_pEWrapper); + + return decoder.parseAndProcessMsg(beginPtr, endPtr); +} + +int EClient::processOnePrefixedMsg(const char*& beginPtr, const char* endPtr, messageHandler handler) +{ + if( beginPtr + HEADER_LEN >= endPtr) + return 0; + + assert( sizeof(unsigned) == HEADER_LEN); + + unsigned netLen = 0; + memcpy( &netLen, beginPtr, HEADER_LEN); + + const unsigned msgLen = ntohl(netLen); + + // shold never happen, but still.... + if( !msgLen) { + beginPtr += HEADER_LEN; + return HEADER_LEN; + } + + // enforce max msg len limit + if( msgLen > MAX_MSG_LEN) { + m_pEWrapper->error( NO_VALID_ID, BAD_LENGTH.code(), BAD_LENGTH.msg()); + eDisconnect(); + m_pEWrapper->connectionClosed(); + return 0; + } + + const char* msgStart = beginPtr + HEADER_LEN; + const char* msgEnd = msgStart + msgLen; + + // handle incomplete messages + if( msgEnd > endPtr) { + return 0; + } + + int decoded = (this->*handler)( msgStart, msgEnd); + if( decoded <= 0) { + // this would mean something went real wrong + // and message was incomplete from decoder POV + m_pEWrapper->error( NO_VALID_ID, BAD_MESSAGE.code(), BAD_MESSAGE.msg()); + eDisconnect(); + m_pEWrapper->connectionClosed(); + return 0; + } + + int consumed = msgEnd - beginPtr; + beginPtr = msgEnd; + return consumed; +} + +bool EClient::extraAuth() { + return m_extraAuth; +} + +int EClient::processMsg(const char*& beginPtr, const char* endPtr) +{ + if( !m_useV100Plus) { + return processMsgImpl( beginPtr, endPtr); + } + return processOnePrefixedMsg( beginPtr, endPtr, &EClient::processMsgImpl); +} + +EWrapper * EClient::getWrapper() const +{ + return m_pEWrapper; +} + +void EClient::setClientId( int clientId) +{ + m_clientId = clientId; +} + +void EClient::setExtraAuth( bool extraAuth) +{ + m_extraAuth = extraAuth; +} + +void EClient::setHost( const std::string& host) +{ + m_host = host; +} + +void EClient::setPort( unsigned port) +{ + m_port = port; +} + + +/////////////////////////////////////////////////////////// +// callbacks from socket +int EClient::sendConnectRequest() +{ + m_connState = CS_CONNECTING; + + int rval; + + // send client version + std::stringstream msg; + if( m_useV100Plus) { + msg.write( API_SIGN, sizeof(API_SIGN)); + prepareBufferImpl( msg); + if( MIN_CLIENT_VER < MAX_CLIENT_VER) { + msg << 'v' << MIN_CLIENT_VER << ".." << MAX_CLIENT_VER; + } + else { + msg << 'v' << MIN_CLIENT_VER; + } + if( !m_connectOptions.empty()) { + msg << ' ' << m_connectOptions; + } + + rval = closeAndSend( msg.str(), sizeof(API_SIGN)); + } + else { + ENCODE_FIELD( CLIENT_VERSION); + + rval = bufferedSend( msg.str()); + } + + m_connState = rval > 0 ? CS_CONNECTED : CS_DISCONNECTED; + + return rval; +} + +bool EClient::isInBufferEmpty() const +{ + return m_inBuffer.empty(); +} + diff --git a/vn.ib/ibapi/windows/client/EClient.h b/vn.ib/ibapi/windows/client/EClient.h new file mode 100644 index 00000000..15c96d15 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EClient.h @@ -0,0 +1,384 @@ +/* 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. */ + +#pragma once +#ifndef eclient_h__INCLUDED +#define eclient_h__INCLUDED + + +#include +#include +#include +#include +#include "CommonDefs.h" +#include "TagValue.h" + +namespace ibapi { +namespace client_constants { + +///////////////////////////////////////////////////////////////////////////////// +// SOCKET CLIENT VERSION CHANGE LOG : Incremented when the format of incomming +// server responses change +///////////////////////////////////////////////////////////////////////////////// +// constants +// 6 = Added parentId to orderStatus +// 7 = The new execDetails event returned for an order filled status and reqExecDetails +// Also added market depth support. +// 8 = Added 'lastFillPrice' to orderStatus and 'permId' to execDetails +// 9 = Added 'avgCost', '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 = Added IgnoreRth, hidden, and discretionaryAmt +// 13 = Added GoodAfterTime +// 14 = always send size on bid/ask/last tick +// 15 = send allocation string with open order +// 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 send backfill requests +// 19 = can receive new extended order attributes in OPEN_ORDER +// 20 = expects TWS time string on connection after server version >= 20, and parentId in open order +// 21 = can receive bond contract details. +// 22 = can receive price magnifier in contract details +// 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 +// 28 = can receive option model computation ticks +// 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 +// 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 multipier 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 +// can receive position, positionEnd, accountSummary and accountSummaryEnd +// 61 = can receive multiplier in openOrder +// can receive tradingClass in openOrder, updatePortfolio, execDetails and position +// 62 = can receive avgCost in position message +// 63 = can receive verifyMessageAPI, verifyCompleted, displayGroupList and displayGroupUpdated messages +// 64 = can receive solicited attrib in openOrder message +// 65 = can receive verifyAndAuthMessageAPI and verifyAndAuthCompleted messages +// 66 = can receive randomize size and randomize price order fields + +const int CLIENT_VERSION = 66; + + +// outgoing msg id's +const int REQ_MKT_DATA = 1; +const int CANCEL_MKT_DATA = 2; +const int PLACE_ORDER = 3; +const int CANCEL_ORDER = 4; +const int REQ_OPEN_ORDERS = 5; +const int REQ_ACCT_DATA = 6; +const int REQ_EXECUTIONS = 7; +const int REQ_IDS = 8; +const int REQ_CONTRACT_DATA = 9; +const int REQ_MKT_DEPTH = 10; +const int CANCEL_MKT_DEPTH = 11; +const int REQ_NEWS_BULLETINS = 12; +const int CANCEL_NEWS_BULLETINS = 13; +const int SET_SERVER_LOGLEVEL = 14; +const int REQ_AUTO_OPEN_ORDERS = 15; +const int REQ_ALL_OPEN_ORDERS = 16; +const int REQ_MANAGED_ACCTS = 17; +const int REQ_FA = 18; +const int REPLACE_FA = 19; +const int REQ_HISTORICAL_DATA = 20; +const int EXERCISE_OPTIONS = 21; +const int REQ_SCANNER_SUBSCRIPTION = 22; +const int CANCEL_SCANNER_SUBSCRIPTION = 23; +const int REQ_SCANNER_PARAMETERS = 24; +const int CANCEL_HISTORICAL_DATA = 25; +const int REQ_CURRENT_TIME = 49; +const int REQ_REAL_TIME_BARS = 50; +const int CANCEL_REAL_TIME_BARS = 51; +const int REQ_FUNDAMENTAL_DATA = 52; +const int CANCEL_FUNDAMENTAL_DATA = 53; +const int REQ_CALC_IMPLIED_VOLAT = 54; +const int REQ_CALC_OPTION_PRICE = 55; +const int CANCEL_CALC_IMPLIED_VOLAT = 56; +const int CANCEL_CALC_OPTION_PRICE = 57; +const int REQ_GLOBAL_CANCEL = 58; +const int REQ_MARKET_DATA_TYPE = 59; +const int REQ_POSITIONS = 61; +const int REQ_ACCOUNT_SUMMARY = 62; +const int CANCEL_ACCOUNT_SUMMARY = 63; +const int CANCEL_POSITIONS = 64; +const int VERIFY_REQUEST = 65; +const int VERIFY_MESSAGE = 66; +const int QUERY_DISPLAY_GROUPS = 67; +const int SUBSCRIBE_TO_GROUP_EVENTS = 68; +const int UPDATE_DISPLAY_GROUP = 69; +const int UNSUBSCRIBE_FROM_GROUP_EVENTS = 70; +const int START_API = 71; +const int VERIFY_AND_AUTH_REQUEST = 72; +const int VERIFY_AND_AUTH_MESSAGE = 73; +const int REQ_POSITIONS_MULTI = 74; +const int CANCEL_POSITIONS_MULTI = 75; +const int REQ_ACCOUNT_UPDATES_MULTI = 76; +const int CANCEL_ACCOUNT_UPDATES_MULTI = 77; +const int REQ_SEC_DEF_OPT_PARAMS = 78; +const int REQ_SOFT_DOLLAR_TIERS = 79; + +// TWS New Bulletins constants +const int NEWS_MSG = 1; // standard IB news bulleting message +const int EXCHANGE_AVAIL_MSG = 2; // control message specifing that an exchange is available for trading +const int EXCHANGE_UNAVAIL_MSG = 3; // control message specifing that an exchange is unavailable for trading + +} // namespace client_constants +} // namespace ibapi + +struct Contract; +struct Order; +struct ExecutionFilter; +struct ScannerSubscription; +struct ETransport; + +class EWrapper; +typedef std::vector BytesVec; + + +class TWSAPIDLLEXP EClient +{ +public: + + explicit EClient(EWrapper *ptr, ETransport *pTransport); + ~EClient(); + + virtual void eDisconnect() = 0; + + int clientId() const { return m_clientId; } + + const std::string& optionalCapabilities() const; + void setOptionalCapabilities(const std::string& optCapts); + + void setConnectOptions(const std::string& connectOptions); + void disableUseV100Plus(); + bool usingV100Plus(); + +protected: + + void eConnectBase(); + void eDisconnectBase(); + +public: + + enum ConnState { + CS_DISCONNECTED, + CS_CONNECTING, + CS_CONNECTED, + CS_REDIRECT + }; + + // connection state + ConnState connState() const; + bool isConnected() const; + + const std::string& host() const { return m_host; } + unsigned port() const { return m_port; } + +public: + + // access to protected variables + EWrapper * getWrapper() const; +protected: + void setClientId( int clientId); + void setExtraAuth( bool extraAuth); + void setHost( const std::string& host); + void setPort( unsigned port); + +public: + + bool isInBufferEmpty() const; + + // override virtual funcs from EClient + int serverVersion(); + std::string TwsConnectionTime(); + void reqMktData(TickerId id, const Contract& contract, + const std::string& genericTicks, bool snapshot, const TagValueListSPtr& mktDataOptions); + void cancelMktData(TickerId id); + void placeOrder(OrderId id, const Contract& contract, const Order& order); + void cancelOrder(OrderId id) ; + void reqOpenOrders(); + void reqAccountUpdates(bool subscribe, const std::string& acctCode); + void reqExecutions(int reqId, const ExecutionFilter& filter); + void reqIds(int numIds); + void reqContractDetails(int reqId, const Contract& contract); + void reqMktDepth(TickerId tickerId, const Contract& contract, int numRows, const TagValueListSPtr& mktDepthOptions); + void cancelMktDepth(TickerId tickerId); + void reqNewsBulletins(bool allMsgs); + void cancelNewsBulletins(); + void setServerLogLevel(int level); + void reqAutoOpenOrders(bool bAutoBind); + void reqAllOpenOrders(); + void reqManagedAccts(); + void requestFA(faDataType pFaDataType); + void replaceFA(faDataType pFaDataType, const std::string& cxml); + void reqHistoricalData( TickerId id, const Contract& contract, + const std::string& endDateTime, const std::string& durationStr, + const std::string& barSizeSetting, const std::string& whatToShow, + int useRTH, int formatDate, const TagValueListSPtr& chartOptions); + void exerciseOptions(TickerId tickerId, const Contract& contract, + int exerciseAction, int exerciseQuantity, + const std::string& account, int override); + void cancelHistoricalData(TickerId tickerId ); + void reqRealTimeBars(TickerId id, const Contract& contract, int barSize, + const std::string& whatToShow, bool useRTH, const TagValueListSPtr& realTimeBarsOptions); + void cancelRealTimeBars(TickerId tickerId ); + void cancelScannerSubscription(int tickerId); + void reqScannerParameters(); + void reqScannerSubscription(int tickerId, const ScannerSubscription& subscription, const TagValueListSPtr& scannerSubscriptionOptions); + void reqCurrentTime(); + void reqFundamentalData(TickerId reqId, const Contract&, const std::string& reportType); + void cancelFundamentalData(TickerId reqId); + void calculateImpliedVolatility(TickerId reqId, const Contract& contract, double optionPrice, double underPrice); + void calculateOptionPrice(TickerId reqId, const Contract& contract, double volatility, double underPrice); + void cancelCalculateImpliedVolatility(TickerId reqId); + void cancelCalculateOptionPrice(TickerId reqId); + void reqGlobalCancel(); + void reqMarketDataType(int marketDataType); + void reqPositions(); + void cancelPositions(); + void reqAccountSummary( int reqId, const std::string& groupName, const std::string& tags); + void cancelAccountSummary( int reqId); + void verifyRequest( const std::string& apiName, const std::string& apiVersion); + void verifyMessage( const std::string& apiData); + void verifyAndAuthRequest( const std::string& apiName, const std::string& apiVersion, const std::string& opaqueIsvKey); + void verifyAndAuthMessage( const std::string& apiData, const std::string& xyzResponse); + void queryDisplayGroups( int reqId); + void subscribeToGroupEvents( int reqId, int groupId); + void updateDisplayGroup( int reqId, const std::string& contractInfo); + void unsubscribeFromGroupEvents( int reqId); + void reqPositionsMulti( int reqId, const std::string& account, const std::string& modelCode); + void cancelPositionsMulti( int reqId); + void reqAccountUpdatessMulti( int reqId, const std::string& account, const std::string& modelCode, bool ledgerAndNLV); + void cancelAccountUpdatesMulti( int reqId); + void reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, const std::string& futFopExchange, const std::string& underlyingSecType, int underlyingConId); + void reqSoftDollarTiers(int reqId); + +private: + + virtual int receive(char* buf, size_t sz) = 0; + +protected: + + virtual void prepareBufferImpl(std::ostream&) const = 0; + virtual void prepareBuffer(std::ostream&) const = 0; + virtual bool closeAndSend(std::string msg, unsigned offset = 0) = 0; + virtual int bufferedSend(const std::string& msg); + +protected: + int bufferedRead(); + + // try to process connection request ack +private: + // try to process single msg + int processMsgImpl(const char*& ptr, const char* endPtr); + int processMsg(const char*& ptr, const char* endPtr); + + typedef int (EClient::*messageHandler)(const char*& ptr, const char* endPtr); + int processOnePrefixedMsg(const char*& ptr, const char* endPtr, messageHandler); + +public: + void startApi(); + + + // encoders + template static void EncodeField(std::ostream&, T); + + // "max" encoders + static void EncodeFieldMax(std::ostream& os, int); + static void EncodeFieldMax(std::ostream& os, double); + + // socket state +private: + virtual bool isSocketOK() const = 0; + +protected: + + bool isConnecting() const; + int sendConnectRequest(); + bool extraAuth(); + +protected: + + EWrapper *m_pEWrapper; + std::auto_ptr m_transport; + +private: + BytesVec m_inBuffer; + + std::string m_host; + int m_port; + + int m_clientId; + + ConnState m_connState; + bool m_extraAuth; + +protected: + int m_serverVersion; + std::string m_TwsTime; + +private: + std::string m_optionalCapabilities; + + std::string m_connectOptions; + +protected: + bool m_useV100Plus; + +}; + +template<> void EClient::EncodeField(std::ostream& os, bool); +template<> void EClient::EncodeField(std::ostream& os, double); + +#define ENCODE_FIELD(x) EClient::EncodeField(msg, x); +#define ENCODE_FIELD_MAX(x) EClient::EncodeFieldMax(msg, x); + + +#endif diff --git a/vn.ib/ibapi/windows/client/EClientMsgSink.h b/vn.ib/ibapi/windows/client/EClientMsgSink.h new file mode 100644 index 00000000..2bdc6d4e --- /dev/null +++ b/vn.ib/ibapi/windows/client/EClientMsgSink.h @@ -0,0 +1,10 @@ +/* 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. */ + +#pragma once +struct EClientMsgSink +{ + virtual void serverVersion(int version, const char *time) = 0; + virtual void redirect(const char *host, int port) = 0; +}; + diff --git a/vn.ib/ibapi/windows/client/EClientSocket.cpp b/vn.ib/ibapi/windows/client/EClientSocket.cpp new file mode 100644 index 00000000..8fbe26bd --- /dev/null +++ b/vn.ib/ibapi/windows/client/EClientSocket.cpp @@ -0,0 +1,332 @@ +/* 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. */ + +#include "StdAfx.h" + + +#include "EPosixClientSocketPlatform.h" +#include "EClientSocket.h" + +#include "TwsSocketClientErrors.h" +#include "EWrapper.h" +#include "EDecoder.h" +#include "EReaderSignal.h" +#include "EReader.h" +#include "EMessage.h" + +#include +#include +#include + +const int MIN_SERVER_VER_SUPPORTED = 38; //all supported server versions are defined in EDecoder.h + +/////////////////////////////////////////////////////////// +// member funcs +EClientSocket::EClientSocket(EWrapper *ptr, EReaderSignal *pSignal) : EClient( ptr, new ESocket()) +{ + m_fd = SocketsInit() ? -1 : -2; + m_allowRedirect = false; + m_asyncEConnect = false; + m_pSignal = pSignal; +} + +EClientSocket::~EClientSocket() +{ + if( m_fd != -2) + SocketsDestroy(); +} + +bool EClientSocket::asyncEConnect() const { + return m_asyncEConnect; +} + +void EClientSocket::asyncEConnect(bool val) { + m_asyncEConnect = val; +} + +bool EClientSocket::eConnect( const char *host, unsigned int port, int clientId, bool extraAuth) +{ + if( m_fd == -2) { + getWrapper()->error( NO_VALID_ID, FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()); + return false; + } + + // reset errno + errno = 0; + + // already connected? + if( m_fd >= 0) { + errno = EISCONN; + getWrapper()->error( NO_VALID_ID, ALREADY_CONNECTED.code(), ALREADY_CONNECTED.msg()); + return false; + } + + // normalize host + m_hostNorm = (host && *host) ? host : "127.0.0.1"; + + // initialize host and port + setHost( m_hostNorm); + setPort( port); + + // try to connect to specified host and port + ConnState resState = CS_DISCONNECTED; + + return eConnectImpl( clientId, extraAuth, &resState); +} + +ESocket *EClientSocket::getTransport() { + assert(dynamic_cast(m_transport.get()) != 0); + + return static_cast(m_transport.get()); +} + +bool EClientSocket::eConnectImpl(int clientId, bool extraAuth, ConnState* stateOutPt) +{ + // resolve host + struct hostent* hostEnt = gethostbyname( host().c_str()); + if ( !hostEnt) { + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + // create socket + m_fd = socket(AF_INET, SOCK_STREAM, 0); + + // cannot create socket + if( m_fd < 0) { + getWrapper()->error( NO_VALID_ID, FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()); + return false; + } + + // starting to connect to server + struct sockaddr_in sa; + memset( &sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port()); + sa.sin_addr.s_addr = ((in_addr*)hostEnt->h_addr)->s_addr; + + // try to connect + if( (connect( m_fd, (struct sockaddr *) &sa, sizeof( sa))) < 0) { + // error connecting + SocketClose( m_fd); + m_fd = -1; + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + getTransport()->fd(m_fd); + + // set client id + setClientId( clientId); + setExtraAuth( extraAuth); + + int res = sendConnectRequest(); + + if (res < 0 && !handleSocketError()) + return false; + + if( !isConnected()) { + if( connState() != CS_DISCONNECTED) { + assert( connState() == CS_REDIRECT); + if( stateOutPt) { + *stateOutPt = connState(); + } + eDisconnect(); + } + return false; + } + + // set socket to non-blocking state + if ( !SetSocketNonBlocking(m_fd)) { + // error setting socket to non-blocking + eDisconnect(); + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + assert( connState() == CS_CONNECTED); + if( stateOutPt) { + *stateOutPt = connState(); + } + + if (!m_asyncEConnect) { + EReader reader(this, m_pSignal); + + reader.putMessageToQueue(); + + while (m_pSignal && !m_serverVersion && isSocketOK()) { + reader.checkClient(); + m_pSignal->waitForSignal(); + reader.processMsgs(); + } + } + + // successfully connected + return isSocketOK(); +} + +void EClientSocket::encodeMsgLen(std::string& msg, unsigned offset) const +{ + assert( !msg.empty()); + assert( m_useV100Plus); + + assert( sizeof(unsigned) == HEADER_LEN); + assert( msg.size() > offset + HEADER_LEN); + unsigned len = msg.size() - HEADER_LEN - offset; + if( len > MAX_MSG_LEN) { + m_pEWrapper->error( NO_VALID_ID, BAD_LENGTH.code(), BAD_LENGTH.msg()); + return; + } + + unsigned netlen = htonl( len); + memcpy( &msg[offset], &netlen, HEADER_LEN); +} + +bool EClientSocket::closeAndSend(std::string msg, unsigned offset) +{ + assert( !msg.empty()); + if( m_useV100Plus) { + encodeMsgLen( msg, offset); + } + + if (bufferedSend(msg) == -1) + return handleSocketError(); + + return true; +} + +void EClientSocket::prepareBufferImpl(std::ostream& buf) const +{ + assert( m_useV100Plus); + assert( sizeof(unsigned) == HEADER_LEN); + + char header[HEADER_LEN] = { 0 }; + buf.write( header, sizeof(header)); +} + +void EClientSocket::prepareBuffer(std::ostream& buf) const +{ + if( !m_useV100Plus) + return; + + prepareBufferImpl( buf); +} + +void EClientSocket::eDisconnect() +{ + if ( m_fd >= 0 ) + // close socket + SocketClose( m_fd); + m_fd = -1; + + eDisconnectBase(); +} + +bool EClientSocket::isSocketOK() const +{ + return ( m_fd >= 0); +} + +int EClientSocket::fd() const +{ + return m_fd; +} + +int EClientSocket::receive(char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + int nResult = ::recv( m_fd, buf, sz, 0); + + if( nResult == -1 && !handleSocketError()) { + return -1; + } + if( nResult == 0) { + onClose(); + } + if( nResult <= 0) { + return 0; + } + return nResult; +} + +void EClientSocket::serverVersion(int version, const char *time) { + m_serverVersion = version; + m_TwsTime = time; + + if( usingV100Plus() ? (m_serverVersion < MIN_CLIENT_VER || m_serverVersion > MAX_CLIENT_VER) : m_serverVersion < MIN_SERVER_VER_SUPPORTED ) { + getWrapper()->error( NO_VALID_ID, UNSUPPORTED_VERSION.code(), UNSUPPORTED_VERSION.msg()); + eDisconnect(); + } + + if (!m_asyncEConnect) + startApi(); +} + +void EClientSocket::redirect(const char *host, int port) { + // handle redirect + if( (m_hostNorm != this->host() || port != this->port())) { + if (!m_allowRedirect) { + getWrapper()->error(NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + + return; + } + + eDisconnect(); + eConnectImpl( clientId(), extraAuth(), 0); + } +} + +bool EClientSocket::handleSocketError() +{ + // no error + if( errno == 0) + return true; + + // Socket is already connected + if( errno == EISCONN) { + return true; + } + + if( errno == EWOULDBLOCK) + return false; + + if( errno == ECONNREFUSED) { + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + } + else { + getWrapper()->error( NO_VALID_ID, SOCKET_EXCEPTION.code(), + SOCKET_EXCEPTION.msg() + strerror(errno)); + } + // reset errno + errno = 0; + eDisconnect(); + return false; +} + + +/////////////////////////////////////////////////////////// +// callbacks from socket + +void EClientSocket::onSend() +{ + if( !handleSocketError()) + return; + + getTransport()->sendBufferedData(); +} + +void EClientSocket::onClose() +{ + if( !handleSocketError()) + return; + + eDisconnect(); + getWrapper()->connectionClosed(); +} + +void EClientSocket::onError() +{ + handleSocketError(); +} \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/EClientSocket.h b/vn.ib/ibapi/windows/client/EClientSocket.h new file mode 100644 index 00000000..7a31dfe4 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EClientSocket.h @@ -0,0 +1,70 @@ +/* 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. */ + +#pragma once +#ifndef eposixclientsocket_def +#define eposixclientsocket_def + +#include "EClient.h" +#include "EClientMsgSink.h" +#include "ESocket.h" + +class EWrapper; +class EReaderSignal; + +class TWSAPIDLLEXP EClientSocket : public EClient, public EClientMsgSink +{ +protected: + virtual void prepareBufferImpl(std::ostream&) const; + virtual void prepareBuffer(std::ostream&) const; + virtual bool closeAndSend(std::string msg, unsigned offset = 0); + +public: + + explicit EClientSocket(EWrapper *ptr, EReaderSignal *pSignal = 0); + ~EClientSocket(); + + bool eConnect( const char *host, unsigned int port, int clientId = 0, bool extraAuth = false); + // override virtual funcs from EClient + void eDisconnect(); + + bool isSocketOK() const; + int fd() const; + bool asyncEConnect() const; + void asyncEConnect(bool val); + ESocket *getTransport(); + +private: + + bool eConnectImpl(int clientId, bool extraAuth, ConnState* stateOutPt); + +private: + void encodeMsgLen(std::string& msg, unsigned offset) const; +public: + bool handleSocketError(); + int receive( char* buf, size_t sz); + +public: + // callback from socket + void onSend(); + void onError(); + +private: + + void onClose(); + +private: + + int m_fd; + bool m_allowRedirect; + const char* m_hostNorm; + bool m_asyncEConnect; + EReaderSignal *m_pSignal; + +//EClientMsgSink implementation +public: + void serverVersion(int version, const char *time); + void redirect(const char *host, int port); +}; + +#endif diff --git a/vn.ib/ibapi/windows/client/EDecoder.cpp b/vn.ib/ibapi/windows/client/EDecoder.cpp new file mode 100644 index 00000000..63964c13 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EDecoder.cpp @@ -0,0 +1,2076 @@ +/* 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. */ + +#include "StdAfx.h" +#include +#include +#include "EWrapper.h" +#include "Order.h" +#include "Contract.h" +#include "OrderState.h" +#include "Execution.h" +#include "CommissionReport.h" +#include "TwsSocketClientErrors.h" +#include "EDecoder.h" +#include "EClientMsgSink.h" +#include + +EDecoder::EDecoder(int serverVersion, EWrapper *callback, EClientMsgSink *clientMsgSink) { + m_pEWrapper = callback; + m_serverVersion = serverVersion; + m_pClientMsgSink = clientMsgSink; +} + +const char* EDecoder::processTickPriceMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + double price; + + int size; + int canAutoExecute; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + DECODE_FIELD( price); + + DECODE_FIELD( size); // ver 2 field + DECODE_FIELD( canAutoExecute); // ver 3 field + + m_pEWrapper->tickPrice( tickerId, (TickType)tickTypeInt, price, canAutoExecute); + + // process ver 2 fields + { + TickType sizeTickType = NOT_SET; + switch( (TickType)tickTypeInt) { + case BID: + sizeTickType = BID_SIZE; + break; + case ASK: + sizeTickType = ASK_SIZE; + break; + case LAST: + sizeTickType = LAST_SIZE; + break; + default: + break; + } + if( sizeTickType != NOT_SET) + m_pEWrapper->tickSize( tickerId, sizeTickType, size); + } + + return ptr; +} + +const char* EDecoder::processTickSizeMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + int size; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + DECODE_FIELD( size); + + m_pEWrapper->tickSize( tickerId, (TickType)tickTypeInt, size); + + return ptr; +} + +const char* EDecoder::processTickOptionComputationMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + double impliedVol; + double delta; + + double optPrice = DBL_MAX; + double pvDividend = DBL_MAX; + + double gamma = DBL_MAX; + double vega = DBL_MAX; + double theta = DBL_MAX; + double undPrice = DBL_MAX; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + + DECODE_FIELD( impliedVol); + DECODE_FIELD( delta); + + if( impliedVol < 0) { // -1 is the "not computed" indicator + impliedVol = DBL_MAX; + } + if( delta > 1 || delta < -1) { // -2 is the "not computed" indicator + delta = DBL_MAX; + } + + if( version >= 6 || tickTypeInt == MODEL_OPTION) { // introduced in version == 5 + + DECODE_FIELD( optPrice); + DECODE_FIELD( pvDividend); + + if( optPrice < 0) { // -1 is the "not computed" indicator + optPrice = DBL_MAX; + } + if( pvDividend < 0) { // -1 is the "not computed" indicator + pvDividend = DBL_MAX; + } + } + if( version >= 6) { + + DECODE_FIELD( gamma); + DECODE_FIELD( vega); + DECODE_FIELD( theta); + DECODE_FIELD( undPrice); + + if( gamma > 1 || gamma < -1) { // -2 is the "not yet computed" indicator + gamma = DBL_MAX; + } + if( vega > 1 || vega < -1) { // -2 is the "not yet computed" indicator + vega = DBL_MAX; + } + if( theta > 1 || theta < -1) { // -2 is the "not yet computed" indicator + theta = DBL_MAX; + } + if( undPrice < 0) { // -1 is the "not computed" indicator + undPrice = DBL_MAX; + } + } + m_pEWrapper->tickOptionComputation( tickerId, (TickType)tickTypeInt, + impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice); + + return ptr; +} + +const char* EDecoder::processTickGenericMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + double value; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + DECODE_FIELD( value); + + m_pEWrapper->tickGeneric( tickerId, (TickType)tickTypeInt, value); + + return ptr; +} + +const char* EDecoder::processTickStringMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + std::string value; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + DECODE_FIELD( value); + + m_pEWrapper->tickString( tickerId, (TickType)tickTypeInt, value); + + return ptr; +} + +const char* EDecoder::processTickEfpMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + int tickTypeInt; + double basisPoints; + std::string formattedBasisPoints; + double impliedFuturesPrice; + int holdDays; + std::string futureLastTradeDate; + double dividendImpact; + double dividendsToLastTradeDate; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + DECODE_FIELD( tickTypeInt); + DECODE_FIELD( basisPoints); + DECODE_FIELD( formattedBasisPoints); + DECODE_FIELD( impliedFuturesPrice); + DECODE_FIELD( holdDays); + DECODE_FIELD( futureLastTradeDate); + DECODE_FIELD( dividendImpact); + DECODE_FIELD( dividendsToLastTradeDate); + + m_pEWrapper->tickEFP( tickerId, (TickType)tickTypeInt, basisPoints, formattedBasisPoints, + impliedFuturesPrice, holdDays, futureLastTradeDate, dividendImpact, dividendsToLastTradeDate); + + return ptr; +} + +const char* EDecoder::processOrderStatusMsg(const char* ptr, const char* endPtr) { + int version; + int orderId; + std::string status; + double filled; + double remaining; + double avgFillPrice; + int permId; + int parentId; + double lastFillPrice; + int clientId; + std::string whyHeld; + + DECODE_FIELD( version); + DECODE_FIELD( orderId); + DECODE_FIELD( status); + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + { + DECODE_FIELD( filled); + } + else + { + int iFilled; + + DECODE_FIELD(iFilled); + + filled = iFilled; + } + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + { + DECODE_FIELD( remaining); + } + else + { + int iRemaining; + + DECODE_FIELD(iRemaining); + + remaining = iRemaining; + } + + DECODE_FIELD( avgFillPrice); + + DECODE_FIELD( permId); // ver 2 field + DECODE_FIELD( parentId); // ver 3 field + DECODE_FIELD( lastFillPrice); // ver 4 field + DECODE_FIELD( clientId); // ver 5 field + DECODE_FIELD( whyHeld); // ver 6 field + + m_pEWrapper->orderStatus( orderId, status, filled, remaining, + avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld); + + + return ptr; +} + +const char* EDecoder::processErrMsgMsg(const char* ptr, const char* endPtr) { + int version; + int id; // ver 2 field + int errorCode; // ver 2 field + std::string errorMsg; + + DECODE_FIELD( version); + DECODE_FIELD( id); + DECODE_FIELD( errorCode); + DECODE_FIELD( errorMsg); + + m_pEWrapper->error( id, errorCode, errorMsg); + + return ptr; +} + +const char* EDecoder::processOpenOrderMsg(const char* ptr, const char* endPtr) { + // read version + int version; + DECODE_FIELD( version); + + // read order id + Order order; + DECODE_FIELD( order.orderId); + + // read contract fields + Contract contract; + DECODE_FIELD( contract.conId); // ver 17 field + DECODE_FIELD( contract.symbol); + DECODE_FIELD( contract.secType); + DECODE_FIELD( contract.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.strike); + DECODE_FIELD( contract.right); + if (version >= 32) { + DECODE_FIELD( contract.multiplier); + } + DECODE_FIELD( contract.exchange); + DECODE_FIELD( contract.currency); + DECODE_FIELD( contract.localSymbol); // ver 2 field + if (version >= 32) { + DECODE_FIELD( contract.tradingClass); + } + + // read order fields + DECODE_FIELD( order.action); + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + { + DECODE_FIELD( order.totalQuantity); + } + else + { + long lTotalQuantity; + + DECODE_FIELD(lTotalQuantity); + + order.totalQuantity = lTotalQuantity; + } + + DECODE_FIELD( order.orderType); + if (version < 29) { + DECODE_FIELD( order.lmtPrice); + } + else { + DECODE_FIELD_MAX( order.lmtPrice); + } + if (version < 30) { + DECODE_FIELD( order.auxPrice); + } + else { + DECODE_FIELD_MAX( order.auxPrice); + } + DECODE_FIELD( order.tif); + DECODE_FIELD( order.ocaGroup); + DECODE_FIELD( order.account); + DECODE_FIELD( order.openClose); + + int orderOriginInt; + DECODE_FIELD( orderOriginInt); + order.origin = (Origin)orderOriginInt; + + DECODE_FIELD( order.orderRef); + DECODE_FIELD( order.clientId); // ver 3 field + DECODE_FIELD( order.permId); // ver 4 field + + //if( version < 18) { + // // will never happen + // /* order.ignoreRth = */ readBoolFromInt(); + //} + + DECODE_FIELD( order.outsideRth); // ver 18 field + DECODE_FIELD( order.hidden); // ver 4 field + DECODE_FIELD( order.discretionaryAmt); // ver 4 field + DECODE_FIELD( order.goodAfterTime); // ver 5 field + + { + std::string sharesAllocation; + DECODE_FIELD( sharesAllocation); // deprecated ver 6 field + } + + DECODE_FIELD( order.faGroup); // ver 7 field + DECODE_FIELD( order.faMethod); // ver 7 field + DECODE_FIELD( order.faPercentage); // ver 7 field + DECODE_FIELD( order.faProfile); // ver 7 field + + if( m_serverVersion >= MIN_SERVER_VER_MODELS_SUPPORT ) { + DECODE_FIELD( order.modelCode); + } + + DECODE_FIELD( order.goodTillDate); // ver 8 field + + DECODE_FIELD( order.rule80A); // ver 9 field + DECODE_FIELD_MAX( order.percentOffset); // ver 9 field + DECODE_FIELD( order.settlingFirm); // ver 9 field + DECODE_FIELD( order.shortSaleSlot); // ver 9 field + DECODE_FIELD( order.designatedLocation); // ver 9 field + if( m_serverVersion == MIN_SERVER_VER_SSHORTX_OLD){ + int exemptCode; + DECODE_FIELD( exemptCode); + } + else if( version >= 23){ + DECODE_FIELD( order.exemptCode); + } + DECODE_FIELD( order.auctionStrategy); // ver 9 field + DECODE_FIELD_MAX( order.startingPrice); // ver 9 field + DECODE_FIELD_MAX( order.stockRefPrice); // ver 9 field + DECODE_FIELD_MAX( order.delta); // ver 9 field + DECODE_FIELD_MAX( order.stockRangeLower); // ver 9 field + DECODE_FIELD_MAX( order.stockRangeUpper); // ver 9 field + DECODE_FIELD( order.displaySize); // ver 9 field + + //if( version < 18) { + // // will never happen + // /* order.rthOnly = */ readBoolFromInt(); + //} + + DECODE_FIELD( order.blockOrder); // ver 9 field + DECODE_FIELD( order.sweepToFill); // ver 9 field + DECODE_FIELD( order.allOrNone); // ver 9 field + DECODE_FIELD_MAX( order.minQty); // ver 9 field + DECODE_FIELD( order.ocaType); // ver 9 field + DECODE_FIELD( order.eTradeOnly); // ver 9 field + DECODE_FIELD( order.firmQuoteOnly); // ver 9 field + DECODE_FIELD_MAX( order.nbboPriceCap); // ver 9 field + + DECODE_FIELD( order.parentId); // ver 10 field + DECODE_FIELD( order.triggerMethod); // ver 10 field + + DECODE_FIELD_MAX( order.volatility); // ver 11 field + DECODE_FIELD( order.volatilityType); // ver 11 field + DECODE_FIELD( order.deltaNeutralOrderType); // ver 11 field (had a hack for ver 11) + DECODE_FIELD_MAX( order.deltaNeutralAuxPrice); // ver 12 field + + if (version >= 27 && !order.deltaNeutralOrderType.empty()) { + DECODE_FIELD( order.deltaNeutralConId); + DECODE_FIELD( order.deltaNeutralSettlingFirm); + DECODE_FIELD( order.deltaNeutralClearingAccount); + DECODE_FIELD( order.deltaNeutralClearingIntent); + } + + if (version >= 31 && !order.deltaNeutralOrderType.empty()) { + DECODE_FIELD( order.deltaNeutralOpenClose); + DECODE_FIELD( order.deltaNeutralShortSale); + DECODE_FIELD( order.deltaNeutralShortSaleSlot); + DECODE_FIELD( order.deltaNeutralDesignatedLocation); + } + + DECODE_FIELD( order.continuousUpdate); // ver 11 field + + // will never happen + //if( m_serverVersion == 26) { + // order.stockRangeLower = readDouble(); + // order.stockRangeUpper = readDouble(); + //} + + DECODE_FIELD( order.referencePriceType); // ver 11 field + + DECODE_FIELD_MAX( order.trailStopPrice); // ver 13 field + + if (version >= 30) { + DECODE_FIELD_MAX( order.trailingPercent); + } + + DECODE_FIELD_MAX( order.basisPoints); // ver 14 field + DECODE_FIELD_MAX( order.basisPointsType); // ver 14 field + DECODE_FIELD( contract.comboLegsDescrip); // ver 14 field + + if (version >= 29) { + int comboLegsCount = 0; + DECODE_FIELD( comboLegsCount); + + if (comboLegsCount > 0) { + Contract::ComboLegListSPtr comboLegs( new Contract::ComboLegList); + comboLegs->reserve( comboLegsCount); + for (int i = 0; i < comboLegsCount; ++i) { + ComboLegSPtr comboLeg( new ComboLeg()); + DECODE_FIELD( comboLeg->conId); + DECODE_FIELD( comboLeg->ratio); + DECODE_FIELD( comboLeg->action); + DECODE_FIELD( comboLeg->exchange); + DECODE_FIELD( comboLeg->openClose); + DECODE_FIELD( comboLeg->shortSaleSlot); + DECODE_FIELD( comboLeg->designatedLocation); + DECODE_FIELD( comboLeg->exemptCode); + + comboLegs->push_back( comboLeg); + } + contract.comboLegs = comboLegs; + } + + int orderComboLegsCount = 0; + DECODE_FIELD( orderComboLegsCount); + if (orderComboLegsCount > 0) { + Order::OrderComboLegListSPtr orderComboLegs( new Order::OrderComboLegList); + orderComboLegs->reserve( orderComboLegsCount); + for (int i = 0; i < orderComboLegsCount; ++i) { + OrderComboLegSPtr orderComboLeg( new OrderComboLeg()); + DECODE_FIELD_MAX( orderComboLeg->price); + + orderComboLegs->push_back( orderComboLeg); + } + order.orderComboLegs = orderComboLegs; + } + } + + if (version >= 26) { + int smartComboRoutingParamsCount = 0; + DECODE_FIELD( smartComboRoutingParamsCount); + if( smartComboRoutingParamsCount > 0) { + TagValueListSPtr smartComboRoutingParams( new TagValueList); + smartComboRoutingParams->reserve( smartComboRoutingParamsCount); + for( int i = 0; i < smartComboRoutingParamsCount; ++i) { + TagValueSPtr tagValue( new TagValue()); + DECODE_FIELD( tagValue->tag); + DECODE_FIELD( tagValue->value); + smartComboRoutingParams->push_back( tagValue); + } + order.smartComboRoutingParams = smartComboRoutingParams; + } + } + + if( version >= 20) { + DECODE_FIELD_MAX( order.scaleInitLevelSize); + DECODE_FIELD_MAX( order.scaleSubsLevelSize); + } + else { + // ver 15 fields + int notSuppScaleNumComponents = 0; + DECODE_FIELD_MAX( notSuppScaleNumComponents); + DECODE_FIELD_MAX( order.scaleInitLevelSize); // scaleComponectSize + } + DECODE_FIELD_MAX( order.scalePriceIncrement); // ver 15 field + + if (version >= 28 && order.scalePriceIncrement > 0.0 && order.scalePriceIncrement != UNSET_DOUBLE) { + DECODE_FIELD_MAX( order.scalePriceAdjustValue); + DECODE_FIELD_MAX( order.scalePriceAdjustInterval); + DECODE_FIELD_MAX( order.scaleProfitOffset); + DECODE_FIELD( order.scaleAutoReset); + DECODE_FIELD_MAX( order.scaleInitPosition); + DECODE_FIELD_MAX( order.scaleInitFillQty); + DECODE_FIELD( order.scaleRandomPercent); + } + + if( version >= 24) { + DECODE_FIELD( order.hedgeType); + if( !order.hedgeType.empty()) { + DECODE_FIELD( order.hedgeParam); + } + } + + if( version >= 25) { + DECODE_FIELD( order.optOutSmartRouting); + } + + DECODE_FIELD( order.clearingAccount); // ver 19 field + DECODE_FIELD( order.clearingIntent); // ver 19 field + + if( version >= 22) { + DECODE_FIELD( order.notHeld); + } + + UnderComp underComp; + if( version >= 20) { + bool underCompPresent = false; + DECODE_FIELD(underCompPresent); + if( underCompPresent){ + DECODE_FIELD(underComp.conId); + DECODE_FIELD(underComp.delta); + DECODE_FIELD(underComp.price); + contract.underComp = &underComp; + } + } + + + if( version >= 21) { + DECODE_FIELD( order.algoStrategy); + if( !order.algoStrategy.empty()) { + int algoParamsCount = 0; + DECODE_FIELD( algoParamsCount); + if( algoParamsCount > 0) { + TagValueListSPtr algoParams( new TagValueList); + algoParams->reserve( algoParamsCount); + for( int i = 0; i < algoParamsCount; ++i) { + TagValueSPtr tagValue( new TagValue()); + DECODE_FIELD( tagValue->tag); + DECODE_FIELD( tagValue->value); + algoParams->push_back( tagValue); + } + order.algoParams = algoParams; + } + } + } + + if (version >= 33) { + DECODE_FIELD(order.solicited); + } + + OrderState orderState; + + DECODE_FIELD( order.whatIf); // ver 16 field + + DECODE_FIELD( orderState.status); // ver 16 field + DECODE_FIELD( orderState.initMargin); // ver 16 field + DECODE_FIELD( orderState.maintMargin); // ver 16 field + DECODE_FIELD( orderState.equityWithLoan); // ver 16 field + DECODE_FIELD_MAX( orderState.commission); // ver 16 field + DECODE_FIELD_MAX( orderState.minCommission); // ver 16 field + DECODE_FIELD_MAX( orderState.maxCommission); // ver 16 field + DECODE_FIELD( orderState.commissionCurrency); // ver 16 field + DECODE_FIELD( orderState.warningText); // ver 16 field + + if (version >= 34) { + DECODE_FIELD(order.randomizeSize); + DECODE_FIELD(order.randomizePrice); + } + + if (m_serverVersion >= MIN_SERVER_VER_PEGGED_TO_BENCHMARK) { + if (order.orderType == "PEG BENCH") { + DECODE_FIELD(order.referenceContractId); + DECODE_FIELD(order.isPeggedChangeAmountDecrease); + DECODE_FIELD(order.peggedChangeAmount); + DECODE_FIELD(order.referenceChangeAmount); + DECODE_FIELD(order.referenceExchangeId); + } + + int conditionsSize; + + DECODE_FIELD(conditionsSize); + + if (conditionsSize > 0) { + for (; conditionsSize; conditionsSize--) { + int conditionType; + + DECODE_FIELD(conditionType); + + ibapi::shared_ptr item = ibapi::shared_ptr(OrderCondition::create((OrderCondition::OrderConditionType)conditionType)); + + if (!(ptr = item->readExternal(ptr, endPtr))) + return 0; + + order.conditions.push_back(item); + } + + DECODE_FIELD(order.conditionsIgnoreRth); + DECODE_FIELD(order.conditionsCancelOrder); + } + + DECODE_FIELD(order.adjustedOrderType); + DECODE_FIELD(order.triggerPrice); + DECODE_FIELD(order.trailStopPrice); + DECODE_FIELD(order.lmtPriceOffset); + DECODE_FIELD(order.adjustedStopPrice); + DECODE_FIELD(order.adjustedStopLimitPrice); + DECODE_FIELD(order.adjustedTrailingAmount); + DECODE_FIELD(order.adjustableTrailingUnit); + } + + if (m_serverVersion >= MIN_SERVER_VER_SOFT_DOLLAR_TIER) { + std::string name, value, displayName; + + DECODE_FIELD(name); + DECODE_FIELD(value); + DECODE_FIELD(displayName); + + order.softDollarTier = SoftDollarTier(name, value, displayName); + } + + m_pEWrapper->openOrder( (OrderId)order.orderId, contract, order, orderState); + + return ptr; +} + +const char* EDecoder::processAcctValueMsg(const char* ptr, const char* endPtr) { + int version; + std::string key; + std::string val; + std::string cur; + std::string accountName; + + DECODE_FIELD( version); + DECODE_FIELD( key); + DECODE_FIELD( val); + DECODE_FIELD( cur); + DECODE_FIELD( accountName); // ver 2 field + + m_pEWrapper->updateAccountValue( key, val, cur, accountName); + return ptr; +} + +const char* EDecoder::processPortfolioValueMsg(const char* ptr, const char* endPtr) { + // decode version + int version; + DECODE_FIELD( version); + + // read contract fields + Contract contract; + DECODE_FIELD( contract.conId); // ver 6 field + DECODE_FIELD( contract.symbol); + DECODE_FIELD( contract.secType); + DECODE_FIELD( contract.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.strike); + DECODE_FIELD( contract.right); + + if( version >= 7) { + DECODE_FIELD( contract.multiplier); + DECODE_FIELD( contract.primaryExchange); + } + + DECODE_FIELD( contract.currency); + DECODE_FIELD( contract.localSymbol); // ver 2 field + if (version >= 8) { + DECODE_FIELD( contract.tradingClass); + } + + double position; + double marketPrice; + double marketValue; + double averageCost; + double unrealizedPNL; + double realizedPNL; + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + { + DECODE_FIELD( position); + } + else + { + int iPosition; + + DECODE_FIELD(iPosition); + + position = iPosition; + } + + DECODE_FIELD( marketPrice); + DECODE_FIELD( marketValue); + DECODE_FIELD( averageCost); // ver 3 field + DECODE_FIELD( unrealizedPNL); // ver 3 field + DECODE_FIELD( realizedPNL); // ver 3 field + + std::string accountName; + DECODE_FIELD( accountName); // ver 4 field + + if( version == 6 && m_serverVersion == 39) { + DECODE_FIELD( contract.primaryExchange); + } + + m_pEWrapper->updatePortfolio( contract, + position, marketPrice, marketValue, averageCost, + unrealizedPNL, realizedPNL, accountName); + + return ptr; +} + +const char* EDecoder::processAcctUpdateTimeMsg(const char* ptr, const char* endPtr) { + int version; + std::string accountTime; + + DECODE_FIELD( version); + DECODE_FIELD( accountTime); + + m_pEWrapper->updateAccountTime( accountTime); + + return ptr; +} + +const char* EDecoder::processNextValidIdMsg(const char* ptr, const char* endPtr) { + int version; + int orderId; + + DECODE_FIELD( version); + DECODE_FIELD( orderId); + + m_pEWrapper->nextValidId(orderId); + + return ptr; +} + +const char* EDecoder::processContractDataMsg(const char* ptr, const char* endPtr) { + int version; + DECODE_FIELD( version); + + int reqId = -1; + if( version >= 3) { + DECODE_FIELD( reqId); + } + + ContractDetails contract; + DECODE_FIELD( contract.summary.symbol); + DECODE_FIELD( contract.summary.secType); + DECODE_FIELD( contract.summary.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.summary.strike); + DECODE_FIELD( contract.summary.right); + DECODE_FIELD( contract.summary.exchange); + DECODE_FIELD( contract.summary.currency); + DECODE_FIELD( contract.summary.localSymbol); + DECODE_FIELD( contract.marketName); + DECODE_FIELD( contract.summary.tradingClass); + DECODE_FIELD( contract.summary.conId); + DECODE_FIELD( contract.minTick); + DECODE_FIELD( contract.summary.multiplier); + DECODE_FIELD( contract.orderTypes); + DECODE_FIELD( contract.validExchanges); + DECODE_FIELD( contract.priceMagnifier); // ver 2 field + if( version >= 4) { + DECODE_FIELD( contract.underConId); + } + if( version >= 5) { + DECODE_FIELD( contract.longName); + DECODE_FIELD( contract.summary.primaryExchange); + } + if( version >= 6) { + DECODE_FIELD( contract.contractMonth); + DECODE_FIELD( contract.industry); + DECODE_FIELD( contract.category); + DECODE_FIELD( contract.subcategory); + DECODE_FIELD( contract.timeZoneId); + DECODE_FIELD( contract.tradingHours); + DECODE_FIELD( contract.liquidHours); + } + if( version >= 8) { + DECODE_FIELD( contract.evRule); + DECODE_FIELD( contract.evMultiplier); + } + if( version >= 7) { + int secIdListCount = 0; + DECODE_FIELD( secIdListCount); + if( secIdListCount > 0) { + TagValueListSPtr secIdList( new TagValueList); + secIdList->reserve( secIdListCount); + for( int i = 0; i < secIdListCount; ++i) { + TagValueSPtr tagValue( new TagValue()); + DECODE_FIELD( tagValue->tag); + DECODE_FIELD( tagValue->value); + secIdList->push_back( tagValue); + } + contract.secIdList = secIdList; + } + } + + m_pEWrapper->contractDetails( reqId, contract); + + return ptr; +} + +const char* EDecoder::processBondContractDataMsg(const char* ptr, const char* endPtr) { + int version; + DECODE_FIELD( version); + + int reqId = -1; + if( version >= 3) { + DECODE_FIELD( reqId); + } + + ContractDetails contract; + DECODE_FIELD( contract.summary.symbol); + DECODE_FIELD( contract.summary.secType); + DECODE_FIELD( contract.cusip); + DECODE_FIELD( contract.coupon); + DECODE_FIELD( contract.maturity); + DECODE_FIELD( contract.issueDate); + DECODE_FIELD( contract.ratings); + DECODE_FIELD( contract.bondType); + DECODE_FIELD( contract.couponType); + DECODE_FIELD( contract.convertible); + DECODE_FIELD( contract.callable); + DECODE_FIELD( contract.putable); + DECODE_FIELD( contract.descAppend); + DECODE_FIELD( contract.summary.exchange); + DECODE_FIELD( contract.summary.currency); + DECODE_FIELD( contract.marketName); + DECODE_FIELD( contract.summary.tradingClass); + DECODE_FIELD( contract.summary.conId); + DECODE_FIELD( contract.minTick); + DECODE_FIELD( contract.orderTypes); + DECODE_FIELD( contract.validExchanges); + DECODE_FIELD( contract.nextOptionDate); // ver 2 field + DECODE_FIELD( contract.nextOptionType); // ver 2 field + DECODE_FIELD( contract.nextOptionPartial); // ver 2 field + DECODE_FIELD( contract.notes); // ver 2 field + if( version >= 4) { + DECODE_FIELD( contract.longName); + } + if( version >= 6) { + DECODE_FIELD( contract.evRule); + DECODE_FIELD( contract.evMultiplier); + } + if( version >= 5) { + int secIdListCount = 0; + DECODE_FIELD( secIdListCount); + if( secIdListCount > 0) { + TagValueListSPtr secIdList( new TagValueList); + secIdList->reserve( secIdListCount); + for( int i = 0; i < secIdListCount; ++i) { + TagValueSPtr tagValue( new TagValue()); + DECODE_FIELD( tagValue->tag); + DECODE_FIELD( tagValue->value); + secIdList->push_back( tagValue); + } + contract.secIdList = secIdList; + } + } + + m_pEWrapper->bondContractDetails( reqId, contract); + + return ptr; +} + +const char* EDecoder::processExecutionDataMsg(const char* ptr, const char* endPtr) { + int version; + DECODE_FIELD( version); + + int reqId = -1; + if( version >= 7) { + DECODE_FIELD(reqId); + } + + int orderId; + DECODE_FIELD( orderId); + + // decode contract fields + Contract contract; + DECODE_FIELD( contract.conId); // ver 5 field + DECODE_FIELD( contract.symbol); + DECODE_FIELD( contract.secType); + DECODE_FIELD( contract.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.strike); + DECODE_FIELD( contract.right); + if( version >= 9) { + DECODE_FIELD( contract.multiplier); + } + DECODE_FIELD( contract.exchange); + DECODE_FIELD( contract.currency); + DECODE_FIELD( contract.localSymbol); + if (version >= 10) { + DECODE_FIELD( contract.tradingClass); + } + + // decode execution fields + Execution exec; + exec.orderId = orderId; + DECODE_FIELD( exec.execId); + DECODE_FIELD( exec.time); + DECODE_FIELD( exec.acctNumber); + DECODE_FIELD( exec.exchange); + DECODE_FIELD( exec.side); + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) { + DECODE_FIELD( exec.shares) + } + else { + int iShares; + + DECODE_FIELD(iShares); + + exec.shares = iShares; + } + + DECODE_FIELD( exec.price); + DECODE_FIELD( exec.permId); // ver 2 field + DECODE_FIELD( exec.clientId); // ver 3 field + DECODE_FIELD( exec.liquidation); // ver 4 field + + if( version >= 6) { + DECODE_FIELD( exec.cumQty); + DECODE_FIELD( exec.avgPrice); + } + + if( version >= 8) { + DECODE_FIELD( exec.orderRef); + } + + if( version >= 9) { + DECODE_FIELD( exec.evRule); + DECODE_FIELD( exec.evMultiplier); + } + if( m_serverVersion >= MIN_SERVER_VER_MODELS_SUPPORT) { + DECODE_FIELD( exec.modelCode); + } + + m_pEWrapper->execDetails( reqId, contract, exec); + + return ptr; +} + +const char* EDecoder::processMarketDepthMsg(const char* ptr, const char* endPtr) { + int version; + int id; + int position; + int operation; + int side; + double price; + int size; + + DECODE_FIELD( version); + DECODE_FIELD( id); + DECODE_FIELD( position); + DECODE_FIELD( operation); + DECODE_FIELD( side); + DECODE_FIELD( price); + DECODE_FIELD( size); + + m_pEWrapper->updateMktDepth( id, position, operation, side, price, size); + + return ptr; +} + +const char* EDecoder::processMarketDepthL2Msg(const char* ptr, const char* endPtr) { + int version; + int id; + int position; + std::string marketMaker; + int operation; + int side; + double price; + int size; + + DECODE_FIELD( version); + DECODE_FIELD( id); + DECODE_FIELD( position); + DECODE_FIELD( marketMaker); + DECODE_FIELD( operation); + DECODE_FIELD( side); + DECODE_FIELD( price); + DECODE_FIELD( size); + + m_pEWrapper->updateMktDepthL2( id, position, marketMaker, operation, side, + price, size); + + return ptr; +} + +const char* EDecoder::processNewsBulletinsMsg(const char* ptr, const char* endPtr) { + int version; + int msgId; + int msgType; + std::string newsMessage; + std::string originatingExch; + + DECODE_FIELD( version); + DECODE_FIELD( msgId); + DECODE_FIELD( msgType); + DECODE_FIELD( newsMessage); + DECODE_FIELD( originatingExch); + + m_pEWrapper->updateNewsBulletin( msgId, msgType, newsMessage, originatingExch); + + return ptr; +} + +const char* EDecoder::processManagedAcctsMsg(const char* ptr, const char* endPtr) { + int version; + std::string accountsList; + + DECODE_FIELD( version); + DECODE_FIELD( accountsList); + + m_pEWrapper->managedAccounts( accountsList); + + return ptr; +} + +const char* EDecoder::processReceiveFaMsg(const char* ptr, const char* endPtr) { + int version; + int faDataTypeInt; + std::string cxml; + + DECODE_FIELD( version); + DECODE_FIELD( faDataTypeInt); + DECODE_FIELD( cxml); + + m_pEWrapper->receiveFA( (faDataType)faDataTypeInt, cxml); + + return ptr; +} + +const char* EDecoder::processHistoricalDataMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string startDateStr; + std::string endDateStr; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( startDateStr); // ver 2 field + DECODE_FIELD( endDateStr); // ver 2 field + + int itemCount; + DECODE_FIELD( itemCount); + + typedef std::vector BarDataList; + BarDataList bars; + + bars.reserve( itemCount); + + for( int ctr = 0; ctr < itemCount; ++ctr) { + + BarData bar; + DECODE_FIELD( bar.date); + DECODE_FIELD( bar.open); + DECODE_FIELD( bar.high); + DECODE_FIELD( bar.low); + DECODE_FIELD( bar.close); + DECODE_FIELD( bar.volume); + DECODE_FIELD( bar.average); + DECODE_FIELD( bar.hasGaps); + DECODE_FIELD( bar.barCount); // ver 3 field + + bars.push_back(bar); + } + + assert( (int)bars.size() == itemCount); + + for( int ctr = 0; ctr < itemCount; ++ctr) { + + const BarData& bar = bars[ctr]; + m_pEWrapper->historicalData( reqId, bar.date, bar.open, bar.high, bar.low, + bar.close, bar.volume, bar.barCount, bar.average, + bar.hasGaps == "true"); + } + + // send end of dataset marker + std::string finishedStr = std::string("finished-") + startDateStr + "-" + endDateStr; + m_pEWrapper->historicalData( reqId, finishedStr, -1, -1, -1, -1, -1, -1, -1, 0); + + return ptr; +} + +const char* EDecoder::processScannerDataMsg(const char* ptr, const char* endPtr) { + int version; + int tickerId; + + DECODE_FIELD( version); + DECODE_FIELD( tickerId); + + int numberOfElements; + DECODE_FIELD( numberOfElements); + + typedef std::vector ScanDataList; + ScanDataList scannerDataList; + + scannerDataList.reserve( numberOfElements); + + for( int ctr=0; ctr < numberOfElements; ++ctr) { + + ScanData data; + + DECODE_FIELD( data.rank); + DECODE_FIELD( data.contract.summary.conId); // ver 3 field + DECODE_FIELD( data.contract.summary.symbol); + DECODE_FIELD( data.contract.summary.secType); + DECODE_FIELD( data.contract.summary.lastTradeDateOrContractMonth); + DECODE_FIELD( data.contract.summary.strike); + DECODE_FIELD( data.contract.summary.right); + DECODE_FIELD( data.contract.summary.exchange); + DECODE_FIELD( data.contract.summary.currency); + DECODE_FIELD( data.contract.summary.localSymbol); + DECODE_FIELD( data.contract.marketName); + DECODE_FIELD( data.contract.summary.tradingClass); + DECODE_FIELD( data.distance); + DECODE_FIELD( data.benchmark); + DECODE_FIELD( data.projection); + DECODE_FIELD( data.legsStr); + + scannerDataList.push_back( data); + } + + assert( (int)scannerDataList.size() == numberOfElements); + + for( int ctr=0; ctr < numberOfElements; ++ctr) { + + const ScanData& data = scannerDataList[ctr]; + m_pEWrapper->scannerData( tickerId, data.rank, data.contract, + data.distance, data.benchmark, data.projection, data.legsStr); + } + + m_pEWrapper->scannerDataEnd( tickerId); + + return ptr; +} + +const char* EDecoder::processScannerParametersMsg(const char* ptr, const char* endPtr) { + int version; + std::string xml; + + DECODE_FIELD( version); + DECODE_FIELD( xml); + + m_pEWrapper->scannerParameters( xml); + + return ptr; +} + +const char* EDecoder::processCurrentTimeMsg(const char* ptr, const char* endPtr) { + int version; + int time; + + DECODE_FIELD(version); + DECODE_FIELD(time); + + m_pEWrapper->currentTime( time); + + return ptr; +} + +const char* EDecoder::processRealTimeBarsMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + int time; + double open; + double high; + double low; + double close; + int volume; + double average; + int count; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( time); + DECODE_FIELD( open); + DECODE_FIELD( high); + DECODE_FIELD( low); + DECODE_FIELD( close); + DECODE_FIELD( volume); + DECODE_FIELD( average); + DECODE_FIELD( count); + + m_pEWrapper->realtimeBar( reqId, time, open, high, low, close, + volume, average, count); + + return ptr; +} + +const char* EDecoder::processFundamentalDataMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string data; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( data); + + m_pEWrapper->fundamentalData( reqId, data); + + return ptr; +} + +const char* EDecoder::processContractDataEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->contractDetailsEnd( reqId); + + return ptr; +} + +const char* EDecoder::processOpenOrderEndMsg(const char* ptr, const char* endPtr) { + int version; + + DECODE_FIELD( version); + + m_pEWrapper->openOrderEnd(); + + return ptr; +} + +const char* EDecoder::processAcctDownloadEndMsg(const char* ptr, const char* endPtr) { + int version; + std::string account; + + DECODE_FIELD( version); + DECODE_FIELD( account); + + m_pEWrapper->accountDownloadEnd( account); + + return ptr; +} + +const char* EDecoder::processExecutionDataEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->execDetailsEnd( reqId); + + return ptr; +} + +const char* EDecoder::processDeltaNeutralValidationMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + UnderComp underComp; + + DECODE_FIELD( underComp.conId); + DECODE_FIELD( underComp.delta); + DECODE_FIELD( underComp.price); + + m_pEWrapper->deltaNeutralValidation( reqId, underComp); + + return ptr; +} + +const char* EDecoder::processTickSnapshotEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->tickSnapshotEnd( reqId); + + return ptr; +} + +const char* EDecoder::processMarketDataTypeMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + int marketDataType; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( marketDataType); + + m_pEWrapper->marketDataType( reqId, marketDataType); + + return ptr; +} + +const char* EDecoder::processCommissionReportMsg(const char* ptr, const char* endPtr) { + int version; + DECODE_FIELD( version); + + CommissionReport commissionReport; + DECODE_FIELD( commissionReport.execId); + DECODE_FIELD( commissionReport.commission); + DECODE_FIELD( commissionReport.currency); + DECODE_FIELD( commissionReport.realizedPNL); + DECODE_FIELD( commissionReport.yield); + DECODE_FIELD( commissionReport.yieldRedemptionDate); + + m_pEWrapper->commissionReport( commissionReport); + + return ptr; +} + +const char* EDecoder::processPositionDataMsg(const char* ptr, const char* endPtr) { + int version; + std::string account; + double position; + double avgCost = 0; + + DECODE_FIELD( version); + DECODE_FIELD( account); + + // decode contract fields + Contract contract; + DECODE_FIELD( contract.conId); + DECODE_FIELD( contract.symbol); + DECODE_FIELD( contract.secType); + DECODE_FIELD( contract.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.strike); + DECODE_FIELD( contract.right); + DECODE_FIELD( contract.multiplier); + DECODE_FIELD( contract.exchange); + DECODE_FIELD( contract.currency); + DECODE_FIELD( contract.localSymbol); + if (version >= 2) { + DECODE_FIELD( contract.tradingClass); + } + + if (m_serverVersion >= MIN_SERVER_VER_FRACTIONAL_POSITIONS) + { + DECODE_FIELD( position); + } + else + { + int iPosition; + + DECODE_FIELD(iPosition); + + position = iPosition; + } + + if (version >= 3) { + DECODE_FIELD( avgCost); + } + + m_pEWrapper->position( account, contract, position, avgCost); + + return ptr; +} + +const char* EDecoder::processPositionEndMsg(const char* ptr, const char* endPtr) { + int version; + + DECODE_FIELD( version); + + m_pEWrapper->positionEnd(); + + return ptr; +} + +const char* EDecoder::processAccountSummaryMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string account; + std::string tag; + std::string value; + std::string curency; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( account); + DECODE_FIELD( tag); + DECODE_FIELD( value); + DECODE_FIELD( curency); + + m_pEWrapper->accountSummary( reqId, account, tag, value, curency); + + return ptr; +} + +const char* EDecoder::processAccountSummaryEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->accountSummaryEnd( reqId); + + return ptr; +} + +const char* EDecoder::processVerifyMessageApiMsg(const char* ptr, const char* endPtr) { + int version; + std::string apiData; + + DECODE_FIELD( version); + DECODE_FIELD( apiData); + + m_pEWrapper->verifyMessageAPI( apiData); + + return ptr; +} + +const char* EDecoder::processVerifyCompletedMsg(const char* ptr, const char* endPtr) { + int version; + std::string isSuccessful; + std::string errorText; + + DECODE_FIELD( version); + DECODE_FIELD( isSuccessful); + DECODE_FIELD( errorText); + + bool bRes = isSuccessful == "true"; + + m_pEWrapper->verifyCompleted( bRes, errorText); + + return ptr; +} + +const char* EDecoder::processDisplayGroupListMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string groups; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( groups); + + m_pEWrapper->displayGroupList( reqId, groups); + + return ptr; +} + +const char* EDecoder::processDisplayGroupUpdatedMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string contractInfo; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( contractInfo); + + m_pEWrapper->displayGroupUpdated( reqId, contractInfo); + + return ptr; +} + +const char* EDecoder::processVerifyAndAuthMessageApiMsg(const char* ptr, const char* endPtr) { + int version; + std::string apiData; + std::string xyzChallenge; + + DECODE_FIELD( version); + DECODE_FIELD( apiData); + DECODE_FIELD( xyzChallenge); + + m_pEWrapper->verifyAndAuthMessageAPI( apiData, xyzChallenge); + + return ptr; +} + +const char* EDecoder::processVerifyAndAuthCompletedMsg(const char* ptr, const char* endPtr) { + int version; + std::string isSuccessful; + std::string errorText; + + DECODE_FIELD( version); + DECODE_FIELD( isSuccessful); + DECODE_FIELD( errorText); + + bool bRes = isSuccessful == "true"; + + m_pEWrapper->verifyAndAuthCompleted( bRes, errorText); + + return ptr; +} + +const char* EDecoder::processPositionMultiMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string account; + std::string modelCode; + double position; + double avgCost = 0; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( account); + + // decode contract fields + Contract contract; + DECODE_FIELD( contract.conId); + DECODE_FIELD( contract.symbol); + DECODE_FIELD( contract.secType); + DECODE_FIELD( contract.lastTradeDateOrContractMonth); + DECODE_FIELD( contract.strike); + DECODE_FIELD( contract.right); + DECODE_FIELD( contract.multiplier); + DECODE_FIELD( contract.exchange); + DECODE_FIELD( contract.currency); + DECODE_FIELD( contract.localSymbol); + DECODE_FIELD( contract.tradingClass); + DECODE_FIELD( position); + DECODE_FIELD( avgCost); + DECODE_FIELD( modelCode); + + m_pEWrapper->positionMulti( reqId, account, modelCode, contract, position, avgCost); + + return ptr; +} + +const char* EDecoder::processPositionMultiEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->positionMultiEnd( reqId); + + return ptr; +} + +const char* EDecoder::processAccountUpdateMultiMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + std::string account; + std::string modelCode; + std::string key; + std::string value; + std::string currency; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + DECODE_FIELD( account); + DECODE_FIELD( modelCode); + DECODE_FIELD( key); + DECODE_FIELD( value); + DECODE_FIELD( currency); + + m_pEWrapper->accountUpdateMulti( reqId, account, modelCode, key, value, currency); + + return ptr; +} + +const char* EDecoder::processAccountUpdateMultiEndMsg(const char* ptr, const char* endPtr) { + int version; + int reqId; + + DECODE_FIELD( version); + DECODE_FIELD( reqId); + + m_pEWrapper->accountUpdateMultiEnd( reqId); + + return ptr; +} + +const char* EDecoder::processSecurityDefinitionOptionalParameterMsg(const char* ptr, const char* endPtr) { + int reqId; + std::string exchange; + int underlyingConId; + std::string tradingClass; + std::string multiplier; + int expirationsSize, strikesSize; + std::set expirations; + std::set strikes; + + DECODE_FIELD(reqId); + DECODE_FIELD(exchange); + DECODE_FIELD(underlyingConId); + DECODE_FIELD(tradingClass); + DECODE_FIELD(multiplier); + DECODE_FIELD(expirationsSize); + + for (int i = 0; i < expirationsSize; i++) { + std::string expiration; + + DECODE_FIELD(expiration); + + expirations.insert(expiration); + } + + DECODE_FIELD(strikesSize); + + for (int i = 0; i < strikesSize; i++) { + double strike; + + DECODE_FIELD(strike); + + strikes.insert(strike); + } + + m_pEWrapper->securityDefinitionOptionalParameter(reqId, exchange, underlyingConId, tradingClass, multiplier, expirations, strikes); + + return ptr; +} + +const char* EDecoder::processSecurityDefinitionOptionalParameterEndMsg(const char* ptr, const char* endPtr) { + int reqId; + + DECODE_FIELD(reqId); + + m_pEWrapper->securityDefinitionOptionalParameterEnd(reqId); + + return ptr; +} + +const char* EDecoder::processSoftDollarTiersMsg(const char* ptr, const char* endPtr) +{ + int reqId; + int nTiers; + + DECODE_FIELD(reqId); + DECODE_FIELD(nTiers); + + std::vector tiers(nTiers); + + for (int i = 0; i < nTiers; i++) { + std::string name, value, dislplayName; + + DECODE_FIELD(name); + DECODE_FIELD(value); + DECODE_FIELD(dislplayName); + + tiers[i] = SoftDollarTier(name, value, value); + } + + m_pEWrapper->softDollarTiers(reqId, tiers); + + return ptr; +} + + +int EDecoder::processConnectAck(const char*& beginPtr, const char* endPtr) +{ + // process a connect Ack message from the buffer; + // return number of bytes consumed + assert( beginPtr && beginPtr < endPtr); + + try { + + const char* ptr = beginPtr; + + // check server version + DECODE_FIELD( m_serverVersion); + + // handle redirects + if( m_serverVersion < 0) { + m_serverVersion = 0; + + std::string hostport, host; + int port = -1; + + DECODE_FIELD( hostport); + + std::string::size_type sep = hostport.find( ':'); + if( sep != std::string::npos) { + host = hostport.substr(0, sep); + port = atoi( hostport.c_str() + ++sep); + } + else { + host = hostport; + } + + if (m_pClientMsgSink) + m_pClientMsgSink->redirect(host.c_str(), port); + } else { + std::string twsTime; + + if( m_serverVersion >= 20) { + + DECODE_FIELD(twsTime); + } + + if (m_pClientMsgSink) + m_pClientMsgSink->serverVersion(m_serverVersion, twsTime.c_str()); + + m_pEWrapper->connectAck(); + } + + int processed = ptr - beginPtr; + beginPtr = ptr; + return processed; + } + catch( std::exception e) { + m_pEWrapper->error( NO_VALID_ID, SOCKET_EXCEPTION.code(), + SOCKET_EXCEPTION.msg() + errMsg( e) ); + } + + return 0; +} + + +int EDecoder::parseAndProcessMsg(const char*& beginPtr, const char* endPtr) { + // process a single message from the buffer; + // return number of bytes consumed + + assert( beginPtr && beginPtr < endPtr); + + if (m_serverVersion == 0) + return processConnectAck(beginPtr, endPtr); + + try { + + const char* ptr = beginPtr; + + int msgId; + DECODE_FIELD( msgId); + + switch( msgId) { + case TICK_PRICE: + ptr = processTickPriceMsg(ptr, endPtr); + break; + + case TICK_SIZE: + ptr = processTickSizeMsg(ptr, endPtr); + break; + + case TICK_OPTION_COMPUTATION: + ptr = processTickOptionComputationMsg(ptr, endPtr); + break; + + case TICK_GENERIC: + ptr = processTickGenericMsg(ptr, endPtr); + break; + + case TICK_STRING: + ptr = processTickStringMsg(ptr, endPtr); + break; + + case TICK_EFP: + ptr = processTickEfpMsg(ptr, endPtr); + break; + + case ORDER_STATUS: + ptr = processOrderStatusMsg(ptr, endPtr); + break; + + case ERR_MSG: + ptr = processErrMsgMsg(ptr, endPtr); + break; + + case OPEN_ORDER: + ptr = processOpenOrderMsg(ptr, endPtr); + break; + + case ACCT_VALUE: + ptr = processAcctValueMsg(ptr, endPtr); + break; + + case PORTFOLIO_VALUE: + ptr = processPortfolioValueMsg(ptr, endPtr); + break; + + case ACCT_UPDATE_TIME: + ptr = processAcctUpdateTimeMsg(ptr, endPtr); + break; + + case NEXT_VALID_ID: + ptr = processNextValidIdMsg(ptr, endPtr); + break; + + case CONTRACT_DATA: + ptr = processContractDataMsg(ptr, endPtr); + break; + + case BOND_CONTRACT_DATA: + ptr = processBondContractDataMsg(ptr, endPtr); + break; + + case EXECUTION_DATA: + ptr = processExecutionDataMsg(ptr, endPtr); + break; + + case MARKET_DEPTH: + ptr = processMarketDepthMsg(ptr, endPtr); + break; + + case MARKET_DEPTH_L2: + ptr = processMarketDepthL2Msg(ptr, endPtr); + break; + + case NEWS_BULLETINS: + ptr = processNewsBulletinsMsg(ptr, endPtr); + break; + + case MANAGED_ACCTS: + ptr = processManagedAcctsMsg(ptr, endPtr); + break; + + case RECEIVE_FA: + ptr = processReceiveFaMsg(ptr, endPtr); + break; + + case HISTORICAL_DATA: + ptr = processHistoricalDataMsg(ptr, endPtr); + break; + + case SCANNER_DATA: + ptr = processScannerDataMsg(ptr, endPtr); + break; + + case SCANNER_PARAMETERS: + ptr = processScannerParametersMsg(ptr, endPtr); + break; + + case CURRENT_TIME: + ptr = processCurrentTimeMsg(ptr, endPtr); + break; + + case REAL_TIME_BARS: + ptr = processRealTimeBarsMsg(ptr, endPtr); + break; + + case FUNDAMENTAL_DATA: + ptr = processFundamentalDataMsg(ptr, endPtr); + break; + + case CONTRACT_DATA_END: + ptr = processContractDataEndMsg(ptr, endPtr); + break; + + case OPEN_ORDER_END: + ptr = processOpenOrderEndMsg(ptr, endPtr); + break; + + case ACCT_DOWNLOAD_END: + ptr = processAcctDownloadEndMsg(ptr, endPtr); + break; + + case EXECUTION_DATA_END: + ptr = processExecutionDataEndMsg(ptr, endPtr); + break; + + case DELTA_NEUTRAL_VALIDATION: + ptr = processDeltaNeutralValidationMsg(ptr, endPtr); + break; + + case TICK_SNAPSHOT_END: + ptr = processTickSnapshotEndMsg(ptr, endPtr); + break; + + case MARKET_DATA_TYPE: + ptr = processMarketDataTypeMsg(ptr, endPtr); + break; + + case COMMISSION_REPORT: + ptr = processCommissionReportMsg(ptr, endPtr); + break; + + case POSITION_DATA: + ptr = processPositionDataMsg(ptr, endPtr); + break; + + case POSITION_END: + ptr = processPositionEndMsg(ptr, endPtr); + break; + + case ACCOUNT_SUMMARY: + ptr = processAccountSummaryMsg(ptr, endPtr); + break; + + case ACCOUNT_SUMMARY_END: + ptr = processAccountSummaryEndMsg(ptr, endPtr); + break; + + case VERIFY_MESSAGE_API: + ptr = processVerifyMessageApiMsg(ptr, endPtr); + break; + + case VERIFY_COMPLETED: + ptr = processVerifyCompletedMsg(ptr, endPtr); + break; + + case DISPLAY_GROUP_LIST: + ptr = processDisplayGroupListMsg(ptr, endPtr); + break; + + case DISPLAY_GROUP_UPDATED: + ptr = processDisplayGroupUpdatedMsg(ptr, endPtr); + break; + + case VERIFY_AND_AUTH_MESSAGE_API: + ptr = processVerifyAndAuthMessageApiMsg(ptr, endPtr); + break; + + case VERIFY_AND_AUTH_COMPLETED: + ptr = processVerifyAndAuthCompletedMsg(ptr, endPtr); + break; + + case POSITION_MULTI: + ptr = processPositionMultiMsg(ptr, endPtr); + break; + + case POSITION_MULTI_END: + ptr = processPositionMultiEndMsg(ptr, endPtr); + break; + + case ACCOUNT_UPDATE_MULTI: + ptr = processAccountUpdateMultiMsg(ptr, endPtr); + break; + + case ACCOUNT_UPDATE_MULTI_END: + ptr = processAccountUpdateMultiEndMsg(ptr, endPtr); + break; + + case SECURITY_DEFINITION_OPTION_PARAMETER: + ptr = processSecurityDefinitionOptionalParameterMsg(ptr, endPtr); + break; + + case SECURITY_DEFINITION_OPTION_PARAMETER_END: + ptr = processSecurityDefinitionOptionalParameterEndMsg(ptr, endPtr); + break; + + case SOFT_DOLLAR_TIERS: + ptr = processSoftDollarTiersMsg(ptr, endPtr); + break; + + default: + { + m_pEWrapper->error( msgId, UNKNOWN_ID.code(), UNKNOWN_ID.msg()); + m_pEWrapper->connectionClosed(); + break; + } + } + + if (!ptr) + return 0; + + int processed = ptr - beginPtr; + beginPtr = ptr; + return processed; + } + catch( std::exception e) { + m_pEWrapper->error( NO_VALID_ID, SOCKET_EXCEPTION.code(), + SOCKET_EXCEPTION.msg() + errMsg(e)); + } + return 0; +} + + +bool EDecoder::CheckOffset(const char* ptr, const char* endPtr) +{ + assert (ptr && ptr <= endPtr); + return (ptr && ptr < endPtr); +} + +const char* EDecoder::FindFieldEnd(const char* ptr, const char* endPtr) +{ + return (const char*)memchr(ptr, 0, endPtr - ptr); +} + +bool EDecoder::DecodeField(bool& boolValue, const char*& ptr, const char* endPtr) +{ + int intValue; + if( !DecodeField(intValue, ptr, endPtr)) + return false; + boolValue = (intValue > 0); + return true; +} + +bool EDecoder::DecodeField(int& intValue, const char*& ptr, const char* endPtr) +{ + if( !CheckOffset(ptr, endPtr)) + return false; + const char* fieldBeg = ptr; + const char* fieldEnd = FindFieldEnd(fieldBeg, endPtr); + if( !fieldEnd) + return false; + intValue = atoi(fieldBeg); + ptr = ++fieldEnd; + return true; +} + +bool EDecoder::DecodeField(long& longValue, const char*& ptr, const char* endPtr) +{ + int intValue; + if( !DecodeField(intValue, ptr, endPtr)) + return false; + longValue = intValue; + return true; +} + +bool EDecoder::DecodeField(double& doubleValue, const char*& ptr, const char* endPtr) +{ + if( !CheckOffset(ptr, endPtr)) + return false; + const char* fieldBeg = ptr; + const char* fieldEnd = FindFieldEnd(fieldBeg, endPtr); + if( !fieldEnd) + return false; + doubleValue = atof(fieldBeg); + ptr = ++fieldEnd; + return true; +} + +bool EDecoder::DecodeField(std::string& stringValue, + const char*& ptr, const char* endPtr) +{ + if( !CheckOffset(ptr, endPtr)) + return false; + const char* fieldBeg = ptr; + const char* fieldEnd = FindFieldEnd(ptr, endPtr); + if( !fieldEnd) + return false; + stringValue = fieldBeg; // better way? + ptr = ++fieldEnd; + return true; +} + +bool EDecoder::DecodeFieldMax(int& intValue, const char*& ptr, const char* endPtr) +{ + std::string stringValue; + if( !DecodeField(stringValue, ptr, endPtr)) + return false; + intValue = stringValue.empty() ? UNSET_INTEGER : atoi(stringValue.c_str()); + return true; +} + +bool EDecoder::DecodeFieldMax(long& longValue, const char*& ptr, const char* endPtr) +{ + int intValue; + if( !DecodeFieldMax(intValue, ptr, endPtr)) + return false; + longValue = intValue; + return true; +} + +bool EDecoder::DecodeFieldMax(double& doubleValue, const char*& ptr, const char* endPtr) +{ + std::string stringValue; + if( !DecodeField(stringValue, ptr, endPtr)) + return false; + doubleValue = stringValue.empty() ? UNSET_DOUBLE : atof(stringValue.c_str()); + return true; +} diff --git a/vn.ib/ibapi/windows/client/EDecoder.h b/vn.ib/ibapi/windows/client/EDecoder.h new file mode 100644 index 00000000..eb4e586f --- /dev/null +++ b/vn.ib/ibapi/windows/client/EDecoder.h @@ -0,0 +1,244 @@ +/* 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. */ + +#pragma once + +#include "Contract.h" + + +//const int MIN_SERVER_VER_REAL_TIME_BARS = 34; +//const int MIN_SERVER_VER_SCALE_ORDERS = 35; +//const int MIN_SERVER_VER_SNAPSHOT_MKT_DATA = 35; +//const int MIN_SERVER_VER_SSHORT_COMBO_LEGS = 35; +//const int MIN_SERVER_VER_WHAT_IF_ORDERS = 36; +//const int MIN_SERVER_VER_CONTRACT_CONID = 37; +const int MIN_SERVER_VER_PTA_ORDERS = 39; +const int MIN_SERVER_VER_FUNDAMENTAL_DATA = 40; +const int MIN_SERVER_VER_UNDER_COMP = 40; +const int MIN_SERVER_VER_CONTRACT_DATA_CHAIN = 40; +const int MIN_SERVER_VER_SCALE_ORDERS2 = 40; +const int MIN_SERVER_VER_ALGO_ORDERS = 41; +const int MIN_SERVER_VER_EXECUTION_DATA_CHAIN = 42; +const int MIN_SERVER_VER_NOT_HELD = 44; +const int MIN_SERVER_VER_SEC_ID_TYPE = 45; +const int MIN_SERVER_VER_PLACE_ORDER_CONID = 46; +const int MIN_SERVER_VER_REQ_MKT_DATA_CONID = 47; +const int MIN_SERVER_VER_REQ_CALC_IMPLIED_VOLAT = 49; +const int MIN_SERVER_VER_REQ_CALC_OPTION_PRICE = 50; +const int MIN_SERVER_VER_CANCEL_CALC_IMPLIED_VOLAT = 50; +const int MIN_SERVER_VER_CANCEL_CALC_OPTION_PRICE = 50; +const int MIN_SERVER_VER_SSHORTX_OLD = 51; +const int MIN_SERVER_VER_SSHORTX = 52; +const int MIN_SERVER_VER_REQ_GLOBAL_CANCEL = 53; +const int MIN_SERVER_VER_HEDGE_ORDERS = 54; +const int MIN_SERVER_VER_REQ_MARKET_DATA_TYPE = 55; +const int MIN_SERVER_VER_OPT_OUT_SMART_ROUTING = 56; +const int MIN_SERVER_VER_SMART_COMBO_ROUTING_PARAMS = 57; +const int MIN_SERVER_VER_DELTA_NEUTRAL_CONID = 58; +const int MIN_SERVER_VER_SCALE_ORDERS3 = 60; +const int MIN_SERVER_VER_ORDER_COMBO_LEGS_PRICE = 61; +const int MIN_SERVER_VER_TRAILING_PERCENT = 62; +const int MIN_SERVER_VER_DELTA_NEUTRAL_OPEN_CLOSE = 66; +const int MIN_SERVER_VER_POSITIONS = 67; +const int MIN_SERVER_VER_ACCOUNT_SUMMARY = 67; +const int MIN_SERVER_VER_TRADING_CLASS = 68; +const int MIN_SERVER_VER_SCALE_TABLE = 69; +const int MIN_SERVER_VER_LINKING = 70; +const int MIN_SERVER_VER_ALGO_ID = 71; +const int MIN_SERVER_VER_OPTIONAL_CAPABILITIES = 72; +const int MIN_SERVER_VER_ORDER_SOLICITED = 73; +const int MIN_SERVER_VER_LINKING_AUTH = 74; +const int MIN_SERVER_VER_PRIMARYEXCH = 75; +const int MIN_SERVER_VER_RANDOMIZE_SIZE_AND_PRICE = 76; +const int MIN_SERVER_VER_FRACTIONAL_POSITIONS = 101; +const int MIN_SERVER_VER_PEGGED_TO_BENCHMARK = 102; +const int MIN_SERVER_VER_MODELS_SUPPORT = 103; +const int MIN_SERVER_VER_SEC_DEF_OPT_PARAMS_REQ = 104; +const int MIN_SERVER_VER_EXT_OPERATOR = 105; +const int MIN_SERVER_VER_SOFT_DOLLAR_TIER = 106; + +/* 100+ messaging */ +// 100 = enhanced handshake, msg length prefixes + +const int MIN_CLIENT_VER = 100; +const int MAX_CLIENT_VER = MIN_SERVER_VER_SOFT_DOLLAR_TIER; + + +// incoming msg id's +const int TICK_PRICE = 1; +const int TICK_SIZE = 2; +const int ORDER_STATUS = 3; +const int ERR_MSG = 4; +const int OPEN_ORDER = 5; +const int ACCT_VALUE = 6; +const int PORTFOLIO_VALUE = 7; +const int ACCT_UPDATE_TIME = 8; +const int NEXT_VALID_ID = 9; +const int CONTRACT_DATA = 10; +const int EXECUTION_DATA = 11; +const int MARKET_DEPTH = 12; +const int MARKET_DEPTH_L2 = 13; +const int NEWS_BULLETINS = 14; +const int MANAGED_ACCTS = 15; +const int RECEIVE_FA = 16; +const int HISTORICAL_DATA = 17; +const int BOND_CONTRACT_DATA = 18; +const int SCANNER_PARAMETERS = 19; +const int SCANNER_DATA = 20; +const int TICK_OPTION_COMPUTATION = 21; +const int TICK_GENERIC = 45; +const int TICK_STRING = 46; +const int TICK_EFP = 47; +const int CURRENT_TIME = 49; +const int REAL_TIME_BARS = 50; +const int FUNDAMENTAL_DATA = 51; +const int CONTRACT_DATA_END = 52; +const int OPEN_ORDER_END = 53; +const int ACCT_DOWNLOAD_END = 54; +const int EXECUTION_DATA_END = 55; +const int DELTA_NEUTRAL_VALIDATION = 56; +const int TICK_SNAPSHOT_END = 57; +const int MARKET_DATA_TYPE = 58; +const int COMMISSION_REPORT = 59; +const int POSITION_DATA = 61; +const int POSITION_END = 62; +const int ACCOUNT_SUMMARY = 63; +const int ACCOUNT_SUMMARY_END = 64; +const int VERIFY_MESSAGE_API = 65; +const int VERIFY_COMPLETED = 66; +const int DISPLAY_GROUP_LIST = 67; +const int DISPLAY_GROUP_UPDATED = 68; +const int VERIFY_AND_AUTH_MESSAGE_API = 69; +const int VERIFY_AND_AUTH_COMPLETED = 70; +const int POSITION_MULTI = 71; +const int POSITION_MULTI_END = 72; +const int ACCOUNT_UPDATE_MULTI = 73; +const int ACCOUNT_UPDATE_MULTI_END = 74; +const int SECURITY_DEFINITION_OPTION_PARAMETER = 75; +const int SECURITY_DEFINITION_OPTION_PARAMETER_END = 76; +const int SOFT_DOLLAR_TIERS = 77; + +const int HEADER_LEN = 4; // 4 bytes for msg length +const int MAX_MSG_LEN = 0xFFFFFF; // 16Mb - 1byte +const char API_SIGN[4] = { 'A', 'P', 'I', '\0' }; // "API" + + +// helper structures +namespace { + +struct BarData { + std::string date; + double open; + double high; + double low; + double close; + int volume; + double average; + std::string hasGaps; + int barCount; +}; + +struct ScanData { + ContractDetails contract; + int rank; + std::string distance; + std::string benchmark; + std::string projection; + std::string legsStr; +}; + +} // end of anonymous namespace + +/////////////////////////////////////////////////////////// +// utility funcs +static std::string errMsg(std::exception e) { + // return the error associated with this exception + return std::string(e.what()); +} + +class EWrapper; +class EClient; +struct EClientMsgSink; + +class TWSAPIDLLEXP EDecoder +{ + EWrapper *m_pEWrapper; + int m_serverVersion; + EClientMsgSink *m_pClientMsgSink; + + const char* processTickPriceMsg(const char* ptr, const char* endPtr); + const char* processTickSizeMsg(const char* ptr, const char* endPtr); + const char* processTickOptionComputationMsg(const char* ptr, const char* endPtr); + const char* processTickGenericMsg(const char* ptr, const char* endPtr); + const char* processTickStringMsg(const char* ptr, const char* endPtr); + const char* processTickEfpMsg(const char* ptr, const char* endPtr); + const char* processOrderStatusMsg(const char* ptr, const char* endPtr); + const char* processErrMsgMsg(const char* ptr, const char* endPtr); + const char* processOpenOrderMsg(const char* ptr, const char* endPtr); + const char* processAcctValueMsg(const char* ptr, const char* endPtr); + const char* processPortfolioValueMsg(const char* ptr, const char* endPtr); + const char* processAcctUpdateTimeMsg(const char* ptr, const char* endPtr); + const char* processNextValidIdMsg(const char* ptr, const char* endPtr); + const char* processContractDataMsg(const char* ptr, const char* endPtr); + const char* processBondContractDataMsg(const char* ptr, const char* endPtr); + const char* processExecutionDataMsg(const char* ptr, const char* endPtr); + const char* processMarketDepthMsg(const char* ptr, const char* endPtr); + const char* processMarketDepthL2Msg(const char* ptr, const char* endPtr); + const char* processNewsBulletinsMsg(const char* ptr, const char* endPtr); + const char* processManagedAcctsMsg(const char* ptr, const char* endPtr); + const char* processReceiveFaMsg(const char* ptr, const char* endPtr); + const char* processHistoricalDataMsg(const char* ptr, const char* endPtr); + const char* processScannerDataMsg(const char* ptr, const char* endPtr); + const char* processScannerParametersMsg(const char* ptr, const char* endPtr); + const char* processCurrentTimeMsg(const char* ptr, const char* endPtr); + const char* processRealTimeBarsMsg(const char* ptr, const char* endPtr); + const char* processFundamentalDataMsg(const char* ptr, const char* endPtr); + const char* processContractDataEndMsg(const char* ptr, const char* endPtr); + const char* processOpenOrderEndMsg(const char* ptr, const char* endPtr); + const char* processAcctDownloadEndMsg(const char* ptr, const char* endPtr); + const char* processExecutionDataEndMsg(const char* ptr, const char* endPtr); + const char* processDeltaNeutralValidationMsg(const char* ptr, const char* endPtr); + const char* processTickSnapshotEndMsg(const char* ptr, const char* endPtr); + const char* processMarketDataTypeMsg(const char* ptr, const char* endPtr); + const char* processCommissionReportMsg(const char* ptr, const char* endPtr); + const char* processPositionDataMsg(const char* ptr, const char* endPtr); + const char* processPositionEndMsg(const char* ptr, const char* endPtr); + const char* processAccountSummaryMsg(const char* ptr, const char* endPtr); + const char* processAccountSummaryEndMsg(const char* ptr, const char* endPtr); + const char* processVerifyMessageApiMsg(const char* ptr, const char* endPtr); + const char* processVerifyCompletedMsg(const char* ptr, const char* endPtr); + const char* processDisplayGroupListMsg(const char* ptr, const char* endPtr); + const char* processDisplayGroupUpdatedMsg(const char* ptr, const char* endPtr); + const char* processVerifyAndAuthMessageApiMsg(const char* ptr, const char* endPtr); + const char* processVerifyAndAuthCompletedMsg(const char* ptr, const char* endPtr); + const char* processPositionMultiMsg(const char* ptr, const char* endPtr); + const char* processPositionMultiEndMsg(const char* ptr, const char* endPtr); + const char* processAccountUpdateMultiMsg(const char* ptr, const char* endPtr); + const char* processAccountUpdateMultiEndMsg(const char* ptr, const char* endPtr); + const char* processSecurityDefinitionOptionalParameterMsg(const char* ptr, const char* endPtr); + const char* processSecurityDefinitionOptionalParameterEndMsg(const char* ptr, const char* endPtr); + const char* processSoftDollarTiersMsg(const char* ptr, const char* endPtr); + + int processConnectAck(const char*& beginPtr, const char* endPtr); + +public: + static bool CheckOffset(const char* ptr, const char* endPtr); + static const char* FindFieldEnd(const char* ptr, const char* endPtr); + // decoders + static bool DecodeField(bool&, const char*& ptr, const char* endPtr); + static bool DecodeField(int&, const char*& ptr, const char* endPtr); + static bool DecodeField(long&, const char*& ptr, const char* endPtr); + static bool DecodeField(double&, const char*& ptr, const char* endPtr); + static bool DecodeField(std::string&, const char*& ptr, const char* endPtr); + + static bool DecodeFieldMax(int&, const char*& ptr, const char* endPtr); + static bool DecodeFieldMax(long&, const char*& ptr, const char* endPtr); + static bool DecodeFieldMax(double&, const char*& ptr, const char* endPtr); + + EDecoder(int serverVersion, EWrapper *callback, EClientMsgSink *clientMsgSink = 0); + + int parseAndProcessMsg(const char*& beginPtr, const char* endPtr); +}; + +#define DECODE_FIELD(x) if (!EDecoder::DecodeField(x, ptr, endPtr)) return 0; +#define DECODE_FIELD_MAX(x) if (!EDecoder::DecodeFieldMax(x, ptr, endPtr)) return 0; diff --git a/vn.ib/ibapi/windows/client/EMessage.cpp b/vn.ib/ibapi/windows/client/EMessage.cpp new file mode 100644 index 00000000..ee1055d4 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EMessage.cpp @@ -0,0 +1,20 @@ +/* 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. */ + +#include "StdAfx.h" +#include "EMessage.h" + + +EMessage::EMessage(const std::vector &data) { + this->data = data; +} + +const char* EMessage::begin(void) const +{ + return data.data(); +} + +const char* EMessage::end(void) const +{ + return data.data() + data.size(); +} diff --git a/vn.ib/ibapi/windows/client/EMessage.h b/vn.ib/ibapi/windows/client/EMessage.h new file mode 100644 index 00000000..80b8c82d --- /dev/null +++ b/vn.ib/ibapi/windows/client/EMessage.h @@ -0,0 +1,13 @@ +/* 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. */ + +#pragma once +class TWSAPIDLLEXP EMessage +{ + std::vector data; +public: + EMessage(const std::vector &data); + const char* begin(void) const; + const char* end(void) const; +}; + diff --git a/vn.ib/ibapi/windows/client/EMutex.cpp b/vn.ib/ibapi/windows/client/EMutex.cpp new file mode 100644 index 00000000..b16e63f5 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EMutex.cpp @@ -0,0 +1,59 @@ +/* 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. */ + +#include "StdAfx.h" +#include "EMutex.h" + +EMutex::EMutex() +{ +#if defined(IB_POSIX) + pthread_mutex_init(&cs, NULL); +#elif defined(IB_WIN32) + InitializeCriticalSection(&cs); +#else +# error "Not implemented on this platform" +#endif +} + +EMutex::~EMutex(void) +{ + Leave(); +#if defined(IB_POSIX) + pthread_mutex_destroy(&cs); +#elif defined(IB_WIN32) + DeleteCriticalSection(&cs); +#else +# error "Not implemented on this platform" +#endif +} + +bool EMutex::TryEnter() +{ +#if defined(IB_POSIX) + return pthread_mutex_trylock(&cs) == 0; +#elif defined(IB_WIN32) + return TryEnterCriticalSection(&cs); +#else +# error "Not implemented on this platform" +#endif +} + +void EMutex::Enter() { +#if defined(IB_POSIX) + pthread_mutex_lock(&cs); +#elif defined(IB_WIN32) + EnterCriticalSection(&cs); +#else +# error "Not implemented on this platform" +#endif +} + +void EMutex::Leave() { +#if defined(IB_POSIX) + pthread_mutex_unlock(&cs); +#elif defined(IB_WIN32) + LeaveCriticalSection(&cs); +#else +# error "Not implemented on this platform" +#endif +} diff --git a/vn.ib/ibapi/windows/client/EMutex.h b/vn.ib/ibapi/windows/client/EMutex.h new file mode 100644 index 00000000..4f762dbd --- /dev/null +++ b/vn.ib/ibapi/windows/client/EMutex.h @@ -0,0 +1,25 @@ +/* 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. */ + +#pragma once + +#include "StdAfx.h" + +class TWSAPIDLLEXP EMutex +{ +#if defined(IB_POSIX) + pthread_mutex_t cs; +#elif defined(IB_WIN32) + CRITICAL_SECTION cs; +#else +# error "Not implemented on this platform" +#endif + +public: + EMutex(); + ~EMutex(); + bool TryEnter(); + void Enter(); + void Leave(); +}; + diff --git a/vn.ib/ibapi/windows/client/EPosixClientSocketPlatform.h b/vn.ib/ibapi/windows/client/EPosixClientSocketPlatform.h new file mode 100644 index 00000000..d47d7ee5 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EPosixClientSocketPlatform.h @@ -0,0 +1,65 @@ +/* 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. */ + +#pragma once +#ifndef eposixclientsocketcommon_def +#define eposixclientsocketcommon_def + +#ifdef _WIN32 + + // Windows + // includes + #include + #include + + // defines + #if _MSC_VER < 1700 + #define EISCONN WSAEISCONN + #define EWOULDBLOCK WSAEWOULDBLOCK + #define ECONNREFUSED WSAECONNREFUSED + #else + #pragma comment(lib, "ws2_32.lib") + #endif + + // helpers + inline bool SocketsInit( void) { + WSADATA data; + return ( !WSAStartup( MAKEWORD(2, 2), &data)); + }; + inline bool SocketsDestroy() { return ( !WSACleanup()); }; + inline int SocketClose(int sockfd) { return closesocket( sockfd); }; + + inline bool SetSocketNonBlocking(int sockfd) { + unsigned long mode = 1; + return ( ioctlsocket( sockfd, FIONBIO, &mode) == 0); + }; + +#else + // LINUX + // includes + + #include + #include + #include + #include + #include + #include + + // helpers + inline bool SocketsInit() { return true; }; + inline bool SocketsDestroy() { return true; }; + inline int SocketClose(int sockfd) { return close( sockfd); }; + + inline bool SetSocketNonBlocking(int sockfd) { + // get socket flags + int flags = fcntl(sockfd, F_GETFL); + if (flags == -1) + return false; + + // set non-blocking mode + return ( fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == 0); + }; + +#endif + +#endif diff --git a/vn.ib/ibapi/windows/client/EReader.cpp b/vn.ib/ibapi/windows/client/EReader.cpp new file mode 100644 index 00000000..5bc00630 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReader.cpp @@ -0,0 +1,290 @@ +/* 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. */ + +#include "StdAfx.h" +#include "shared_ptr.h" +#include "Contract.h" +#include "EDecoder.h" +#include "EMutex.h" +#include "EReader.h" +#include "EClientSocket.h" +#include "EPosixClientSocketPlatform.h" +#include "EReaderSignal.h" +#include "EMessage.h" +#include "DefaultEWrapper.h" + +#define IN_BUF_SIZE_DEFAULT 8192 + +static DefaultEWrapper defaultWrapper; + +EReader::EReader(EClientSocket *clientSocket, EReaderSignal *signal) + : processMsgsDecoder_(clientSocket->EClient::serverVersion(), clientSocket->getWrapper(), clientSocket) { + m_isAlive = true; + m_pClientSocket = clientSocket; + m_pEReaderSignal = signal; + m_needsWriteSelect = false; + m_nMaxBufSize = IN_BUF_SIZE_DEFAULT; + m_buf.reserve(IN_BUF_SIZE_DEFAULT); +} + +EReader::~EReader(void) { + m_isAlive = false; + +#if defined(IB_WIN32) + WaitForSingleObject(m_hReadThread, INFINITE); +#endif +} + +void EReader::checkClient() { + m_needsWriteSelect = !m_pClientSocket->getTransport()->isOutBufferEmpty(); +} + +void EReader::start() { +#if defined(IB_POSIX) + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create( &thread, &attr, readToQueueThread, this ); + pthread_attr_destroy(&attr); +#elif defined(IB_WIN32) + m_hReadThread = CreateThread(0, 0, readToQueueThread, this, 0, 0); +#else +# error "Not implemented on this platform" +#endif +} + +#if defined(IB_POSIX) +void * EReader::readToQueueThread(void * lpParam) +#elif defined(IB_WIN32) +DWORD WINAPI EReader::readToQueueThread(LPVOID lpParam) +#else +# error "Not implemented on this platform" +#endif +{ + EReader *pThis = reinterpret_cast(lpParam); + + pThis->readToQueue(); + return 0; +} + +void EReader::readToQueue() { + EMessage *msg = 0; + + while (m_isAlive) { + if (m_buf.size() == 0 && !processNonBlockingSelect() && m_pClientSocket->isSocketOK()) + continue; + + if (!putMessageToQueue()) + break; + } + + m_pClientSocket->handleSocketError(); + m_pEReaderSignal->issueSignal(); //letting client know that socket was closed +} + +bool EReader::putMessageToQueue() { + EMessage *msg = 0; + + if (m_pClientSocket->isSocketOK()) + msg = readSingleMsg(); + + if (msg == 0) + return false; + + m_csMsgQueue.Enter(); + m_msgQueue.push_back(ibapi::shared_ptr(msg)); + m_csMsgQueue.Leave(); + m_pEReaderSignal->issueSignal(); + + return true; +} + +bool EReader::processNonBlockingSelect() { + fd_set readSet, writeSet, errorSet; + struct timeval tval; + + tval.tv_usec = 100 * 1000; //100 ms + tval.tv_sec = 0; + + if( m_pClientSocket->fd() >= 0 ) { + + FD_ZERO( &readSet); + errorSet = writeSet = readSet; + + FD_SET( m_pClientSocket->fd(), &readSet); + + if (m_needsWriteSelect) + FD_SET( m_pClientSocket->fd(), &writeSet); + + FD_SET( m_pClientSocket->fd(), &errorSet); + + int ret = select( m_pClientSocket->fd() + 1, &readSet, &writeSet, &errorSet, &tval); + + if( ret == 0) { // timeout + return false; + } + + if( ret < 0) { // error + m_pClientSocket->eDisconnect(); + return false; + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &errorSet)) { + // error on socket + m_pClientSocket->onError(); + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &writeSet)) { + // socket is ready for writing + onSend(); + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &readSet)) { + // socket is ready for reading + onReceive(); + } + + return true; + } + + return false; +} + +void EReader::onSend() { + m_pEReaderSignal->issueSignal(); +} + +void EReader::onReceive() { + int nOffset = m_buf.size(); + + m_buf.resize(m_nMaxBufSize); + + int nRes = m_pClientSocket->receive(m_buf.data() + nOffset, m_buf.size() - nOffset); + + if (nRes <= 0) + return; + + m_buf.resize(nRes + nOffset); +} + +bool EReader::bufferedRead(char *buf, int size) { + while (size > 0) { + while (m_buf.size() < size && m_buf.size() < m_nMaxBufSize) + if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) + return false; + + int nBytes = min(m_nMaxBufSize, size); + + std::copy(m_buf.begin(), m_buf.begin() + nBytes, buf); + std::copy(m_buf.begin() + nBytes, m_buf.end(), m_buf.begin()); + m_buf.resize(m_buf.size() - nBytes); + + size -= nBytes; + buf += nBytes; + } + + return true; +} + +EMessage * EReader::readSingleMsg() { + if (m_pClientSocket->usingV100Plus()) { + int msgSize; + + if (!bufferedRead((char *)&msgSize, sizeof(msgSize))) + return 0; + + msgSize = htonl(msgSize); + + if (msgSize <= 0 || msgSize > MAX_MSG_LEN) + return 0; + + std::vector buf = std::vector(msgSize); + + if (!bufferedRead(buf.data(), buf.size())) + return 0; + + return new EMessage(buf); + } + else { + const char *pBegin = 0; + const char *pEnd = 0; + int msgSize = 0; + + while (msgSize == 0) + { + if (m_buf.size() >= m_nMaxBufSize * 3/4) + m_nMaxBufSize *= 2; + + if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) + return 0; + + pBegin = m_buf.data(); + pEnd = pBegin + m_buf.size(); + msgSize = EDecoder(m_pClientSocket->EClient::serverVersion(), &defaultWrapper).parseAndProcessMsg(pBegin, pEnd); + } + + std::vector msgData(msgSize); + + if (!bufferedRead(msgData.data(), msgSize)) + return 0; + + if (m_buf.size() < IN_BUF_SIZE_DEFAULT && m_buf.capacity() > IN_BUF_SIZE_DEFAULT) + { + m_buf.resize(m_nMaxBufSize = IN_BUF_SIZE_DEFAULT); + m_buf.shrink_to_fit(); + } + + EMessage * msg = new EMessage(msgData); + + return msg; + } +} + +ibapi::shared_ptr EReader::getMsg(void) { + m_csMsgQueue.Enter(); + + if (m_msgQueue.size() == 0) { + m_csMsgQueue.Leave(); + + return ibapi::shared_ptr(); + } + + ibapi::shared_ptr msg = m_msgQueue.front(); + + m_msgQueue.pop_front(); + m_csMsgQueue.Leave(); + + return msg; +} + + +void EReader::processMsgs(void) { + m_pClientSocket->onSend(); + checkClient(); + + ibapi::shared_ptr msg = getMsg(); + + if (!msg.get()) + return; + + const char *pBegin = msg->begin(); + + while (processMsgsDecoder_.parseAndProcessMsg(pBegin, msg->end()) > 0) { + msg = getMsg(); + + if (!msg.get()) + break; + + pBegin = msg->begin(); + } +} diff --git a/vn.ib/ibapi/windows/client/EReader.h b/vn.ib/ibapi/windows/client/EReader.h new file mode 100644 index 00000000..f373d221 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReader.h @@ -0,0 +1,58 @@ +/* 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. */ + +#pragma once + +#include "StdAfx.h" +#include "EDecoder.h" +#include "EMutex.h" +#include "EReaderOSSignal.h" + +class EClientSocket; +class EReaderSignal; +class EMessage; + +class TWSAPIDLLEXP EReader +{ + EClientSocket *m_pClientSocket; + EReaderSignal *m_pEReaderSignal; + EDecoder processMsgsDecoder_; + std::deque> m_msgQueue; + EMutex m_csMsgQueue; + std::vector m_buf; + bool m_needsWriteSelect; + bool m_isAlive; +#if defined(IB_WIN32) + HANDLE m_hReadThread; +#endif + int m_nMaxBufSize; + + void onReceive(); + void onSend(); + bool bufferedRead(char *buf, int size); + +public: + EReader(EClientSocket *clientSocket, EReaderSignal *signal); + ~EReader(void); + +protected: + bool processNonBlockingSelect(); + ibapi::shared_ptr getMsg(void); + void readToQueue(); +#if defined(IB_POSIX) + static void * readToQueueThread(void * lpParam); +#elif defined(IB_WIN32) + static DWORD WINAPI readToQueueThread(LPVOID lpParam); +#else +# error "Not implemented on this platform" +#endif + + EMessage * readSingleMsg(); + +public: + void processMsgs(void); + void checkClient(); + bool putMessageToQueue(); + void start(); +}; + diff --git a/vn.ib/ibapi/windows/client/EReaderOSSignal.cpp b/vn.ib/ibapi/windows/client/EReaderOSSignal.cpp new file mode 100644 index 00000000..d4b2d70d --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReaderOSSignal.cpp @@ -0,0 +1,73 @@ +/* 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. */ + +#include "StdAfx.h" +#include "EReaderOSSignal.h" + + +#define MS_IN_SEC 1000 + + +EReaderOSSignal::EReaderOSSignal(unsigned long waitTimeout) throw (std::runtime_error) +{ + bool ok = false; + m_waitTimeout = waitTimeout; +#if defined(IB_POSIX) + int rc1 = pthread_mutex_init(&m_mutex, NULL); + int rc2 = pthread_cond_init(&m_evMsgs, NULL); + ok = rc1 == 0 && rc2 == 0; +#elif defined(IB_WIN32) + m_evMsgs = CreateEvent(0, false, false, 0); + ok = (NULL != m_evMsgs); +#else +# error "Not implemented on this platform" +#endif + if (!ok) + throw std::runtime_error("Failed to create event"); +} + + +EReaderOSSignal::~EReaderOSSignal(void) +{ +#if defined(IB_POSIX) + pthread_cond_destroy(&m_evMsgs); + pthread_mutex_destroy(&m_mutex); +#elif defined(IB_WIN32) + CloseHandle(m_evMsgs); +#else +# error "Not implemented on this platform" +#endif +} + + +void EReaderOSSignal::issueSignal() { +#if defined(IB_POSIX) + pthread_mutex_lock(&m_mutex); + pthread_cond_signal(&m_evMsgs); + pthread_mutex_unlock(&m_mutex); +#elif defined(IB_WIN32) + SetEvent(m_evMsgs); +#else +# error "Not implemented on this platform" +#endif +} + +void EReaderOSSignal::waitForSignal() { +#if defined(IB_POSIX) + pthread_mutex_lock(&m_mutex); + if ( m_waitTimeout == INFINITE ) { + pthread_cond_wait(&m_evMsgs, &m_mutex); + } + else { + struct timespec ts; + ts.tv_sec = m_waitTimeout/MS_IN_SEC; + ts.tv_nsec = (m_waitTimeout%MS_IN_SEC)*1000/*us/ms*/*1000/*ns/us*/; + pthread_cond_timedwait(&m_evMsgs, &m_mutex, &ts); + } + pthread_mutex_unlock(&m_mutex); +#elif defined(IB_WIN32) + WaitForSingleObject(m_evMsgs, m_waitTimeout); +#else +# error "Not implemented on this platform" +#endif +} diff --git a/vn.ib/ibapi/windows/client/EReaderOSSignal.h b/vn.ib/ibapi/windows/client/EReaderOSSignal.h new file mode 100644 index 00000000..a87d4659 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReaderOSSignal.h @@ -0,0 +1,33 @@ +/* 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. */ + +#pragma once +#include "EReaderSignal.h" +#include "StdAfx.h" +#include + +#if !defined(INFINITE) +#define INFINITE ((unsigned long)-1) +#endif + +class TWSAPIDLLEXP EReaderOSSignal : + public EReaderSignal +{ +#if defined(IB_POSIX) + pthread_cond_t m_evMsgs; + pthread_mutex_t m_mutex; +#elif defined(IB_WIN32) + HANDLE m_evMsgs; +#else +# error "Not implemented on this platform" +#endif + unsigned long m_waitTimeout; // in milliseconds + +public: + EReaderOSSignal(unsigned long waitTimeout = INFINITE) throw (std::runtime_error); + ~EReaderOSSignal(void); + + virtual void issueSignal(); + virtual void waitForSignal(); +}; + diff --git a/vn.ib/ibapi/windows/client/EReaderSignal.h b/vn.ib/ibapi/windows/client/EReaderSignal.h new file mode 100644 index 00000000..74ad520f --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReaderSignal.h @@ -0,0 +1,10 @@ +/* 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. */ + +#pragma once +struct EReaderSignal +{ + virtual void issueSignal() = 0; + virtual void waitForSignal() = 0; +}; + diff --git a/vn.ib/ibapi/windows/client/EReaderWMSignal.cpp b/vn.ib/ibapi/windows/client/EReaderWMSignal.cpp new file mode 100644 index 00000000..8488c8d8 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReaderWMSignal.cpp @@ -0,0 +1,25 @@ +/* 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. */ + +#include "StdAfx.h" +#if defined(IB_WIN32) +#include "EReaderWMSignal.h" + + +EReaderWMSignal::EReaderWMSignal(HWND hWnd, int wmUserOffset) { + m_hWnd = hWnd; + m_msg = WM_USER + wmUserOffset; +} + +void EReaderWMSignal::issueSignal() { + if (IsWindow(m_hWnd)) + PostMessage(m_hWnd, m_msg, 0, 0); +} + +void EReaderWMSignal::waitForSignal() { + MSG msg; + + if (GetMessage(&msg, 0, m_msg, m_msg)) + DispatchMessage(&msg); +} +#endif diff --git a/vn.ib/ibapi/windows/client/EReaderWMSignal.h b/vn.ib/ibapi/windows/client/EReaderWMSignal.h new file mode 100644 index 00000000..943a6ff6 --- /dev/null +++ b/vn.ib/ibapi/windows/client/EReaderWMSignal.h @@ -0,0 +1,19 @@ +/* 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. */ + +#pragma once +#include "ereadersignal.h" + +class EReaderWMSignal : + public EReaderSignal +{ + HWND m_hWnd; + int m_msg; + +public: + EReaderWMSignal(HWND hWnd, int msg); + + virtual void issueSignal(); + virtual void waitForSignal(); +}; + diff --git a/vn.ib/ibapi/windows/client/ESocket.cpp b/vn.ib/ibapi/windows/client/ESocket.cpp new file mode 100644 index 00000000..18fadc68 --- /dev/null +++ b/vn.ib/ibapi/windows/client/ESocket.cpp @@ -0,0 +1,102 @@ +#include "StdAfx.h" +#include "EMessage.h" +#include "ESocket.h" + +#include + +#if defined(IB_POSIX) +#include +#endif + +ESocket::ESocket() { +} + +void ESocket::fd(int fd) { + m_fd = fd; +} + +ESocket::~ESocket(void) { +} + +int ESocket::send(EMessage *pMsg) { + return bufferedSend(pMsg->begin(), pMsg->end() - pMsg->begin()); +} + +int ESocket::bufferedSend(const char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + if( !m_outBuffer.empty()) { + m_outBuffer.insert( m_outBuffer.end(), buf, buf + sz); + return sendBufferedData(); + } + + int nResult = send(buf, sz); + + if( nResult < (int)sz) { + int sent = (std::max)( nResult, 0); + m_outBuffer.insert( m_outBuffer.end(), buf + sent, buf + sz); + } + + return nResult; +} + +int ESocket::sendBufferedData() +{ + if( m_outBuffer.empty()) + return 0; + + int nResult = send( &m_outBuffer[0], m_outBuffer.size()); + if( nResult <= 0) { + return nResult; + } + CleanupBuffer( m_outBuffer, nResult); + return nResult; +} + +int ESocket::send(const char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + int nResult = ::send( m_fd, buf, sz, 0); + + if( nResult == -1) { + return -1; + } + if( nResult <= 0) { + return 0; + } + return nResult; +} + +static const size_t BufferSizeHighMark = 1 * 1024 * 1024; // 1Mb + +void ESocket::CleanupBuffer(std::vector& buffer, int processed) +{ + assert( buffer.empty() || processed <= (int)buffer.size()); + + if( buffer.empty()) + return; + + if( processed <= 0) + return; + + if( (size_t)processed == buffer.size()) { + if( buffer.capacity() >= BufferSizeHighMark) { + std::vector().swap(buffer); + } + else { + buffer.clear(); + } + } + else { + buffer.erase( buffer.begin(), buffer.begin() + processed); + } +} + +bool ESocket::isOutBufferEmpty() const +{ + return m_outBuffer.empty(); +} diff --git a/vn.ib/ibapi/windows/client/ESocket.h b/vn.ib/ibapi/windows/client/ESocket.h new file mode 100644 index 00000000..c391cefc --- /dev/null +++ b/vn.ib/ibapi/windows/client/ESocket.h @@ -0,0 +1,23 @@ +#pragma once +#include "ETransport.h" + +class ESocket : + public ETransport +{ + int m_fd; + std::vector m_outBuffer; + + int bufferedSend(const char* buf, size_t sz); + int send(const char* buf, size_t sz); + void CleanupBuffer(std::vector& buffer, int processed); + +public: + ESocket(); + ~ESocket(void); + + int send(EMessage *pMsg); + bool isOutBufferEmpty() const; + int sendBufferedData(); + void fd(int fd); +}; + diff --git a/vn.ib/ibapi/windows/client/ETransport.h b/vn.ib/ibapi/windows/client/ETransport.h new file mode 100644 index 00000000..572a8215 --- /dev/null +++ b/vn.ib/ibapi/windows/client/ETransport.h @@ -0,0 +1,11 @@ +#pragma once + +class EMessage; + +struct ETransport +{ + virtual int send(EMessage *pMsg) = 0; + //virtual int sendBufferedData() = 0; + //virtual bool isOutBufferEmpty() const = 0; +}; + diff --git a/vn.ib/ibapi/windows/client/EWrapper.h b/vn.ib/ibapi/windows/client/EWrapper.h new file mode 100644 index 00000000..ce6b70dd --- /dev/null +++ b/vn.ib/ibapi/windows/client/EWrapper.h @@ -0,0 +1,176 @@ +/* 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. */ + +#pragma once +#ifndef ewrapper_def +#define ewrapper_def + +#include "CommonDefs.h" +#include "SoftDollarTier.h" +#include +#include + +enum TickType { BID_SIZE, BID, ASK, ASK_SIZE, LAST, LAST_SIZE, + HIGH, LOW, VOLUME, CLOSE, + BID_OPTION_COMPUTATION, + ASK_OPTION_COMPUTATION, + LAST_OPTION_COMPUTATION, + MODEL_OPTION, + OPEN, + LOW_13_WEEK, + HIGH_13_WEEK, + LOW_26_WEEK, + HIGH_26_WEEK, + LOW_52_WEEK, + HIGH_52_WEEK, + AVG_VOLUME, + OPEN_INTEREST, + OPTION_HISTORICAL_VOL, + OPTION_IMPLIED_VOL, + OPTION_BID_EXCH, + OPTION_ASK_EXCH, + OPTION_CALL_OPEN_INTEREST, + OPTION_PUT_OPEN_INTEREST, + OPTION_CALL_VOLUME, + OPTION_PUT_VOLUME, + INDEX_FUTURE_PREMIUM, + BID_EXCH, + ASK_EXCH, + AUCTION_VOLUME, + AUCTION_PRICE, + AUCTION_IMBALANCE, + MARK_PRICE, + BID_EFP_COMPUTATION, + ASK_EFP_COMPUTATION, + LAST_EFP_COMPUTATION, + OPEN_EFP_COMPUTATION, + HIGH_EFP_COMPUTATION, + LOW_EFP_COMPUTATION, + CLOSE_EFP_COMPUTATION, + LAST_TIMESTAMP, + SHORTABLE, + FUNDAMENTAL_RATIOS, + RT_VOLUME, + HALTED, + BID_YIELD, + ASK_YIELD, + LAST_YIELD, + CUST_OPTION_COMPUTATION, + TRADE_COUNT, + TRADE_RATE, + VOLUME_RATE, + LAST_RTH_TRADE, + RT_HISTORICAL_VOL, + IB_DIVIDENDS, + BOND_FACTOR_MULTIPLIER, + REGULATORY_IMBALANCE, + NEWS_TICK, + SHORT_TERM_VOLUME_3_MIN, + SHORT_TERM_VOLUME_5_MIN, + SHORT_TERM_VOLUME_10_MIN, + DELAYED_BID, + DELAYED_ASK, + DELAYED_LAST, + DELAYED_BID_SIZE, + DELAYED_ASK_SIZE, + DELAYED_LAST_SIZE, + DELAYED_HIGH, + DELAYED_LOW, + DELAYED_VOLUME, + DELAYED_CLOSE, + DELAYED_OPEN, + RT_TRD_VOLUME, + CREDITMAN_MARK_PRICE, + CREDITMAN_SLOW_MARK_PRICE, + NOT_SET }; + +inline bool isPrice( TickType tickType) { + return tickType == BID || tickType == ASK || tickType == LAST; +} + +struct Contract; +struct ContractDetails; +struct Order; +struct OrderState; +struct Execution; +struct UnderComp; +struct CommissionReport; + +class EWrapper +{ +public: + virtual ~EWrapper() {}; + + virtual void tickPrice( TickerId tickerId, TickType field, double price, int canAutoExecute) = 0; + virtual void tickSize( TickerId tickerId, TickType field, int size) = 0; + virtual void tickOptionComputation( TickerId tickerId, TickType tickType, double impliedVol, double delta, + double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) = 0; + virtual void tickGeneric(TickerId tickerId, TickType tickType, double value) = 0; + virtual void tickString(TickerId tickerId, TickType tickType, const std::string& value) = 0; + virtual void tickEFP(TickerId tickerId, TickType tickType, double basisPoints, const std::string& formattedBasisPoints, + double totalDividends, int holdDays, const std::string& futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate) = 0; + virtual void orderStatus( OrderId orderId, const std::string& status, double filled, + double remaining, double avgFillPrice, int permId, int parentId, + double lastFillPrice, int clientId, const std::string& whyHeld) = 0; + virtual void openOrder( OrderId orderId, const Contract&, const Order&, const OrderState&) = 0; + virtual void openOrderEnd() = 0; + virtual void winError( const std::string& str, int lastError) = 0; + virtual void connectionClosed() = 0; + virtual void updateAccountValue(const std::string& key, const std::string& val, + const std::string& currency, const std::string& accountName) = 0; + virtual void updatePortfolio( const Contract& contract, double position, + double marketPrice, double marketValue, double averageCost, + double unrealizedPNL, double realizedPNL, const std::string& accountName) = 0; + virtual void updateAccountTime(const std::string& timeStamp) = 0; + virtual void accountDownloadEnd(const std::string& accountName) = 0; + virtual void nextValidId( OrderId orderId) = 0; + virtual void contractDetails( int reqId, const ContractDetails& contractDetails) = 0; + virtual void bondContractDetails( int reqId, const ContractDetails& contractDetails) = 0; + virtual void contractDetailsEnd( int reqId) = 0; + virtual void execDetails( int reqId, const Contract& contract, const Execution& execution) =0; + virtual void execDetailsEnd( int reqId) =0; + virtual void error(const int id, const int errorCode, const std::string errorString) = 0; + virtual void updateMktDepth(TickerId id, int position, int operation, int side, + double price, int size) = 0; + virtual void updateMktDepthL2(TickerId id, int position, std::string marketMaker, int operation, + int side, double price, int size) = 0; + virtual void updateNewsBulletin(int msgId, int msgType, const std::string& newsMessage, const std::string& originExch) = 0; + virtual void managedAccounts( const std::string& accountsList) = 0; + virtual void receiveFA(faDataType pFaDataType, const std::string& cxml) = 0; + virtual void historicalData(TickerId reqId, const std::string& date, double open, double high, + double low, double close, int volume, int barCount, double WAP, int hasGaps) = 0; + virtual void scannerParameters(const std::string& xml) = 0; + virtual void scannerData(int reqId, int rank, const ContractDetails& contractDetails, + const std::string& distance, const std::string& benchmark, const std::string& projection, + const std::string& legsStr) = 0; + virtual void scannerDataEnd(int reqId) = 0; + virtual void realtimeBar(TickerId reqId, long time, double open, double high, double low, double close, + long volume, double wap, int count) = 0; + virtual void currentTime(long time) = 0; + virtual void fundamentalData(TickerId reqId, const std::string& data) = 0; + virtual void deltaNeutralValidation(int reqId, const UnderComp& underComp) = 0; + virtual void tickSnapshotEnd( int reqId) = 0; + virtual void marketDataType( TickerId reqId, int marketDataType) = 0; + virtual void commissionReport( const CommissionReport& commissionReport) = 0; + virtual void position( const std::string& account, const Contract& contract, double position, double avgCost) = 0; + virtual void positionEnd() = 0; + virtual void accountSummary( int reqId, const std::string& account, const std::string& tag, const std::string& value, const std::string& curency) = 0; + virtual void accountSummaryEnd( int reqId) = 0; + virtual void verifyMessageAPI( const std::string& apiData) = 0; + virtual void verifyCompleted( bool isSuccessful, const std::string& errorText) = 0; + virtual void displayGroupList( int reqId, const std::string& groups) = 0; + virtual void displayGroupUpdated( int reqId, const std::string& contractInfo) = 0; + virtual void verifyAndAuthMessageAPI( const std::string& apiData, const std::string& xyzChallange) = 0; + virtual void verifyAndAuthCompleted( bool isSuccessful, const std::string& errorText) = 0; + virtual void connectAck() = 0; + virtual void positionMulti( int reqId, const std::string& account,const std::string& modelCode, const Contract& contract, double pos, double avgCost) = 0; + virtual void positionMultiEnd( int reqId) = 0; + virtual void accountUpdateMulti( int reqId, const std::string& account, const std::string& modelCode, const std::string& key, const std::string& value, const std::string& currency) = 0; + virtual void accountUpdateMultiEnd( int reqId) = 0; + virtual void securityDefinitionOptionalParameter(int reqId, const std::string& exchange, int underlyingConId, const std::string& tradingClass, const std::string& multiplier, std::set expirations, std::set strikes) = 0; + virtual void securityDefinitionOptionalParameterEnd(int reqId) = 0; + virtual void softDollarTiers(int reqId, const std::vector &tiers) = 0; +}; + + +#endif diff --git a/vn.ib/ibapi/windows/client/Execution.h b/vn.ib/ibapi/windows/client/Execution.h new file mode 100644 index 00000000..372f378f --- /dev/null +++ b/vn.ib/ibapi/windows/client/Execution.h @@ -0,0 +1,59 @@ +/* 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. */ + +#pragma once +#ifndef execution_def +#define execution_def + + +struct Execution +{ + Execution() + { + shares = 0; + price = 0; + permId = 0; + clientId = 0; + orderId = 0; + cumQty = 0; + avgPrice = 0; + evMultiplier = 0; + } + + std::string execId; + std::string time; + std::string acctNumber; + std::string exchange; + std::string side; + double shares; + double price; + int permId; + long clientId; + long orderId; + int liquidation; + int cumQty; + double avgPrice; + std::string orderRef; + std::string evRule; + double evMultiplier; + std::string modelCode; +}; + +struct ExecutionFilter +{ + ExecutionFilter() + : m_clientId(0) + { + } + + // Filter fields + long m_clientId; + std::string m_acctCode; + std::string m_time; + std::string m_symbol; + std::string m_secType; + std::string m_exchange; + std::string m_side; +}; + +#endif // execution_def diff --git a/vn.ib/ibapi/windows/client/IExternalizable.h b/vn.ib/ibapi/windows/client/IExternalizable.h new file mode 100644 index 00000000..361847e3 --- /dev/null +++ b/vn.ib/ibapi/windows/client/IExternalizable.h @@ -0,0 +1,9 @@ +#pragma once +#include + +struct IExternalizable +{ + virtual const char* readExternal(const char* ptr, const char* endPtr) = 0; + virtual void writeExternal(std::ostream &out) const = 0; +}; + diff --git a/vn.ib/ibapi/windows/client/MarginCondition.cpp b/vn.ib/ibapi/windows/client/MarginCondition.cpp new file mode 100644 index 00000000..3bbb66c5 --- /dev/null +++ b/vn.ib/ibapi/windows/client/MarginCondition.cpp @@ -0,0 +1,30 @@ +#include "StdAfx.h" +#include "MarginCondition.h" +#include + +std::string MarginCondition::valueToString() const { + std::stringstream tmp; + + tmp << m_percent; + + return tmp.str(); +} + +void MarginCondition::valueFromString(const std::string & v) { + std::stringstream tmp; + + tmp << v; + tmp >> m_percent; +} + +std::string MarginCondition::toString() { + return "the margin cushion percent" + OperatorCondition::toString(); +} + +int MarginCondition::percent() { + return m_percent; +} + +void MarginCondition::percent(int percent) { + m_percent = percent; +} diff --git a/vn.ib/ibapi/windows/client/MarginCondition.h b/vn.ib/ibapi/windows/client/MarginCondition.h new file mode 100644 index 00000000..505b920d --- /dev/null +++ b/vn.ib/ibapi/windows/client/MarginCondition.h @@ -0,0 +1,23 @@ +#pragma once +#include "OperatorCondition.h" + +class TWSAPIDLLEXP MarginCondition : public OperatorCondition { + friend OrderCondition; + + int m_percent; + +public: + static const OrderConditionType conditionType = OrderConditionType::Margin; + +protected: + MarginCondition() { } + + virtual std::string valueToString() const; + virtual void valueFromString(const std::string &v); + +public: + virtual std::string toString(); + + int percent(); + void percent(int percent); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/OperatorCondition.cpp b/vn.ib/ibapi/windows/client/OperatorCondition.cpp new file mode 100644 index 00000000..b24306bf --- /dev/null +++ b/vn.ib/ibapi/windows/client/OperatorCondition.cpp @@ -0,0 +1,38 @@ +#include "StdAfx.h" +#include "OperatorCondition.h" +#include "EDecoder.h" +#include "EClient.h" + +const char* OperatorCondition::readExternal(const char* ptr, const char* endPtr) { + if (!(ptr = OrderCondition::readExternal(ptr, endPtr))) + return 0; + + DECODE_FIELD(m_isMore); + + std::string str; + + DECODE_FIELD(str); + + valueFromString(str); + + return ptr; +} + +std::string OperatorCondition::toString() { + return " is " + std::string(isMore() ? ">= " : "<= ") + valueToString(); +} + +void OperatorCondition::writeExternal(std::ostream & msg) const { + OrderCondition::writeExternal(msg); + + ENCODE_FIELD(m_isMore); + ENCODE_FIELD(valueToString()); +} + +bool OperatorCondition::isMore() { + return m_isMore; +} + +void OperatorCondition::isMore(bool isMore) { + m_isMore = isMore; +} diff --git a/vn.ib/ibapi/windows/client/OperatorCondition.h b/vn.ib/ibapi/windows/client/OperatorCondition.h new file mode 100644 index 00000000..36a9062c --- /dev/null +++ b/vn.ib/ibapi/windows/client/OperatorCondition.h @@ -0,0 +1,18 @@ +#pragma once +#include "OrderCondition.h" + +class TWSAPIDLLEXP OperatorCondition : public OrderCondition { + bool m_isMore; + +protected: + virtual std::string valueToString() const = 0; + virtual void valueFromString(const std::string &v) = 0; + +public: + virtual const char* readExternal(const char* ptr, const char* endPtr); + virtual std::string toString(); + virtual void writeExternal(std::ostream &out) const; + + bool isMore(); + void isMore(bool isMore); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/Order.h b/vn.ib/ibapi/windows/client/Order.h new file mode 100644 index 00000000..d92cec8d --- /dev/null +++ b/vn.ib/ibapi/windows/client/Order.h @@ -0,0 +1,339 @@ +/* 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. */ + +#pragma once +#ifndef order_def +#define order_def + +#include "TagValue.h" +#include "OrderCondition.h" +#include "SoftDollarTier.h" + +#include +#include + +#define UNSET_DOUBLE DBL_MAX +#define UNSET_INTEGER INT_MAX + +enum Origin { CUSTOMER, + FIRM, + UNKNOWN }; + +enum AuctionStrategy { AUCTION_UNSET = 0, + AUCTION_MATCH = 1, + AUCTION_IMPROVEMENT = 2, + AUCTION_TRANSPARENT = 3 }; + +struct OrderComboLeg +{ + OrderComboLeg() + { + price = UNSET_DOUBLE; + } + + double price; + + bool operator==( const OrderComboLeg& other) const + { + return (price == other.price); + } +}; + +typedef ibapi::shared_ptr OrderComboLegSPtr; + +struct Order +{ + Order() : + softDollarTier("", "", "") + { + // order identifier + orderId = 0; + clientId = 0; + permId = 0; + + // main order fields + totalQuantity = 0; + lmtPrice = UNSET_DOUBLE; + auxPrice = UNSET_DOUBLE; + + // extended order fields + activeStartTime = ""; + activeStopTime = ""; + ocaType = 0; + transmit = true; + parentId = 0; + blockOrder = false; + sweepToFill = false; + displaySize = 0; + triggerMethod = 0; + outsideRth = false; + hidden = false; + allOrNone = false; + minQty = UNSET_INTEGER; + percentOffset = UNSET_DOUBLE; + overridePercentageConstraints = false; + trailStopPrice = UNSET_DOUBLE; + trailingPercent = UNSET_DOUBLE; + + // institutional (ie non-cleared) only + openClose = "O"; + origin = CUSTOMER; + shortSaleSlot = 0; + exemptCode = -1; + + // SMART routing only + discretionaryAmt = 0; + eTradeOnly = true; + firmQuoteOnly = true; + nbboPriceCap = UNSET_DOUBLE; + optOutSmartRouting = false; + + // BOX exchange orders only + auctionStrategy = AUCTION_UNSET; + startingPrice = UNSET_DOUBLE; + stockRefPrice = UNSET_DOUBLE; + delta = UNSET_DOUBLE; + + // pegged to stock and VOL orders only + stockRangeLower = UNSET_DOUBLE; + stockRangeUpper = UNSET_DOUBLE; + + randomizePrice = false; + randomizeSize = false; + + // VOLATILITY ORDERS ONLY + volatility = UNSET_DOUBLE; + volatilityType = UNSET_INTEGER; // 1=daily, 2=annual + deltaNeutralOrderType = ""; + deltaNeutralAuxPrice = UNSET_DOUBLE; + deltaNeutralConId = 0; + deltaNeutralSettlingFirm = ""; + deltaNeutralClearingAccount = ""; + deltaNeutralClearingIntent = ""; + deltaNeutralOpenClose = ""; + deltaNeutralShortSale = false; + deltaNeutralShortSaleSlot = 0; + deltaNeutralDesignatedLocation = ""; + continuousUpdate = false; + referencePriceType = UNSET_INTEGER; // 1=Average, 2 = BidOrAsk + + // COMBO ORDERS ONLY + basisPoints = UNSET_DOUBLE; // EFP orders only + basisPointsType = UNSET_INTEGER; // EFP orders only + + // SCALE ORDERS ONLY + scaleInitLevelSize = UNSET_INTEGER; + scaleSubsLevelSize = UNSET_INTEGER; + scalePriceIncrement = UNSET_DOUBLE; + scalePriceAdjustValue = UNSET_DOUBLE; + scalePriceAdjustInterval = UNSET_INTEGER; + scaleProfitOffset = UNSET_DOUBLE; + scaleAutoReset = false; + scaleInitPosition = UNSET_INTEGER; + scaleInitFillQty = UNSET_INTEGER; + scaleRandomPercent = false; + scaleTable = ""; + + // What-if + whatIf = false; + + // Not Held + notHeld = false; + solicited = false; + + triggerPrice = UNSET_DOUBLE; + adjustedStopPrice = UNSET_DOUBLE; + adjustedStopLimitPrice = UNSET_DOUBLE; + adjustedTrailingAmount = UNSET_DOUBLE; + lmtPriceOffset = UNSET_DOUBLE; + extOperator = ""; + } + + // order identifier + long orderId; + long clientId; + long permId; + + // main order fields + std::string action; + double totalQuantity; + std::string orderType; + double lmtPrice; + double auxPrice; + + // extended order fields + std::string tif; // "Time in Force" - DAY, GTC, etc. + std::string activeStartTime; // for GTC orders + std::string activeStopTime; // for GTC orders + std::string ocaGroup; // one cancels all group name + int ocaType; // 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK + std::string orderRef; // order reference + bool transmit; // if false, order will be created but not transmited + long parentId; // Parent order Id, to associate Auto STP or TRAIL orders with the original order. + bool blockOrder; + bool sweepToFill; + int displaySize; + int triggerMethod; // 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last, 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point + bool outsideRth; + bool hidden; + std::string goodAfterTime; // Format: 20060505 08:00:00 {time zone} + std::string goodTillDate; // Format: 20060505 08:00:00 {time zone} + std::string rule80A; // Individual = 'I', Agency = 'A', AgentOtherMember = 'W', IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M', IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N' + bool allOrNone; + int minQty; + double percentOffset; // REL orders only + bool overridePercentageConstraints; + double trailStopPrice; // TRAILLIMIT orders only + double trailingPercent; + + // financial advisors only + std::string faGroup; + std::string faProfile; + std::string faMethod; + std::string faPercentage; + + // institutional (ie non-cleared) only + std::string openClose; // O=Open, C=Close + Origin origin; // 0=Customer, 1=Firm + int shortSaleSlot; // 1 if you hold the shares, 2 if they will be delivered from elsewhere. Only for Action="SSHORT + std::string designatedLocation; // set when slot=2 only. + int exemptCode; + + // SMART routing only + double discretionaryAmt; + bool eTradeOnly; + bool firmQuoteOnly; + double nbboPriceCap; + bool optOutSmartRouting; + + // BOX exchange orders only + int auctionStrategy; // AUCTION_MATCH, AUCTION_IMPROVEMENT, AUCTION_TRANSPARENT + double startingPrice; + double stockRefPrice; + double delta; + + // pegged to stock and VOL orders only + double stockRangeLower; + double stockRangeUpper; + + bool randomizeSize; + bool randomizePrice; + + // VOLATILITY ORDERS ONLY + double volatility; + int volatilityType; // 1=daily, 2=annual + std::string deltaNeutralOrderType; + double deltaNeutralAuxPrice; + long deltaNeutralConId; + std::string deltaNeutralSettlingFirm; + std::string deltaNeutralClearingAccount; + std::string deltaNeutralClearingIntent; + std::string deltaNeutralOpenClose; + bool deltaNeutralShortSale; + int deltaNeutralShortSaleSlot; + std::string deltaNeutralDesignatedLocation; + bool continuousUpdate; + int referencePriceType; // 1=Average, 2 = BidOrAsk + + // COMBO ORDERS ONLY + double basisPoints; // EFP orders only + int basisPointsType; // EFP orders only + + // SCALE ORDERS ONLY + int scaleInitLevelSize; + int scaleSubsLevelSize; + double scalePriceIncrement; + double scalePriceAdjustValue; + int scalePriceAdjustInterval; + double scaleProfitOffset; + bool scaleAutoReset; + int scaleInitPosition; + int scaleInitFillQty; + bool scaleRandomPercent; + std::string scaleTable; + + // HEDGE ORDERS + std::string hedgeType; // 'D' - delta, 'B' - beta, 'F' - FX, 'P' - pair + std::string hedgeParam; // 'beta=X' value for beta hedge, 'ratio=Y' for pair hedge + + // Clearing info + std::string account; // IB account + std::string settlingFirm; + std::string clearingAccount; // True beneficiary of the order + std::string clearingIntent; // "" (Default), "IB", "Away", "PTA" (PostTrade) + + // ALGO ORDERS ONLY + std::string algoStrategy; + + TagValueListSPtr algoParams; + TagValueListSPtr smartComboRoutingParams; + + std::string algoId; + + // What-if + bool whatIf; + + // Not Held + bool notHeld; + bool solicited; + + // models + std::string modelCode; + + // order combo legs + typedef std::vector OrderComboLegList; + typedef ibapi::shared_ptr OrderComboLegListSPtr; + + OrderComboLegListSPtr orderComboLegs; + + TagValueListSPtr orderMiscOptions; + + //VER PEG2BENCH fields: + int referenceContractId; + double peggedChangeAmount; + bool isPeggedChangeAmountDecrease; + double referenceChangeAmount; + std::string referenceExchangeId; + std::string adjustedOrderType; + double triggerPrice; + double adjustedStopPrice; + double adjustedStopLimitPrice; + double adjustedTrailingAmount; + int adjustableTrailingUnit; + double lmtPriceOffset; + + std::vector> conditions; + bool conditionsCancelOrder; + bool conditionsIgnoreRth; + + // ext operator + std::string extOperator; + + SoftDollarTier softDollarTier; + +public: + + // Helpers + static void CloneOrderComboLegs(OrderComboLegListSPtr& dst, const OrderComboLegListSPtr& src); +}; + +inline void +Order::CloneOrderComboLegs(OrderComboLegListSPtr& dst, const OrderComboLegListSPtr& src) +{ + if (!src.get()) + return; + + dst->reserve(src->size()); + + OrderComboLegList::const_iterator iter = src->begin(); + const OrderComboLegList::const_iterator iterEnd = src->end(); + + for (; iter != iterEnd; ++iter) { + const OrderComboLeg* leg = iter->get(); + if (!leg) + continue; + dst->push_back(OrderComboLegSPtr(new OrderComboLeg(*leg))); + } +} + +#endif diff --git a/vn.ib/ibapi/windows/client/OrderCondition.cpp b/vn.ib/ibapi/windows/client/OrderCondition.cpp new file mode 100644 index 00000000..02c0497c --- /dev/null +++ b/vn.ib/ibapi/windows/client/OrderCondition.cpp @@ -0,0 +1,73 @@ +#include "StdAfx.h" +#include "OrderCondition.h" +#include "executioncondition.h" +#include "MarginCondition.h" +#include "TimeCondition.h" +#include "PercentChangeCondition.h" +#include "PriceCondition.h" +#include "VolumeCondition.h" +#include "EDecoder.h" +#include "EClient.h" + +const char* OrderCondition::readExternal(const char* ptr, const char* endPtr) { + std::string connector; + + DECODE_FIELD(connector) + + conjunctionConnection(connector == "a"); + + return ptr; +} + +void OrderCondition::writeExternal(std::ostream & msg) const { + ENCODE_FIELD(conjunctionConnection() ? "a" : "o") +} + +std::string OrderCondition::toString() { + return conjunctionConnection() ? "" : ""; +} + +bool OrderCondition::conjunctionConnection() const { + return m_isConjunctionConnection; +} + +void OrderCondition::conjunctionConnection(bool isConjunctionConnection) { + m_isConjunctionConnection = isConjunctionConnection; +} + +OrderCondition::OrderConditionType OrderCondition::type() { return m_type; } + +OrderCondition *OrderCondition::create(OrderConditionType type) { + OrderCondition *rval = 0; + + switch (type) { + case Execution: + rval = new ExecutionCondition(); + break; + + case Margin: + rval = new MarginCondition(); + break; + + case PercentChange: + rval = new PercentChangeCondition(); + break; + + case Price: + rval = new PriceCondition(); + break; + + case Time: + rval = new TimeCondition(); + break; + + case Volume: + rval = new VolumeCondition(); + break; + } + + if (rval != 0) + rval->m_type = type; + + return rval; +} diff --git a/vn.ib/ibapi/windows/client/OrderCondition.h b/vn.ib/ibapi/windows/client/OrderCondition.h new file mode 100644 index 00000000..55b0090e --- /dev/null +++ b/vn.ib/ibapi/windows/client/OrderCondition.h @@ -0,0 +1,30 @@ +#pragma once +#include "IExternalizable.h" +#include "shared_ptr.h" + +class TWSAPIDLLEXP OrderCondition : public IExternalizable { +public: + enum OrderConditionType { + Price = 1, + Time = 3, + Margin = 4, + Execution = 5, + Volume = 6, + PercentChange = 7 + }; + +private: + OrderConditionType m_type; + bool m_isConjunctionConnection; + +public: + virtual const char* readExternal(const char* ptr, const char* endPtr); + virtual void writeExternal(std::ostream &out) const; + + std::string toString(); + bool conjunctionConnection() const; + void conjunctionConnection(bool isConjunctionConnection); + OrderConditionType type(); + + static OrderCondition *create(OrderConditionType type); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/OrderState.h b/vn.ib/ibapi/windows/client/OrderState.h new file mode 100644 index 00000000..ba12851c --- /dev/null +++ b/vn.ib/ibapi/windows/client/OrderState.h @@ -0,0 +1,33 @@ +/* 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. */ + +#pragma once +#ifndef ORDER_STATE_H__INCLUDED +#define ORDER_STATE_H__INCLUDED + +#include "Order.h" + +struct OrderState { + + explicit OrderState() + : + commission(UNSET_DOUBLE), + minCommission(UNSET_DOUBLE), + maxCommission(UNSET_DOUBLE) + {} + + std::string status; + + std::string initMargin; + std::string maintMargin; + std::string equityWithLoan; + + double commission; + double minCommission; + double maxCommission; + std::string commissionCurrency; + + std::string warningText; +}; + +#endif diff --git a/vn.ib/ibapi/windows/client/PercentChangeCondition.cpp b/vn.ib/ibapi/windows/client/PercentChangeCondition.cpp new file mode 100644 index 00000000..a05d9800 --- /dev/null +++ b/vn.ib/ibapi/windows/client/PercentChangeCondition.cpp @@ -0,0 +1,26 @@ +#include "StdAfx.h" +#include "PercentChangeCondition.h" +#include + +std::string PercentChangeCondition::valueToString() const { + std::stringstream tmp; + + tmp << m_changePercent; + + return tmp.str(); +} + +void PercentChangeCondition::valueFromString(const std::string & v) { + std::stringstream tmp; + + tmp << v; + tmp >> m_changePercent; +} + +double PercentChangeCondition::changePercent() { + return m_changePercent; +} + +void PercentChangeCondition::changePercent(double changePercent) { + m_changePercent = changePercent; +} diff --git a/vn.ib/ibapi/windows/client/PercentChangeCondition.h b/vn.ib/ibapi/windows/client/PercentChangeCondition.h new file mode 100644 index 00000000..6ed18f89 --- /dev/null +++ b/vn.ib/ibapi/windows/client/PercentChangeCondition.h @@ -0,0 +1,23 @@ +#pragma once +#include "ContractCondition.h" +#include "Order.h" + +class TWSAPIDLLEXP PercentChangeCondition : public ContractCondition { + friend OrderCondition; + + double m_changePercent; + +protected: + PercentChangeCondition() + : m_changePercent(UNSET_DOUBLE) + { } + + virtual std::string valueToString() const; + virtual void valueFromString(const std::string &v); + +public: + static const OrderConditionType conditionType = OrderConditionType::PercentChange; + + double changePercent(); + void changePercent(double changePercent); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/PriceCondition.cpp b/vn.ib/ibapi/windows/client/PriceCondition.cpp new file mode 100644 index 00000000..d5cea7ab --- /dev/null +++ b/vn.ib/ibapi/windows/client/PriceCondition.cpp @@ -0,0 +1,61 @@ +#include "StdAfx.h" +#include "PriceCondition.h" +#include +#include "EDecoder.h" +#include "EClient.h" + +std::string PriceCondition::valueToString() const { + std::stringstream tmp; + + tmp << m_price; + + return tmp.str(); +} + +void PriceCondition::valueFromString(const std::string & v) { + std::stringstream tmp; + + tmp << v; + tmp >> m_price; +} + +double PriceCondition::price() { + return m_price; +} + +void PriceCondition::price(double price) { + m_price = price; +} + +std::string PriceCondition::toString() { + return strTriggerMethod() + " " + ContractCondition::toString(); +} + +PriceCondition::Method PriceCondition::triggerMethod() { + return (Method)m_triggerMethod; +} + +std::string PriceCondition::strTriggerMethod() { + static std::string mthdNames[] = { "default", "double bid/ask", "last", "double last", "bid/ask", "", "", "last of bid/ask", "mid-point" }; + + return mthdNames[triggerMethod()]; +} + +void PriceCondition::triggerMethod(Method triggerMethod) { + m_triggerMethod = triggerMethod; +} + +const char* PriceCondition::readExternal(const char* ptr, const char* endPtr) { + if (!(ptr = ContractCondition::readExternal(ptr, endPtr))) + return 0; + + DECODE_FIELD(m_triggerMethod) + + return ptr; +} + +void PriceCondition::writeExternal(std::ostream & msg) const { + ContractCondition::writeExternal(msg); + + ENCODE_FIELD(m_triggerMethod); +} diff --git a/vn.ib/ibapi/windows/client/PriceCondition.h b/vn.ib/ibapi/windows/client/PriceCondition.h new file mode 100644 index 00000000..4635b095 --- /dev/null +++ b/vn.ib/ibapi/windows/client/PriceCondition.h @@ -0,0 +1,38 @@ +#pragma once +#include "ContractCondition.h" + +class TWSAPIDLLEXP PriceCondition : public ContractCondition { + friend OrderCondition; + + double m_price; + int m_triggerMethod; + + virtual std::string valueToString() const; + virtual void valueFromString(const std::string &v); + +protected: + PriceCondition() { }; + +public: + static const OrderConditionType conditionType = OrderConditionType::Price; + enum Method { + Default = 0, + DoubleBidAsk = 1, + Last = 2, + DoubleLast = 3, + BidAsk = 4, + LastBidAsk = 7, + MidPoint = 8 + }; + + double price(); + void price(double price); + + virtual std::string toString(); + virtual const char* readExternal(const char* ptr, const char* endPtr); + virtual void writeExternal(std::ostream & out) const; + + Method triggerMethod(); + std::string strTriggerMethod(); + void triggerMethod(Method triggerMethod); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/Resource.h b/vn.ib/ibapi/windows/client/Resource.h new file mode 100644 index 00000000..d1af86eb --- /dev/null +++ b/vn.ib/ibapi/windows/client/Resource.h @@ -0,0 +1,19 @@ +/* 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. */ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by TWSSOCKETCLIENT.RC +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/vn.ib/ibapi/windows/client/ScannerSubscription.h b/vn.ib/ibapi/windows/client/ScannerSubscription.h new file mode 100644 index 00000000..007a5722 --- /dev/null +++ b/vn.ib/ibapi/windows/client/ScannerSubscription.h @@ -0,0 +1,51 @@ +/* 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. */ + +#pragma once +#ifndef scanner_def +#define scanner_def + +#include +#include + +#define UNSET_DOUBLE DBL_MAX +#define UNSET_INTEGER INT_MAX +#define NO_ROW_NUMBER_SPECIFIED -1; + +struct ScannerSubscription { + ScannerSubscription() { + numberOfRows = NO_ROW_NUMBER_SPECIFIED; + abovePrice = DBL_MAX; + belowPrice = DBL_MAX; + aboveVolume = INT_MAX; + marketCapAbove = DBL_MAX; + marketCapBelow = DBL_MAX; + couponRateAbove = DBL_MAX; + couponRateBelow = DBL_MAX; + excludeConvertible = 0; + averageOptionVolumeAbove = 0; + } + int numberOfRows; + std::string instrument; + std::string locationCode; + std::string scanCode; + double abovePrice; + double belowPrice; + int aboveVolume; + double marketCapAbove; + double marketCapBelow; + std::string moodyRatingAbove; + std::string moodyRatingBelow; + std::string spRatingAbove; + std::string spRatingBelow; + std::string maturityDateAbove; + std::string maturityDateBelow; + double couponRateAbove; + double couponRateBelow; + int excludeConvertible; + int averageOptionVolumeAbove; + std::string scannerSettingPairs; + std::string stockTypeFilter; +}; + +#endif diff --git a/vn.ib/ibapi/windows/client/SoftDollarTier.cpp b/vn.ib/ibapi/windows/client/SoftDollarTier.cpp new file mode 100644 index 00000000..daf20233 --- /dev/null +++ b/vn.ib/ibapi/windows/client/SoftDollarTier.cpp @@ -0,0 +1,22 @@ +#include "StdAfx.h" +#include "SoftDollarTier.h" + +SoftDollarTier::SoftDollarTier(const std::string& name, const std::string& val, const std::string& displayName) : + m_name(name), m_val(val), m_displayName(displayName) +{ +} + +std::string SoftDollarTier::name() const +{ + return m_name; +} + +std::string SoftDollarTier::val() const +{ + return m_val; +} + +std::string SoftDollarTier::displayName() const +{ + return m_displayName; +} \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/SoftDollarTier.h b/vn.ib/ibapi/windows/client/SoftDollarTier.h new file mode 100644 index 00000000..86761b9b --- /dev/null +++ b/vn.ib/ibapi/windows/client/SoftDollarTier.h @@ -0,0 +1,25 @@ +#pragma once + +class TWSAPIDLLEXP SoftDollarTier +{ + std::string m_name, m_val, m_displayName; + +public: + SoftDollarTier(const std::string& name = "", const std::string& val = "", const std::string& displayName = ""); + + std::string name() const; + std::string val() const; + std::string displayName() const; + + //װ + bool operator==(const SoftDollarTier & a) + { + return a.name() == this->name(); + } + + bool operator!=(const SoftDollarTier & a) + { + return a.name() != this->name(); + } +}; + diff --git a/vn.ib/ibapi/windows/client/StdAfx.cpp b/vn.ib/ibapi/windows/client/StdAfx.cpp new file mode 100644 index 00000000..35d31dac --- /dev/null +++ b/vn.ib/ibapi/windows/client/StdAfx.cpp @@ -0,0 +1,4 @@ +/* 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. */ + +#include "StdAfx.h" diff --git a/vn.ib/ibapi/windows/client/StdAfx.h b/vn.ib/ibapi/windows/client/StdAfx.h new file mode 100644 index 00000000..1174bc50 --- /dev/null +++ b/vn.ib/ibapi/windows/client/StdAfx.h @@ -0,0 +1,39 @@ +/* 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. */ + +#ifdef _MSC_VER + +#ifdef TWSAPIDLL +#ifndef TWSAPIDLLEXP +#define TWSAPIDLLEXP __declspec(dllexport) +#endif +#endif + +#define assert ASSERT +#define snprintf _snprintf +#include +#include +#define IB_WIN32 + +#else + +#include // defines _POSIX_THREADS, @see http://bit.ly/1pWJ8KQ#tag_13_80_03_02 + +#if defined(_POSIX_THREADS) && (_POSIX_THREADS > 0) + #include + #define IB_POSIX +#else + #error "Not supported on this platform" +#endif + +#endif // #ifdef _MSC_VER + +#include +#include +#include +#include + +#ifndef TWSAPIDLLEXP +#define TWSAPIDLLEXP +#endif + diff --git a/vn.ib/ibapi/windows/client/TagValue.h b/vn.ib/ibapi/windows/client/TagValue.h new file mode 100644 index 00000000..2daf2db8 --- /dev/null +++ b/vn.ib/ibapi/windows/client/TagValue.h @@ -0,0 +1,29 @@ +/* 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. */ + +#pragma once +#ifndef tagvalue_def +#define tagvalue_def + +#include "shared_ptr.h" + +#include +#include + +struct TagValue +{ + TagValue() {} + TagValue(const std::string& p_tag, const std::string& p_value) + : tag(p_tag), value(p_value) + {} + + std::string tag; + std::string value; +}; + +typedef ibapi::shared_ptr TagValueSPtr; +typedef std::vector TagValueList; +typedef ibapi::shared_ptr TagValueListSPtr; + +#endif + diff --git a/vn.ib/ibapi/windows/client/TimeCondition.cpp b/vn.ib/ibapi/windows/client/TimeCondition.cpp new file mode 100644 index 00000000..a7cf06f3 --- /dev/null +++ b/vn.ib/ibapi/windows/client/TimeCondition.cpp @@ -0,0 +1,22 @@ +#include "StdAfx.h" +#include "TimeCondition.h" + +std::string TimeCondition::valueToString() const { + return m_time; +} + +void TimeCondition::valueFromString(const std::string & v) { + m_time = v; +} + +std::string TimeCondition::toString() { + return "time" + OperatorCondition::toString(); +} + +std::string TimeCondition::time() { + return m_time; +} + +void TimeCondition::time(const std::string & time) { + m_time = time; +} diff --git a/vn.ib/ibapi/windows/client/TimeCondition.h b/vn.ib/ibapi/windows/client/TimeCondition.h new file mode 100644 index 00000000..c7b3bce9 --- /dev/null +++ b/vn.ib/ibapi/windows/client/TimeCondition.h @@ -0,0 +1,22 @@ +#pragma once +#include "OperatorCondition.h" + +class TWSAPIDLLEXP TimeCondition : public OperatorCondition { + friend OrderCondition; + + std::string m_time; + +protected: + TimeCondition() { } + + virtual std::string valueToString() const; + virtual void valueFromString(const std::string &v); + +public: + static const OrderConditionType conditionType = OrderConditionType::Time; + + virtual std::string toString(); + + std::string time(); + void time(const std::string &time); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/client/TwsSocketClient.def b/vn.ib/ibapi/windows/client/TwsSocketClient.def similarity index 100% rename from vn.ib/ibapi/client/TwsSocketClient.def rename to vn.ib/ibapi/windows/client/TwsSocketClient.def diff --git a/vn.ib/ibapi/client/TwsSocketClient.rc b/vn.ib/ibapi/windows/client/TwsSocketClient.rc similarity index 95% rename from vn.ib/ibapi/client/TwsSocketClient.rc rename to vn.ib/ibapi/windows/client/TwsSocketClient.rc index 9e22a3ca..f496d853 100644 --- a/vn.ib/ibapi/client/TwsSocketClient.rc +++ b/vn.ib/ibapi/windows/client/TwsSocketClient.rc @@ -67,8 +67,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 9,72,16,0 - PRODUCTVERSION 9,72,16,0 + FILEVERSION 9,72,18,0 + PRODUCTVERSION 9,72,18,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -85,12 +85,12 @@ BEGIN BEGIN VALUE "CompanyName", "Interactive Brokers" VALUE "FileDescription", "TwsSocketClient DLL" - VALUE "FileVersion", "9.72.16" + VALUE "FileVersion", "9.72.18" VALUE "InternalName", "TwsSocketClient" VALUE "LegalCopyright", "Copyright (C) 2006" VALUE "OriginalFilename", "TwsSocketClient.DLL" VALUE "ProductName", "TwsSocketClient Dynamic Link Library" - VALUE "ProductVersion", "9.72.16" + VALUE "ProductVersion", "9.72.18" END END BLOCK "VarFileInfo" diff --git a/vn.ib/ibapi/client/TwsSocketClient.sln b/vn.ib/ibapi/windows/client/TwsSocketClient.sln similarity index 100% rename from vn.ib/ibapi/client/TwsSocketClient.sln rename to vn.ib/ibapi/windows/client/TwsSocketClient.sln diff --git a/vn.ib/ibapi/client/TwsSocketClient.vcxproj b/vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj similarity index 99% rename from vn.ib/ibapi/client/TwsSocketClient.vcxproj rename to vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj index 59e2851a..4f32b1e5 100644 --- a/vn.ib/ibapi/client/TwsSocketClient.vcxproj +++ b/vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj @@ -177,6 +177,7 @@ + @@ -211,6 +212,7 @@ + diff --git a/vn.ib/ibapi/client/TwsSocketClient.vcxproj.filters b/vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj.filters similarity index 97% rename from vn.ib/ibapi/client/TwsSocketClient.vcxproj.filters rename to vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj.filters index b2de3f61..d9f5141d 100644 --- a/vn.ib/ibapi/client/TwsSocketClient.vcxproj.filters +++ b/vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + @@ -201,5 +204,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/vn.ib/ibapi/client/TwsSocketClient.vcxproj.user b/vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj.user similarity index 100% rename from vn.ib/ibapi/client/TwsSocketClient.vcxproj.user rename to vn.ib/ibapi/windows/client/TwsSocketClient.vcxproj.user diff --git a/vn.ib/ibapi/windows/client/TwsSocketClientErrors.h b/vn.ib/ibapi/windows/client/TwsSocketClientErrors.h new file mode 100644 index 00000000..b14cdf66 --- /dev/null +++ b/vn.ib/ibapi/windows/client/TwsSocketClientErrors.h @@ -0,0 +1,40 @@ +/* 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. */ + +#pragma once +#ifndef tswsocketclienterrors_def +#define tswsocketclienterrors_def + +static const int NO_VALID_ID = -1; +static const int NO_VALID_ERROR_CODE = 0; +static const int SYSTEM_ERROR = 600; + +class CodeMsgPair { +public: + CodeMsgPair(int code, std::string msg) : m_errorCode(code), m_errorMsg(msg) { + } +private: + int m_errorCode; + std::string m_errorMsg; +public: + int code() const { return m_errorCode; } + const std::string& msg() const { return m_errorMsg; } +}; + +static const CodeMsgPair ALREADY_CONNECTED(501, "Already connected."); +static const CodeMsgPair CONNECT_FAIL(502, "Couldn't connect to TWS. Confirm that \"Enable ActiveX and Socket Clients\" " + "is enabled and connection port is the same as \"Socket Port\" on the " + "TWS \"Edit->Global Configuration...->API->Settings\" menu. Live Trading ports: " + "TWS: 7496; IB Gateway: 4001. Simulated Trading ports for new installations " + "of version 954.1 or newer: TWS: 7497; IB Gateway: 4002"); +static const CodeMsgPair UPDATE_TWS(503, "The TWS is out of date and must be upgraded."); +static const CodeMsgPair NOT_CONNECTED(504, "Not connected"); +static const CodeMsgPair UNKNOWN_ID(505, "Fatal Error: Unknown message id."); +static const CodeMsgPair UNSUPPORTED_VERSION(506, "Unsupported version"); +static const CodeMsgPair BAD_LENGTH(507, "Bad message length"); +static const CodeMsgPair BAD_MESSAGE(508, "Bad message"); +static const CodeMsgPair SOCKET_EXCEPTION(509, "Exception caught while reading socket - "); +static const CodeMsgPair FAIL_CREATE_SOCK(520, "Failed to create socket"); +static const CodeMsgPair SSL_FAIL(530, "SSL specific error: "); + +#endif diff --git a/vn.ib/ibapi/windows/client/VolumeCondition.cpp b/vn.ib/ibapi/windows/client/VolumeCondition.cpp new file mode 100644 index 00000000..60879b8f --- /dev/null +++ b/vn.ib/ibapi/windows/client/VolumeCondition.cpp @@ -0,0 +1,26 @@ +#include "StdAfx.h" +#include "VolumeCondition.h" +#include + +std::string VolumeCondition::valueToString() const { + std::stringstream tmp; + + tmp << m_volume; + + return tmp.str(); +} + +void VolumeCondition::valueFromString(const std::string & v) { + std::stringstream tmp; + + tmp << v; + tmp >> m_volume; +} + +int VolumeCondition::volume() { + return m_volume; +} + +void VolumeCondition::volume(int volume) { + m_volume = volume; +} diff --git a/vn.ib/ibapi/windows/client/VolumeCondition.h b/vn.ib/ibapi/windows/client/VolumeCondition.h new file mode 100644 index 00000000..345e45e2 --- /dev/null +++ b/vn.ib/ibapi/windows/client/VolumeCondition.h @@ -0,0 +1,20 @@ +#pragma once +#include "ContractCondition.h" + +class TWSAPIDLLEXP VolumeCondition : public ContractCondition { + friend OrderCondition; + + int m_volume; + +protected: + VolumeCondition() { } + + virtual std::string valueToString() const; + virtual void valueFromString(const std::string &v); + +public: + static const OrderConditionType conditionType = OrderConditionType::Volume; + + int volume(); + void volume(int volume); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/windows/client/executioncondition.cpp b/vn.ib/ibapi/windows/client/executioncondition.cpp new file mode 100644 index 00000000..6ef18d75 --- /dev/null +++ b/vn.ib/ibapi/windows/client/executioncondition.cpp @@ -0,0 +1,51 @@ +#include "StdAfx.h" +#include "executioncondition.h" +#include "EDecoder.h" +#include "EClient.h" + +const char* ExecutionCondition::readExternal(const char* ptr, const char* endPtr) { + if (!(ptr = OrderCondition::readExternal(ptr, endPtr))) + return 0; + + DECODE_FIELD(m_secType) + DECODE_FIELD(m_exchange); + DECODE_FIELD(m_symbol); + + return ptr; +} + +std::string ExecutionCondition::toString() { + return "trade occurs for " + m_symbol + " symbol on " + m_exchange + " exchange for " + m_secType + " security type"; +} + +void ExecutionCondition::writeExternal(std::ostream & msg) const { + OrderCondition::writeExternal(msg); + + ENCODE_FIELD(m_secType); + ENCODE_FIELD(m_exchange); + ENCODE_FIELD(m_symbol); +} + +std::string ExecutionCondition::exchange() { + return m_exchange; +} + +void ExecutionCondition::exchange(const std::string &exchange) { + m_exchange = exchange; +} + +std::string ExecutionCondition::secType() { + return m_secType; +} + +void ExecutionCondition::secType(const std::string &secType) { + m_secType = secType; +} + +std::string ExecutionCondition::symbol() { + return m_symbol; +} + +void ExecutionCondition::symbol(const std::string &symbol) { + m_symbol = symbol; +} diff --git a/vn.ib/ibapi/windows/client/executioncondition.h b/vn.ib/ibapi/windows/client/executioncondition.h new file mode 100644 index 00000000..bc8f427a --- /dev/null +++ b/vn.ib/ibapi/windows/client/executioncondition.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include "OrderCondition.h" + +class TWSAPIDLLEXP ExecutionCondition : public OrderCondition { + friend OrderCondition; + + std::string m_exchange; + std::string m_secType; + std::string m_symbol; + +public: + static const OrderConditionType conditionType = OrderConditionType::Execution; + +protected: + ExecutionCondition() { } + +public: + virtual const char* readExternal(const char* ptr, const char* endPtr); + virtual std::string toString(); + virtual void writeExternal(std::ostream &out) const; + + std::string exchange(); + void exchange(const std::string &exchange); + std::string secType(); + void secType(const std::string &secType); + std::string symbol(); + void symbol(const std::string &symbol); +}; \ No newline at end of file diff --git a/vn.ib/ibapi/client/res/TwsSocketClient.rc2 b/vn.ib/ibapi/windows/client/res/TwsSocketClient.rc2 similarity index 100% rename from vn.ib/ibapi/client/res/TwsSocketClient.rc2 rename to vn.ib/ibapi/windows/client/res/TwsSocketClient.rc2 diff --git a/vn.ib/ibapi/client/shared_ptr.h b/vn.ib/ibapi/windows/client/shared_ptr.h similarity index 96% rename from vn.ib/ibapi/client/shared_ptr.h rename to vn.ib/ibapi/windows/client/shared_ptr.h index 5cbe7d31..5b64e474 100644 --- a/vn.ib/ibapi/client/shared_ptr.h +++ b/vn.ib/ibapi/windows/client/shared_ptr.h @@ -91,12 +91,12 @@ public: } //封装添加 - bool operator==(const shared_ptr const & a) + bool operator==(const shared_ptr & a) { return a.get() == this->get(); } - bool operator!=(const shared_ptr const & a) + bool operator!=(const shared_ptr & a) { return a.get() != this->get(); } diff --git a/vn.ib/ibapi/windows/lib/TwsSocketClient.lib b/vn.ib/ibapi/windows/lib/TwsSocketClient.lib new file mode 100644 index 00000000..32c1442d Binary files /dev/null and b/vn.ib/ibapi/windows/lib/TwsSocketClient.lib differ diff --git a/vn.ib/ibapi/windows/ssl/EClientSocketSSL.cpp b/vn.ib/ibapi/windows/ssl/EClientSocketSSL.cpp new file mode 100644 index 00000000..cc0ff8e6 --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/EClientSocketSSL.cpp @@ -0,0 +1,470 @@ +/* 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. */ + +#include "StdAfx.h" + + +#include "../client/EPosixClientSocketPlatform.h" +#include "EClientSocketSSL.h" + +#include "../client/TwsSocketClientErrors.h" +#include "../client/EWrapper.h" +#include "../client/EDecoder.h" +#include "../client/EReaderSignal.h" +#include "EReaderSSL.h" +#include "../client/EMessage.h" + +#include +#include +#include + +const int MIN_SERVER_VER_SUPPORTED = 38; //all supported server versions are defined in EDecoder.h + +std::vector EClientSocketSSL::sslLocks(CRYPTO_num_locks()); + +void EClientSocketSSL::lockingFunc(int mode, int type, const char *file, int line) { + if (mode & CRYPTO_LOCK) + sslLocks[type].Enter(); + else + sslLocks[type].Leave(); +} + +unsigned long EClientSocketSSL::thIdFunc() { +#if defined(IB_POSIX) + return syscall(SYS_gettid); +#elif defined(IB_WIN32) + return GetCurrentThreadId(); +#else +# error "Not implemented on this platform" +#endif + +} + +/////////////////////////////////////////////////////////// +// member funcs +EClientSocketSSL::EClientSocketSSL(EWrapper *ptr, EReaderSignal *pSignal) : EClient( ptr, new ESocketSSL()) +{ + m_fd = SocketsInit() ? -1 : -2; + m_allowRedirect = false; + m_asyncEConnect = false; + m_pSignal = pSignal; + + SSL_load_error_strings(); + ERR_load_BIO_strings(); + SSL_library_init(); + CRYPTO_set_locking_callback(lockingFunc); + CRYPTO_w_lock(CRYPTO_LOCK_DYNLOCK); + CRYPTO_set_id_callback(thIdFunc); + CRYPTO_w_unlock(CRYPTO_LOCK_DYNLOCK); +} + +EClientSocketSSL::~EClientSocketSSL() +{ + if( m_fd != -2) + SocketsDestroy(); +} + +bool EClientSocketSSL::asyncEConnect() const { + return m_asyncEConnect; +} + +void EClientSocketSSL::asyncEConnect(bool val) { + m_asyncEConnect = val; +} + +bool EClientSocketSSL::eConnect( const char *host, unsigned int port, int clientId, bool extraAuth) +{ + if( m_fd == -2) { + getWrapper()->error( NO_VALID_ID, FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()); + return false; + } + + // reset errno + errno = 0; + + // already connected? + if( m_fd >= 0) { + errno = EISCONN; + getWrapper()->error( NO_VALID_ID, ALREADY_CONNECTED.code(), ALREADY_CONNECTED.msg()); + return false; + } + + // normalize host + m_hostNorm = (host && *host) ? host : "127.0.0.1"; + + // initialize host and port + setHost( m_hostNorm); + setPort( port); + + // try to connect to specified host and port + ConnState resState = CS_DISCONNECTED; + + return eConnectImpl( clientId, extraAuth, &resState); +} + +ESocketSSL *EClientSocketSSL::getTransport() { + assert(dynamic_cast(m_transport.get()) != 0); + + return static_cast(m_transport.get()); +} + +void EClientSocketSSL::ImportRootCertificatesFromWindowsCertStore() { +#if defined(IB_WIN32) + auto store = CertOpenSystemStore(0, "ROOT"); + auto osslStore = SSL_CTX_get_cert_store(m_pCTX); + + for (auto certCtx = CertEnumCertificatesInStore(store, 0); certCtx; certCtx = CertEnumCertificatesInStore(store, certCtx)) { + if (!(certCtx->dwCertEncodingType & X509_ASN_ENCODING)) + continue; + + auto pBuf = certCtx->pbCertEncoded; + auto cert = d2i_X509(0, (const unsigned char **)&pBuf, certCtx->cbCertEncoded); + + X509_STORE_add_cert(osslStore, cert); + } + + + CertCloseStore(store, 0); +#endif +} + + +bool EClientSocketSSL::eConnectImpl(int clientId, bool extraAuth, ConnState* stateOutPt) +{ + // resolve host + struct hostent* hostEnt = gethostbyname( host().c_str()); + if ( !hostEnt) { + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + // create socket + m_fd = socket(AF_INET, SOCK_STREAM, 0); + + // cannot create socket + if( m_fd < 0) { + getWrapper()->error( NO_VALID_ID, FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()); + return false; + } + + // starting to connect to server + struct sockaddr_in sa; + memset( &sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons( port()); + sa.sin_addr.s_addr = ((in_addr*)hostEnt->h_addr)->s_addr; + + // try to connect + if( (connect( m_fd, (struct sockaddr *) &sa, sizeof( sa))) < 0) { + // error connecting + SocketClose( m_fd); + m_fd = -1; + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + m_pCTX = SSL_CTX_new(SSLv23_client_method()); + + if (!m_pCTX && !handleSocketError()) + return false; + + ImportRootCertificatesFromWindowsCertStore(); + + m_pSSL = SSL_new(m_pCTX); + + if (!m_pSSL && !handleSocketError()) + return false; + + if (!SSL_set_fd(m_pSSL, m_fd) && !handleSocketError()) + return false; + + if (!SSL_connect(m_pSSL) && !handleSocketError()) + return false; + + if(SSL_get_verify_result(m_pSSL) != X509_V_OK) + { + getWrapper()->error(NO_VALID_ID, SSL_FAIL.code(), SSL_FAIL.msg() + "certificate verification failure"); + + //return false; + } + + getTransport()->fd(m_pSSL); + + // set client id + setClientId( clientId); + setExtraAuth( extraAuth); + + int res = sendConnectRequest(); + + if (res == 0 || res < 0 && !handleSocketError(res)) + return false; + + if( !isConnected()) { + if( connState() != CS_DISCONNECTED) { + assert( connState() == CS_REDIRECT); + if( stateOutPt) { + *stateOutPt = connState(); + } + eDisconnect(); + } + return false; + } + + // set socket to non-blocking state + if ( !SetSocketNonBlocking(m_fd)) { + // error setting socket to non-blocking + eDisconnect(); + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + return false; + } + + assert( connState() == CS_CONNECTED); + if( stateOutPt) { + *stateOutPt = connState(); + } + + if (!m_asyncEConnect) { + EReaderSSL reader(this, m_pSignal); + + while (m_pSignal && !m_serverVersion && isSocketOK()) { + reader.checkClient(); + m_pSignal->waitForSignal(); + reader.processMsgs(); + } + } + + // successfully connected + return isSocketOK(); +} + +void EClientSocketSSL::encodeMsgLen(std::string& msg, unsigned offset) const +{ + assert( !msg.empty()); + assert( m_useV100Plus); + + assert( sizeof(unsigned) == HEADER_LEN); + assert( msg.size() > offset + HEADER_LEN); + unsigned len = msg.size() - HEADER_LEN - offset; + if( len > MAX_MSG_LEN) { + m_pEWrapper->error( NO_VALID_ID, BAD_LENGTH.code(), BAD_LENGTH.msg()); + return; + } + + unsigned netlen = htonl( len); + memcpy( &msg[offset], &netlen, HEADER_LEN); +} + +bool EClientSocketSSL::closeAndSend(std::string msg, unsigned offset) +{ + assert( !msg.empty()); + if( m_useV100Plus) { + encodeMsgLen( msg, offset); + } + + int res = bufferedSend(msg); + + if (res < 0) + return handleSocketError(res); + + return true; +} + +void EClientSocketSSL::prepareBufferImpl(std::ostream& buf) const +{ + assert( m_useV100Plus); + assert( sizeof(unsigned) == HEADER_LEN); + + char header[HEADER_LEN] = { 0 }; + buf.write( header, sizeof(header)); +} + +void EClientSocketSSL::prepareBuffer(std::ostream& buf) const +{ + if( !m_useV100Plus) + return; + + prepareBufferImpl( buf); +} + +void EClientSocketSSL::eDisconnect() +{ + if (m_pSSL) + SSL_shutdown(m_pSSL); + + if (m_pCTX) + SSL_CTX_free(m_pCTX); + + if ( m_fd >= 0 ) + // close socket + SocketClose( m_fd); + m_fd = -1; + + eDisconnectBase(); +} + +bool EClientSocketSSL::isSocketOK() const +{ + return ( m_fd >= 0); +} + +int EClientSocketSSL::fd() const +{ + return m_fd; +} + +int EClientSocketSSL::receive(char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + int nResult = SSL_read(m_pSSL, buf, sz); + + if( nResult == -1 && !handleSocketError(nResult)) { + return -1; + } + if( nResult == 0) { + onClose(); + } + if( nResult <= 0) { + return 0; + } + return nResult; +} + +void EClientSocketSSL::serverVersion(int version, const char *time) { + m_serverVersion = version; + m_TwsTime = time; + + if( usingV100Plus() ? (m_serverVersion < MIN_CLIENT_VER || m_serverVersion > MAX_CLIENT_VER) : m_serverVersion < MIN_SERVER_VER_SUPPORTED ) { + getWrapper()->error( NO_VALID_ID, UNSUPPORTED_VERSION.code(), UNSUPPORTED_VERSION.msg()); + eDisconnect(); + } + + if (!m_asyncEConnect) + startApi(); +} + +void EClientSocketSSL::redirect(const char *host, int port) { + // handle redirect + if( (m_hostNorm != this->host() || port != this->port())) { + if (!m_allowRedirect) { + getWrapper()->error(NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + + return; + } + + eDisconnect(); + eConnectImpl( clientId(), extraAuth(), 0); + } +} + +bool EClientSocketSSL::handleSSLError(int &ret_code) { + ret_code = SSL_get_error(m_pSSL, ret_code); + + switch (ret_code) { + case SSL_ERROR_NONE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + ret_code = 0; + return true; + + case SSL_ERROR_SYSCALL: +#if defined(IB_POSIX) + ret_code = errno; +#elif defined(IB_WIN32) + ret_code = GetLastError(); +#else +# error "Not implemented on this platform" +#endif + return true; + } + + return false; +} + +bool EClientSocketSSL::handleSocketErrorInternal(int hr) { +#if defined(IB_WIN32) + if (hr != 0) { + LPTSTR buf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0, (LPTSTR)&buf, 0, 0); + getWrapper()->error( NO_VALID_ID, SOCKET_EXCEPTION.code(), + SOCKET_EXCEPTION.msg() + buf); + LocalFree(buf); + + return false; + } +#endif + + // no error + if( errno == 0) + return true; + + // Socket is already connected + if( errno == EISCONN) { + return true; + } + + if( errno == EWOULDBLOCK) + return false; + + if( errno == ECONNREFUSED) { + getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()); + } + else { + getWrapper()->error( NO_VALID_ID, SOCKET_EXCEPTION.code(), + SOCKET_EXCEPTION.msg() + strerror(errno)); + } + // reset errno + errno = 0; + eDisconnect(); + return false; +} + +bool EClientSocketSSL::handleSocketError(int res) +{ + if (!handleSSLError(res)) { + getWrapper()->error(NO_VALID_ID, SSL_FAIL.code(), SSL_FAIL.msg() + ERR_error_string(res, 0)); + + return false; + } + + return handleSocketErrorInternal(res); +} + +bool EClientSocketSSL::handleSocketError() { + int res = ERR_get_error(); + + if (res) { + getWrapper()->error(NO_VALID_ID, SSL_FAIL.code(), SSL_FAIL.msg() + ERR_error_string(res, 0)); + + return false; + } + + return handleSocketErrorInternal(); +} + +/////////////////////////////////////////////////////////// +// callbacks from socket + +void EClientSocketSSL::onSend() +{ + if( !handleSocketError()) + return; + + getTransport()->sendBufferedData(); +} + +void EClientSocketSSL::onClose() +{ + if( !handleSocketError()) + return; + + eDisconnect(); + getWrapper()->connectionClosed(); +} + +void EClientSocketSSL::onError() +{ + handleSocketError(); +} diff --git a/vn.ib/ibapi/windows/ssl/EClientSocketSSL.h b/vn.ib/ibapi/windows/ssl/EClientSocketSSL.h new file mode 100644 index 00000000..fbe87cec --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/EClientSocketSSL.h @@ -0,0 +1,81 @@ +/* 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. */ + +#pragma once +#ifndef eposixclientsocket_def +#define eposixclientsocket_def + +#include "../client/EClient.h" +#include "../client/EClientMsgSink.h" +#include "ESocketSSL.h" +#include "../client/EMutex.h" + +class EWrapper; +class EReaderSignal; + +class TWSAPISSLDLLEXP EClientSocketSSL : public EClient, public EClientMsgSink +{ +protected: + virtual void prepareBufferImpl(std::ostream&) const; + virtual void prepareBuffer(std::ostream&) const; + virtual bool closeAndSend(std::string msg, unsigned offset = 0); + +public: + + explicit EClientSocketSSL(EWrapper *ptr, EReaderSignal *pSignal = 0); + ~EClientSocketSSL(); + + bool eConnect( const char *host, unsigned int port, int clientId = 0, bool extraAuth = false); + // override virtual funcs from EClient + void eDisconnect(); + + bool isSocketOK() const; + int fd() const; + bool asyncEConnect() const; + void asyncEConnect(bool val); + ESocketSSL *getTransport(); + +private: + + bool eConnectImpl(int clientId, bool extraAuth, ConnState* stateOutPt); + +private: + void encodeMsgLen(std::string& msg, unsigned offset) const; + bool handleSSLError(int &ret_code); + bool handleSocketErrorInternal(int hr = 0); + +public: + bool handleSocketError(); + bool handleSocketError(int res); + int receive( char* buf, size_t sz); + +public: + // callback from socket + void onSend(); + void onError(); + +private: + + void onClose(); + void ImportRootCertificatesFromWindowsCertStore(); + + static void lockingFunc(int mode, int type, const char *file, int line); + static unsigned long thIdFunc(); + + static std::vector sslLocks; + + SSL *m_pSSL; + SSL_CTX *m_pCTX; + int m_fd; + bool m_allowRedirect; + const char* m_hostNorm; + bool m_asyncEConnect; + EReaderSignal *m_pSignal; + +//EClientMsgSink implementation +public: + void serverVersion(int version, const char *time); + void redirect(const char *host, int port); +}; + +#endif diff --git a/vn.ib/ibapi/windows/ssl/EReaderSSL.cpp b/vn.ib/ibapi/windows/ssl/EReaderSSL.cpp new file mode 100644 index 00000000..065be2cb --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/EReaderSSL.cpp @@ -0,0 +1,278 @@ +/* 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. */ + +#include "StdAfx.h" +#include "../client/shared_ptr.h" +#include "../client/Contract.h" +#include "../client/EDecoder.h" +#include "../client/EMutex.h" +#include "EReaderSSL.h" +#include "EClientSocketSSL.h" +#include "../client/EPosixClientSocketPlatform.h" +#include "../client/EReaderSignal.h" +#include "../client/EMessage.h" +#include "../client/DefaultEWrapper.h" + +#define IN_BUF_SIZE_DEFAULT 8192 + +static DefaultEWrapper defaultWrapper; + +EReaderSSL::EReaderSSL(EClientSocketSSL *clientSocket, EReaderSignal *signal) + : processMsgsDecoder_(clientSocket->EClient::serverVersion(), clientSocket->getWrapper(), clientSocket) + , threadReadDecoder_(clientSocket->EClient::serverVersion(), &defaultWrapper) { + m_isAlive = true; + m_pClientSocket = clientSocket; + m_pEReaderSignal = signal; + m_needsWriteSelect = false; + m_nMaxBufSize = IN_BUF_SIZE_DEFAULT; + m_buf.reserve(IN_BUF_SIZE_DEFAULT); + start(); +} + +EReaderSSL::~EReaderSSL(void) { + m_isAlive = false; + +#if defined(IB_WIN32) + WaitForSingleObject(m_hReadThread, INFINITE); +#endif +} + +void EReaderSSL::checkClient() { + m_needsWriteSelect = !m_pClientSocket->getTransport()->isOutBufferEmpty(); +} + +void EReaderSSL::start() { +#if defined(IB_POSIX) + pthread_t thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create( &thread, &attr, readToQueueThread, this ); + pthread_attr_destroy(&attr); +#elif defined(IB_WIN32) + m_hReadThread = CreateThread(0, 0, readToQueueThread, this, 0, 0); +#else +# error "Not implemented on this platform" +#endif +} + +#if defined(IB_POSIX) +void * EReaderSSL::readToQueueThread(void * lpParam) +#elif defined(IB_WIN32) +DWORD WINAPI EReaderSSL::readToQueueThread(LPVOID lpParam) +#else +# error "Not implemented on this platform" +#endif +{ + EReaderSSL *pThis = reinterpret_cast(lpParam); + + pThis->readToQueue(); + return 0; +} + +void EReaderSSL::readToQueue() { + EMessage *msg = 0; + + while (m_isAlive) { + if (m_buf.size() == 0 && !processNonBlockingSelect() && m_pClientSocket->isSocketOK()) + continue; + + if (m_pClientSocket->isSocketOK()) + msg = readSingleMsg(); + + if (msg == 0) + break; + + m_csMsgQueue.Enter(); + m_msgQueue.push_back(ibapi::shared_ptr(msg)); + m_csMsgQueue.Leave(); + m_pEReaderSignal->issueSignal(); + + msg = 0; + } + + m_pClientSocket->handleSocketError(); + m_pEReaderSignal->issueSignal(); //letting client know that socket was closed +} + +bool EReaderSSL::processNonBlockingSelect() { + fd_set readSet, writeSet, errorSet; + struct timeval tval; + + tval.tv_usec = 100 * 1000; //100 ms + tval.tv_sec = 0; + + if( m_pClientSocket->fd() >= 0 ) { + + FD_ZERO( &readSet); + errorSet = writeSet = readSet; + + FD_SET( m_pClientSocket->fd(), &readSet); + + if (m_needsWriteSelect) + FD_SET( m_pClientSocket->fd(), &writeSet); + + FD_SET( m_pClientSocket->fd(), &errorSet); + + int ret = select( m_pClientSocket->fd() + 1, &readSet, &writeSet, &errorSet, &tval); + + if( ret == 0) { // timeout + return false; + } + + if( ret < 0) { // error + m_pClientSocket->eDisconnect(); + return false; + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &errorSet)) { + // error on socket + m_pClientSocket->onError(); + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &writeSet)) { + // socket is ready for writing + onSend(); + } + + if( m_pClientSocket->fd() < 0) + return false; + + if( FD_ISSET( m_pClientSocket->fd(), &readSet)) { + // socket is ready for reading + onReceive(); + } + + return true; + } + + return false; +} + +void EReaderSSL::onSend() { + m_pEReaderSignal->issueSignal(); +} + +void EReaderSSL::onReceive() { + int nOffset = m_buf.size(); + + m_buf.resize(m_nMaxBufSize); + + int nRes = m_pClientSocket->receive(m_buf.data() + nOffset, m_buf.size() - nOffset); + + if (nRes <= 0) + return; + + m_buf.resize(nRes + nOffset); +} + +bool EReaderSSL::bufferedRead(char *buf, int size) { + while (m_buf.size() < size) + if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) + return false; + + std::copy(m_buf.begin(), m_buf.begin() + size, buf); + std::copy(m_buf.begin() + size, m_buf.end(), m_buf.begin()); + m_buf.resize(m_buf.size() - size); + + return true; +} + +EMessage * EReaderSSL::readSingleMsg() { + if (m_pClientSocket->usingV100Plus()) { + int msgSize; + + if (!bufferedRead((char *)&msgSize, sizeof(msgSize))) + return 0; + + msgSize = htonl(msgSize); + + if (msgSize <= 0 || msgSize > MAX_MSG_LEN) + return 0; + + std::vector buf = std::vector(msgSize); + + if (!bufferedRead(buf.data(), buf.size())) + return 0; + + return new EMessage(buf); + } + else { + const char *pBegin = 0; + const char *pEnd = 0; + int msgSize = 0; + + while (msgSize == 0) + { + if (m_buf.size() >= m_nMaxBufSize * 3/4) + m_nMaxBufSize *= 2; + + if (!processNonBlockingSelect() && !m_pClientSocket->isSocketOK()) + return 0; + + pBegin = m_buf.data(); + pEnd = pBegin + m_buf.size(); + msgSize = EDecoder(m_pClientSocket->EClient::serverVersion(), &defaultWrapper).parseAndProcessMsg(pBegin, pEnd); + } + + std::vector msgData(msgSize); + + if (!bufferedRead(msgData.data(), msgSize)) + return 0; + + if (m_buf.size() < IN_BUF_SIZE_DEFAULT && m_buf.capacity() > IN_BUF_SIZE_DEFAULT) + { + m_buf.resize(m_nMaxBufSize = IN_BUF_SIZE_DEFAULT); + m_buf.shrink_to_fit(); + } + + EMessage * msg = new EMessage(msgData); + + return msg; + } +} + +ibapi::shared_ptr EReaderSSL::getMsg(void) { + m_csMsgQueue.Enter(); + + if (m_msgQueue.size() == 0) { + m_csMsgQueue.Leave(); + + return ibapi::shared_ptr(); + } + + ibapi::shared_ptr msg = m_msgQueue.front(); + + m_msgQueue.pop_front(); + m_csMsgQueue.Leave(); + + return msg; +} + + +void EReaderSSL::processMsgs(void) { + m_pClientSocket->onSend(); + checkClient(); + + ibapi::shared_ptr msg = getMsg(); + + if (!msg.get()) + return; + + const char *pBegin = msg->begin(); + + while (processMsgsDecoder_.parseAndProcessMsg(pBegin, msg->end()) > 0) { + msg = getMsg(); + + if (!msg.get()) + break; + + pBegin = msg->begin(); + } +} diff --git a/vn.ib/ibapi/windows/ssl/EReaderSSL.h b/vn.ib/ibapi/windows/ssl/EReaderSSL.h new file mode 100644 index 00000000..3530527d --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/EReaderSSL.h @@ -0,0 +1,60 @@ +/* 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. */ + +#pragma once + +#include "StdAfx.h" +#include "../client/EDecoder.h" +#include "../client/EMutex.h" +#include "../client/EReaderOSSignal.h" + +class EClientSocketSSL; +class EReaderSignal; +class EMessage; + +class TWSAPISSLDLLEXP EReaderSSL +{ + EClientSocketSSL *m_pClientSocket; + EReaderSignal *m_pEReaderSignal; + EDecoder processMsgsDecoder_; + std::deque> m_msgQueue; + EMutex m_csMsgQueue; + std::vector m_buf; + EDecoder threadReadDecoder_; + bool m_needsWriteSelect; + bool m_isAlive; +#if defined(IB_WIN32) + HANDLE m_hReadThread; +#endif + int m_nMaxBufSize; + + void onReceive(); + void onSend(); + bool bufferedRead(char *buf, int size); + +public: + EReaderSSL(EClientSocketSSL *clientSocket, EReaderSignal *signal); + ~EReaderSSL(void); + +protected: + bool processNonBlockingSelect(); + ibapi::shared_ptr getMsg(void); + void readToQueue(); +#if defined(IB_POSIX) + static void * readToQueueThread(void * lpParam); +#elif defined(IB_WIN32) + static DWORD WINAPI readToQueueThread(LPVOID lpParam); +#else +# error "Not implemented on this platform" +#endif + + EMessage * readSingleMsg(); + +public: + void processMsgs(void); + void checkClient(); + +private: + void start(); +}; + diff --git a/vn.ib/ibapi/windows/ssl/ESocketSSL.cpp b/vn.ib/ibapi/windows/ssl/ESocketSSL.cpp new file mode 100644 index 00000000..535c3577 --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/ESocketSSL.cpp @@ -0,0 +1,98 @@ +#include "StdAfx.h" +#include "../client/EMessage.h" +#include "ESocketSSL.h" + +#include + +ESocketSSL::ESocketSSL() { +} + +void ESocketSSL::fd(SSL *fd) { + m_fd = fd; +} + +ESocketSSL::~ESocketSSL(void) { +} + +int ESocketSSL::send(EMessage *pMsg) { + return bufferedSend(pMsg->begin(), pMsg->end() - pMsg->begin()); +} + +int ESocketSSL::bufferedSend(const char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + if( !m_outBuffer.empty()) { + m_outBuffer.insert( m_outBuffer.end(), buf, buf + sz); + return sendBufferedData(); + } + + int nResult = send(buf, sz); + + if( nResult < (int)sz) { + int sent = (std::max)( nResult, 0); + m_outBuffer.insert( m_outBuffer.end(), buf + sent, buf + sz); + } + + return nResult; +} + +int ESocketSSL::sendBufferedData() +{ + if( m_outBuffer.empty()) + return 0; + + int nResult = send( &m_outBuffer[0], m_outBuffer.size()); + if( nResult <= 0) { + return nResult; + } + CleanupBuffer( m_outBuffer, nResult); + return nResult; +} + +int ESocketSSL::send(const char* buf, size_t sz) +{ + if( sz <= 0) + return 0; + + int nResult = ::SSL_write( m_fd, buf, sz); + + if( nResult == -1) { + return -1; + } + if( nResult <= 0) { + return 0; + } + return nResult; +} + +static const size_t BufferSizeHighMark = 1 * 1024 * 1024; // 1Mb + +void ESocketSSL::CleanupBuffer(std::vector& buffer, int processed) +{ + assert( buffer.empty() || processed <= (int)buffer.size()); + + if( buffer.empty()) + return; + + if( processed <= 0) + return; + + if( (size_t)processed == buffer.size()) { + if( buffer.capacity() >= BufferSizeHighMark) { + std::vector().swap(buffer); + } + else { + buffer.clear(); + } + } + else { + buffer.erase( buffer.begin(), buffer.begin() + processed); + } +} + +bool ESocketSSL::isOutBufferEmpty() const +{ + return m_outBuffer.empty(); +} diff --git a/vn.ib/ibapi/windows/ssl/ESocketSSL.h b/vn.ib/ibapi/windows/ssl/ESocketSSL.h new file mode 100644 index 00000000..06d1de7a --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/ESocketSSL.h @@ -0,0 +1,23 @@ +#pragma once +#include "../client/ETransport.h" + +class ESocketSSL : + public ETransport +{ + SSL *m_fd; + std::vector m_outBuffer; + + int bufferedSend(const char* buf, size_t sz); + int send(const char* buf, size_t sz); + void CleanupBuffer(std::vector& buffer, int processed); + +public: + ESocketSSL(); + ~ESocketSSL(void); + + int send(EMessage *pMsg); + bool isOutBufferEmpty() const; + int sendBufferedData(); + void fd(SSL *fd); +}; + diff --git a/vn.ib/ibapi/windows/ssl/StdAfx.cpp b/vn.ib/ibapi/windows/ssl/StdAfx.cpp new file mode 100644 index 00000000..35d31dac --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/StdAfx.cpp @@ -0,0 +1,4 @@ +/* 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. */ + +#include "StdAfx.h" diff --git a/vn.ib/ibapi/windows/ssl/StdAfx.h b/vn.ib/ibapi/windows/ssl/StdAfx.h new file mode 100644 index 00000000..a89d4077 --- /dev/null +++ b/vn.ib/ibapi/windows/ssl/StdAfx.h @@ -0,0 +1,44 @@ +/* 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. */ + +#ifdef _MSC_VER + +#ifdef TWSAPISSLDLL +# define TWSAPISSLDLLEXP __declspec(dllexport) +#endif + +#define assert ASSERT +#define snprintf _snprintf +#include +#include +#define IB_WIN32 + +#else + +#include // defines _POSIX_THREADS, @see http://bit.ly/1pWJ8KQ#tag_13_80_03_02 +#include +#include + +#if defined(_POSIX_THREADS) && (_POSIX_THREADS > 0) + #include + #define IB_POSIX +#else + #error "Not supported on this platform" +#endif + +#endif // #ifdef _MSC_VER + +#include +#include +#include +#include +#include +#include +#include + +#ifndef TWSAPISSLDLLEXP +#define TWSAPISSLDLLEXP +#endif +#ifndef TWSAPIDLLEXP +#define TWSAPIDLLEXP +#endif diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.def b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.def similarity index 100% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.def rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.def diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.rc b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.rc similarity index 95% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.rc rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.rc index 5688c427..44988450 100644 --- a/vn.ib/ibapi/ssl/TwsSocketClientSSL.rc +++ b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.rc @@ -67,8 +67,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 9,72,16,0 - PRODUCTVERSION 9,72,16,0 + FILEVERSION 9,72,18,0 + PRODUCTVERSION 9,72,18,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -85,12 +85,12 @@ BEGIN BEGIN VALUE "CompanyName", "Interactive Brokers" VALUE "FileDescription", "TwsSocketClientSSL DLL" - VALUE "FileVersion", "9.72.16" + VALUE "FileVersion", "9.72.18" VALUE "InternalName", "TwsSocketClientSSL" VALUE "LegalCopyright", "Copyright (C) 2006" VALUE "OriginalFilename", "TwsSocketClientSSL.DLL" VALUE "ProductName", "TwsSocketClientSSL Dynamic Link Library" - VALUE "ProductVersion", "9.72.16" + VALUE "ProductVersion", "9.72.18" END END BLOCK "VarFileInfo" diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.sln b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.sln similarity index 100% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.sln rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.sln diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj similarity index 100% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj.filters b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj.filters similarity index 100% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj.filters rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj.filters diff --git a/vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj.user b/vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj.user similarity index 100% rename from vn.ib/ibapi/ssl/TwsSocketClientSSL.vcxproj.user rename to vn.ib/ibapi/windows/ssl/TwsSocketClientSSL.vcxproj.user diff --git a/vn.ib/ibapi/ssl/res/TwsSocketClientSSL.rc2 b/vn.ib/ibapi/windows/ssl/res/TwsSocketClientSSL.rc2 similarity index 100% rename from vn.ib/ibapi/ssl/res/TwsSocketClientSSL.rc2 rename to vn.ib/ibapi/windows/ssl/res/TwsSocketClientSSL.rc2 diff --git a/vn.ib/test/test.py b/vn.ib/test/test.py index 883a7c02..6f4ab062 100644 --- a/vn.ib/test/test.py +++ b/vn.ib/test/test.py @@ -291,6 +291,11 @@ class TestApi(IbApi): print sys._getframe().f_code.co_name print locals() + #---------------------------------------------------------------------- + def softDollarTiers(self, reqId, tiers): + print sys._getframe().f_code.co_name + print locals() + if __name__ == '__main__': diff --git a/vn.ib/test/vnib.pyd b/vn.ib/test/vnib.pyd index 83df9317..e3ff25d8 100644 Binary files a/vn.ib/test/vnib.pyd and b/vn.ib/test/vnib.pyd differ diff --git a/vn.ib/vnib/Visual Studio 2013/settings/Windows Azure Subscriptions.xml b/vn.ib/vnib/Visual Studio 2013/settings/Windows Azure Subscriptions.xml index 73a800e4..5d668f3b 100644 --- a/vn.ib/vnib/Visual Studio 2013/settings/Windows Azure Subscriptions.xml +++ b/vn.ib/vnib/Visual Studio 2013/settings/Windows Azure Subscriptions.xml @@ -1,5 +1,5 @@ - AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAhuIZgFnYcU6wvp5DI4FozAAAAAACAAAAAAAQZgAAAAEAACAAAADnrYSEO5qfCQPpiUFTIS3ZRFiTItrg4/VIVOH2J3epYgAAAAAOgAAAAAIAACAAAACso6CSyxkad28kFe3eIz1YgltVz/YV200C+PLOhtmmPhAAAABBWAXXnj8W8KUy+QlVKF7JQAAAAFuRLjt27YOpR9+kkpnrDzww07fBW08hBX6gGDrJVJp/hGhDL4nX/wEgsPuN/EJB4f48rrPnGlHmfb6B9a0Il60= + AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAhuIZgFnYcU6wvp5DI4FozAAAAAACAAAAAAAQZgAAAAEAACAAAABSecZ3XkHz1XFYc0nCk5Yiz9Qe6FbTHXXa1BTG6vCZOwAAAAAOgAAAAAIAACAAAAAAtzvgNjp1LEEdupcL4nO9bua8wJolOEbWc5wAG28QMhAAAABhsBhGxU9U551VeMJ5xwKVQAAAAIZXA4STAiZ4xXT9jqMpGhDeYI6VmzvdRa64Ot83fkOMW1JHpm9h2dFZCuwr5wnnETH4pdxZhrEmKeEzXstiRjE= \ No newline at end of file diff --git a/vn.ib/vnib/vnib/vnib.cpp b/vn.ib/vnib/vnib/vnib.cpp index 05a0feaa..261aeba0 100644 --- a/vn.ib/vnib/vnib/vnib.cpp +++ b/vn.ib/vnib/vnib/vnib.cpp @@ -352,6 +352,11 @@ void IbWrapper::securityDefinitionOptionalParameterEnd(int reqId) this->api->securityDefinitionOptionalParameterEnd(reqId); }; +void IbWrapper::softDollarTiers(int reqId, const std::vector &tiers) +{ + PyLock lock; + this->api->softDollarTiers(reqId, tiers); +}; ///------------------------------------------------------------------------------------- ///processMsgs̹߳ @@ -665,6 +670,10 @@ void VnIbApi::reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, this->client->reqSecDefOptParams(reqId, underlyingSymbol, futFopExchange, underlyingSecType, underlyingConId); }; +void VnIbApi::reqSoftDollarTiers(int reqId) +{ + this->client->reqSoftDollarTiers(reqId); +}; ///------------------------------------------------------------------------------------- ///Boost.Pythonװ @@ -1334,6 +1343,18 @@ struct IbApiWrap : VnIbApi, wrapper < VnIbApi > } }; + + virtual void softDollarTiers(int reqId, const std::vector &tiers) + { + try + { + this->get_override("softDollarTiers")(reqId, tiers); + } + catch (error_already_set const &) + { + PyErr_Print(); + } + }; }; @@ -1419,6 +1440,7 @@ BOOST_PYTHON_MODULE(vnib) .def("reqAccountUpdatessMulti", &IbApiWrap::reqAccountUpdatessMulti) .def("cancelAccountUpdatesMulti", &IbApiWrap::cancelAccountUpdatesMulti) .def("reqSecDefOptParams", &IbApiWrap::reqSecDefOptParams) + .def("reqSoftDollarTiers", &IbApiWrap::reqSoftDollarTiers) .def("tickPrice", pure_virtual(&IbApiWrap::tickPrice)) .def("tickSize", pure_virtual(&IbApiWrap::tickSize)) @@ -1475,6 +1497,7 @@ BOOST_PYTHON_MODULE(vnib) .def("accountUpdateMultiEnd", pure_virtual(&IbApiWrap::accountUpdateMultiEnd)) .def("securityDefinitionOptionalParameter", pure_virtual(&IbApiWrap::securityDefinitionOptionalParameter)) .def("securityDefinitionOptionalParameterEnd", pure_virtual(&IbApiWrap::securityDefinitionOptionalParameterEnd)) + .def("softDollarTiers", pure_virtual(&IbApiWrap::softDollarTiers)) ; //ṹصķװ @@ -1756,6 +1779,12 @@ BOOST_PYTHON_MODULE(vnib) .def_readwrite("extOperator", &Order::extOperator) ; + class_("SoftDollarTier") + .def("name", &SoftDollarTier::name) + .def("val", &SoftDollarTier::val) + .def("displayName", &SoftDollarTier::displayName) + ; + //vectorصķװ class_("TagValueList") .def(vector_indexing_suite()); //truedzҪ @@ -1778,6 +1807,9 @@ BOOST_PYTHON_MODULE(vnib) class_>("DoubleList") .def(vector_indexing_suite, true>()); + class_>("SoftDollarTierList") + .def(vector_indexing_suite, true>()); + //enumصķװ enum_("OrderConditionType") .value("Price", OrderCondition::Price) diff --git a/vn.ib/vnib/vnib/vnib.h b/vn.ib/vnib/vnib/vnib.h index e79b482d..d3ea9f9f 100644 --- a/vn.ib/vnib/vnib/vnib.h +++ b/vn.ib/vnib/vnib/vnib.h @@ -219,6 +219,8 @@ public: const std::string& multiplier, std::set expirations, std::set strikes); void securityDefinitionOptionalParameterEnd(int reqId); + + void softDollarTiers(int reqId, const std::vector &tiers); }; @@ -317,9 +319,9 @@ public: virtual void contractDetailsEnd(int reqId){}; - virtual void execDetails(int reqId, const Contract& contract, const Execution& execution) = 0{}; + virtual void execDetails(int reqId, const Contract& contract, const Execution& execution){}; - virtual void execDetailsEnd(int reqId) = 0{}; + virtual void execDetailsEnd(int reqId){}; virtual void updateMktDepth(TickerId id, int position, int operation, int side, double price, int size){}; @@ -391,6 +393,8 @@ public: virtual void securityDefinitionOptionalParameterEnd(int reqId){}; + virtual void softDollarTiers(int reqId, const std::vector &tiers){}; + //------------------------------------------------------------------------------------- //主动函数 //------------------------------------------------------------------------------------- @@ -514,4 +518,6 @@ public: void reqSecDefOptParams(int reqId, const std::string& underlyingSymbol, const std::string& futFopExchange, const std::string& underlyingSecType, int underlyingConId); + + void reqSoftDollarTiers(int reqId); }; diff --git a/vn.ib/vnib/vnib/vnib.vcxproj b/vn.ib/vnib/vnib/vnib.vcxproj index 02819820..25aef65b 100644 --- a/vn.ib/vnib/vnib/vnib.vcxproj +++ b/vn.ib/vnib/vnib/vnib.vcxproj @@ -41,8 +41,8 @@ .pyd - D:\boost_1_57_0;D:\Anaconda2\include;X:\GithubProject\vnpy\vn.ib\ibapi\client;$(IncludePath) - X:\GithubProject\vnpy\vn.ib\ibapi;D:\Anaconda2\libs;D:\boost_1_57_0\libs;$(ReferencePath) + D:\boost_1_57_0;D:\Anaconda2\include;X:\GithubProject\vnpy\vn.ib\ibapi\windows\client;$(IncludePath) + X:\GithubProject\vnpy\vn.ib\ibapi\windows;D:\Anaconda2\libs;D:\boost_1_57_0\libs;$(ReferencePath) @@ -69,70 +69,72 @@ true true true - X:\GithubProject\vnpy\vn.ib\ibapi\lib;D:\boost_1_57_0\stage\lib;D:\Anaconda2\libs;%(AdditionalLibraryDirectories) + X:\GithubProject\vnpy\vn.ib\ibapi\windows\lib;D:\boost_1_57_0\stage\lib;D:\Anaconda2\libs;%(AdditionalLibraryDirectories) - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vn.ib/vnib/vnib/vnib.vcxproj.filters b/vn.ib/vnib/vnib/vnib.vcxproj.filters index 5262e581..cde717c6 100644 --- a/vn.ib/vnib/vnib/vnib.vcxproj.filters +++ b/vn.ib/vnib/vnib/vnib.vcxproj.filters @@ -24,64 +24,67 @@ Source Files - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + Source Files\ib - + + Source Files\ib + + Source Files\ib @@ -89,115 +92,118 @@ Header Files - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + Header Files\ib - + + Header Files\ib + + Header Files\ib diff --git a/vn.trader/ibGateway/ibGateway.py b/vn.trader/ibGateway/ibGateway.py index 0cb6aba4..b51292c9 100644 --- a/vn.trader/ibGateway/ibGateway.py +++ b/vn.trader/ibGateway/ibGateway.py @@ -717,4 +717,9 @@ class IbWrapper(IbApi): def securityDefinitionOptionalParameterEnd(self, reqId): """""" pass + + #---------------------------------------------------------------------- + def softDollarTiers(self, reqId, tiers): + """""" + pass \ No newline at end of file diff --git a/vn.trader/ibGateway/vnib.pyd b/vn.trader/ibGateway/vnib.pyd index 934fef61..e3ff25d8 100644 Binary files a/vn.trader/ibGateway/vnib.pyd and b/vn.trader/ibGateway/vnib.pyd differ