vnpy/vn.ib/ibapi/linux/client/EClient.cpp

2847 lines
74 KiB
C++

/* 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 <sstream>
#include <iomanip>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <assert.h>
using namespace ibapi::client_constants;
///////////////////////////////////////////////////////////
// encoders
template<class T>
void EClient::EncodeField(std::ostream& os, T value)
{
os << value << '\0';
}
template<>
void EClient::EncodeField<const char*>(std::ostream& os, const char* str)
{
os << str << '\0';
}
template<>
void EClient::EncodeField<bool>(std::ostream& os, bool boolValue)
{
EncodeField<int>(os, boolValue ? 1 : 0);
}
template<>
void EClient::EncodeField<double>(std::ostream& os, double doubleValue)
{
char str[128];
snprintf(str, sizeof(str), "%.10g", doubleValue);
EncodeField<const char*>(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<char>(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:
// <account_code1>/<number_shares1>,<account_code2>/<number_shares2>,...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<OrderCondition> 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();
}