Skip to content

Commit

Permalink
Add startApi() to create the API connection
Browse files Browse the repository at this point in the history
The handshake between the server and client changed somewhere between
version 47 and 63. Now it needs a START_API message after the client
and server versions have been established.

The server responds to the START_API message with
  1. a managed account message,
  2. a next valid ID, and
  3. messages with the status of the data farms

Soren did not store the server response, so this commit does not
recreate his PR verbatim. One major difference: this change does not
remove the ewrapper, so the next valid ID is still stored in the
ewrapper environment instead of the global environment (as it does in
Soren's PR).

See #19, see #9.
  • Loading branch information
joshuaulrich committed Sep 19, 2019
1 parent d098292 commit 77f4b04
Showing 1 changed file with 42 additions and 12 deletions.
54 changes: 42 additions & 12 deletions R/twsConnect.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ twsConnect <- twsConnect2 <- function(clientId=1, host="localhost",
port=7496, verbose=TRUE,
timeout=5, filename=NULL,
blocking=.Platform$OS.type=="windows") {
startApi <- function(conn, clientId) {
if (!is.twsConnection(conn)) {
stop("requires twsConnection object")
}
con <- conn[[1]]
VERSION <- "1"
START_API <- "71"
writeBin(START_API, con)
writeBin(VERSION, con)
writeBin(as.character(clientId), con)
}

if(is.null(getOption('digits.secs')))
options(digits.secs=6)

Expand All @@ -27,17 +39,18 @@ twsConnect <- twsConnect2 <- function(clientId=1, host="localhost",
}
CLIENT_VERSION <- "63"

writeBin(c(CLIENT_VERSION,as.character(clientId)), s)
writeBin(CLIENT_VERSION, s)

eW <- eWrapper(NULL)
eW$.Data <- environment()
SERVER_VERSION <- NEXT_VALID_ID <- NULL
SERVER_VERSION <- NEXT_VALID_ID <- CONNECTION_TIME <- NULL
eW$nextValidId <- function(curMsg, msg, timestamp, file, ...) {
eW$.Data$NEXT_VALID_ID <- msg[2]
}

# server version and connection time
while(TRUE) {
if( !is.null(NEXT_VALID_ID))
if( !is.null(CONNECTION_TIME))
break
if( !socketSelect(list(s), FALSE, 0.1))
next
Expand All @@ -49,15 +62,6 @@ twsConnect <- twsConnect2 <- function(clientId=1, host="localhost",
next
}

if(curMsg == .twsIncomingMSG$ERR_MSG) {
errMsg <- readBin(s, character(), 4)
close(s)
on.exit()
return( twsConnect(clientId+1, host, port, verbose, timeout, filename, blocking) )
}

processMsg(curMsg, s, eW, NULL, "")

if(Sys.time()-start.time > timeout) {
close(s)
stop('tws connection timed-out')
Expand All @@ -74,6 +78,32 @@ twsConnect <- twsConnect2 <- function(clientId=1, host="localhost",
twsconn$connected.at <- CONNECTION_TIME
twsconn$connected <- NULL # not yet used
class(twsconn) <- c("twsconn","environment")

# set the clientId (needs an API call now)
startApi(twsconn, clientId)

# server responds with:
# 1) managed account message
# 2) next valid id
# 3) status messages about data farms (market and time)
# these are 'errors', but the id is -1
while(TRUE) {
if(socketSelect(list(s), FALSE, 0.1)) {
curMsg <- readBin(s, character(), 1)
if(curMsg == .twsIncomingMSG$MANAGED_ACCTS) {
processMsg(curMsg, s, eW, NULL, "")
} else
if(curMsg == .twsIncomingMSG$NEXT_VALID_ID) {
twsconn$nextValidId <- processMsg(curMsg, s, eW, NULL, "")
} else
if(curMsg == .twsIncomingMSG$ERR_MSG) {
processMsg(curMsg, s, eW, NULL, "")
}
} else {
break
}
}

return(twsconn)
} else {
#file is defined - not a real connection
Expand Down

0 comments on commit 77f4b04

Please sign in to comment.