Nothing
## Given a symbol, conId (chr or numeric), twsInstrument, instrument,
## instrument name, or twsContract, these functions will create a
## twsInstrument with as much information as can be found.
#implemented: STK,OPT,FUT,CASH,IND
#not implemented: FOP
#---------------------------------------------------#
# FinancialInstrument.type | twsContract.sectype #
# stock | STK #
# synthetic | IND #
# option_series | OPT #
# future_series | FUT #
# exchange_rate | CASH #
#---------------------------------------------------#
#' @export
#' @rdname buildIBcontract
is.twsInstrument <- function(x) {
if (inherits(x, 'twsInstrument')) {
TRUE
} else if (inherits(x, 'instrument') &&
!is.null(x$IB) &&
inherits(x$IB, 'twsContract') ) {
TRUE
} else FALSE
}
#Any of these will create a twsInstrument object
#' @export
#' @rdname buildIBcontract
Contr_From_Instr <- function(instrument, tws=NULL,
addIBslot=FALSE, updateInstrument=FALSE,
output=c('contract','symbol','nothing','instrument'),
include_expired="0", assign_i=FALSE, assign_c=TRUE, verbose=TRUE, silent=FALSE)
{
if (is.numeric(output))
output <- c('contract','symbol','nothing','instrument')[output]
buildIBcontract(symbol=instrument, tws=tws, addIBslot=addIBslot,
updateInstrument=updateInstrument, output=output[1],
include_expired=include_expired,
assign_i=assign_i, assign_c=assign_c, verbose=verbose, silent=silent)
}
#' @export
#' @rdname buildIBcontract
Instr_From_Contr<- function(contract, tws=NULL,
addIBslot=FALSE, updateInstrument=TRUE,
output=c('instrument','symbol','nothing','contract'),
include_expired="0", assign_i=FALSE, assign_c=TRUE, verbose=TRUE, silent=FALSE)
{
if (is.numeric(output))
output=c('instrument','symbol','nothing','contract')[output]
buildIBcontract(symbol=contract, tws=tws, addIBslot=addIBslot,
updateInstrument=updateInstrument, output=output[1],
include_expired=include_expired,
assign_i=assign_i, assign_c=assign_c, verbose=verbose, silent=silent)
}
#' @export
#' @rdname buildIBcontract
twsInstrument <- function(symbol, tws=NULL,
addIBslot=TRUE, updateInstrument=TRUE,
output=c('symbol','nothing','instrument','contract'),
include_expired="0", assign_i=TRUE, assign_c=TRUE, verbose=TRUE, silent=FALSE)
{
if (is.numeric(output))
output <- c('nothing','symbol','instrument','contract')[output]
buildIBcontract(symbol=symbol, tws=tws, addIBslot=addIBslot,
updateInstrument=updateInstrument, output=output,
include_expired=include_expired,
assign_i=assign_i, assign_c=assign_c, verbose=verbose, silent=silent)
}
#' buildIBcontract and wrappers
#'
#' create twsInstrument, or create twsContracts using previously defined
#' FinancialInstruments, or create FinancialInstruments from previously defined
#' twsContract
#'
#' see ?\sQuote{twsInstrument-package} for \code{\link{twsInstrument-package}} help page.
#'
#' Using metadata that has already been defined for an instrument, create a
#' twsContract object and fill in any missing information. Can either add an IB
#' slot to the instrument, or update the entire instrument creating slots as
#' needed.
#'
#' buildIBcontract is the main function; the rest are wrappers.
#'
#' symbol can be the name of an instrument, an instrument, a twsContract,
#' twsInstrument or a conId (unique numeric contract identifier used by
#' Interactive Brokers). Using the information given, it will create an
#' instrument and a twsContract. It will then make a call to
#' reqContractDetails to fill in any missing information. (If you give it a
#' string and there is no instrument by that name, then: (a) If the string ends
#' in a period, it will treat it as a currency pair using "USD" as the base
#' currency. (b) if the string can be coerced to numeric, it will be used as
#' the conId in a call to \code{\link{getContract}} (which in turn calls
#' \code{\link{reqContractDetails}} to get a twsContract object. (c)
#' Otherwise, it will be passed to \code{\link{instrument.auto}} which will try
#' to create an instrument that can be updated. If the string is something
#' other than the name of a \code{FUT}, \code{OPT}, or \code{CASH} -- for
#' example, if it is the name of a \code{STK} or \code{IND} -- it will be
#' assumed that it is a \code{STK}. If the request for contract details fails,
#' it will be tried again as an \code{IND} (Note that if you want an index, but
#' request a stock, it is more likely that you will get a stock of a different
#' currency than that the request will fail. Therefore, you should always
#' define your instruments first. Wrapping the symbol with something like
#' \code{synthetic('SPX','USD')} or \code{stock('SPY','USD')} will ensure that
#' you get the \code{sectype} of \code{twsContract} you are after).
#'
#' if addIBslot is TRUE it will store the contract in the IB slot of the
#' instrument (creating the slot if necessary.) If updateInstrument is TRUE it
#' will add/replace information directly in the instrument object.
#'
#' It is recommended that you do not pass it a twsconn object, in which case it
#' will create a temporary one. If you pass it a twsconn object you are more
#' likely to encounter errors. If you pass a connected twsconn object it will
#' be disconnected after the request.
#'
#' twsInstrument is a wrapper that will create a twsInstrument classed object.
#' By default, It creates a twsContract and an instrument (if necessary) and
#' places the twsContract in the IB slot of the instrument. The twsInstrument
#' class is automatically added to any instrument that has an IB slot.
#'
#' Instr_From_Contr is a wrapper to create an instrument using a twsContract.
#' It does not create an IB slot or store the twsContract in the instrument by
#' default, and therefore does not add the twsInstrument class to the
#' instrument.
#'
#' Contr_From_Instr is a wrapper to create a twsContract using an instrument.
#' By default, it does not make any changes to the instrument, and therefore
#' does not add the twsInstrument class to it.
#'
#' Instr_From_Contr and Contr_From_Instr are essentially the same functions,
#' but with different default outputs.
#'
#' \code{ouput} should be a character string describing what to return. Valid
#' values are c(\sQuote{"nothing}, \sQuote{symbol}, \sQuote{instrument},
#' \sQuote{contract}
#'
#' @aliases buildIBcontract twsInstrument Instr_From_Contr Contr_From_Instr
#' is.twsInstrument
#' @param symbol An instrument, The name of an instrument, a twsContract, or a
#' conId.
#' @param tws twsconn object. Not required.
#' @param addIBslot Boolean. Should an IB slot be created in the instrument
#' object?)
#' @param updateInstrument Should all the attributes of the instrument be
#' updated with the information retrieved from IB?
#' @param output what should be returned. one of
#' 'nothing','symbol','instrument','contract'
#' @param include_expired is the requested contract expired?
#' @param assign_i boolean. Should the instrument be stored in the instrument
#' environment?
#' @param assign_c boolean. If a currency isn't defined, should it be?
#' @param verbose be verbose?
#' @param silent silence warnings?
#' @param instrument for wrapper, alias for symbol
#' @param contract for wrapper, alias for symbol
#' @param x what to test for is.twsInstrument
#' @return Usually called for its side-effect. It will return what is defined
#' by the output argument. See details.
#' @author Garrett See
#' @seealso instrument, twsContract, addIBslot,
#' @examples
#'
#'
#' \dontrun{
#'
#' twsInstrument('SPY') #assumes it's a stock
#'
#' #Now something that isn't denominated in USD
#' twsInstrument(twsFUT(symbol='NIY',exch='GLOBEX',expiry='201109',
#' currency='JPY'))
#'
#' #As a wrapper for instrument wrappers
#' Contr_From_Instr(synthetic('SPX','USD'))
#' Instr_From_Contr(twsFUT(symbol='ES',exch='GLOBEX',expiry='201112', currency='USD'))
#'
#' buildIBcontract(twsSTK("GOOG"),updateInstrument=TRUE, addIBslot=FALSE, output='nothing')
#'
#' stock('AAPL','USD')
#' buildIBcontract('AAPL', updateInstrument=FALSE) #uses instrument
#'
#' ls_instruments()
#'
#' }
#' @export
#' @rdname buildIBcontract
buildIBcontract <- function(symbol, tws=NULL,
addIBslot=FALSE, updateInstrument=FALSE,
output=c('contract','instrument','symbol','nothing'),
include_expired="0", assign_i=FALSE, assign_c=TRUE, verbose=TRUE, silent=FALSE)
{
#TODO: Allow for vector of symbols, instruments, or contracts
if (is.xts(symbol)) stop('symbol can be the name of an xts object, but not the object itself.')
if (inherits(symbol, 'twsContractDetails')) symbol <- getContract(symbol) #TODO: give user the option to not reqContractDetails again.
if (!is.list(symbol) && (is.numeric(symbol) || !is.na(suppressWarnings(as.numeric(symbol))))) symbol <- getContract(symbol)
primary_id <- NULL
right <- NULL
contract <- NULL
instr <- NULL
ambiguous <- FALSE #Is it unclear what type of instrument/contract we're making
if (is.twsContract(symbol)){ #then make an instr
#also create instrument (but it will only be assigned if updateInstrument==TRUE) &| assign_i==TRUE
#need at least primary_id, currency, multiplier, tick_size, identifiers, type
contract <- symbol
symbol <- contract$symbol
#make sure the currency is defined for this product
tmpccy <- try(getInstrument(contract$currency, silent=TRUE),silent=TRUE)
if (inherits(tmpccy, 'try-error') || !is.instrument(tmpccy) ) {
if (assign_c) {
currency(contract$currency)
if (!silent) warning(paste("Creating currency ", contract$currency))
} else stop (paste(contract$currency, 'cannot be found, and assign_c=FALSE'))
}
#primary_id <- symbol
identifiers <- list(conId=contract$conId, local=gsub(" ","",contract$local))
identifiers <- identifiers[!identifiers %in% c("0","")]
instr <- switch(contract$sectype,
IND={
primary_id <- contract$symbol
instrument.tws(primary_id=primary_id, exchange=contract$exch, currency=contract$currency, multiplier=1,
tick_size=NULL, identifiers=identifiers, type='synthetic', assign_i=FALSE)
},
STK={
primary_id <- contract$symbol
#stock(primary_id=primary_id, currency=contract$currency, exchange=contract$exchange)
instrument.tws(primary_id=primary_id, currency=contract$currency,multiplier=1,
tick_size=0.01, identifiers=identifiers, type='stock', assign_i=FALSE)
},
OPT={
# primary_id <- paste('.', contract$symbol,sep="")
if (!is.null(contract$local) && contract$local != "") {
ylocal <- gsub(" ","",contract$local)#take out the triple space
si <- gsub(contract$symbol,"",ylocal) #suffix_id
#id <- paste(primary_id,suffix_id,sep="_")
expiry <- substr(si,1,6)
right <- substr(si,7,7)
strike <- as.numeric(substr(si,8,15))/1000
#local <- paste(symbol, si, sep=" ")
primary_id <- paste(contract$symbol, "_", expiry, right, strike, sep="")
} else {
if (any(nchar(contract$expiry) == c(6,8))) {
m <- substr(contract$expiry,5,6)
y <- substr(contract$expiry,1,4)
} else if (!identical(integer(0),grep('-',contract$expiry))) {
ss <- strsplit(contract$expiry,"-")[[1]]
m <- ss[2]
y <- ss[1]
}
expiry <- paste(y,sprintf("%02d",as.numeric(m)),sep="")
right <- contract$right
strike <- contract$strike
primary_id <- option_id(underlying_id=contract$symbol, strike=strike,
month=m, year=y, right=right)
}
callput <- switch(right, C=,c=,call='call', P=,p=,put='put')
#option(primary_id=primary_id, currency=contract$currency,
# multiplier=contract$multiplier, expires=contract$expiry, right=contract$right,
# strike=contract$strike, exchange=contract$exchange, underlying_id=contract$symbol)
instrument.tws(primary_id=primary_id, currency=contract$currency,
multiplier=as.numeric(contract$multiplier), tick_size=NULL,
identifiers=identifiers, expires=contract$expiry, right=right, callput=callput,
strike=contract$strike, exchange=contract$exch, type=c('option_series','option'),
underlying_id=contract$symbol, assign_i=FALSE)
},
FUT={
primary_id <- symbol
instrument.tws(primary_id=primary_id, currency=contract$currency,
multiplier=as.numeric(contract$multiplier), tick_size=NULL,
identifiers=identifiers, expires=contract$expiry,
exchange=contract$exch, type=c('future_series','future'),
underlying_id=contract$symbol, assign_i=FALSE) #maybe shouldn't specify exchange here
},
CASH={
if (contract$local == "") {
primary_id <- paste(contract$symbol, contract$currency, sep="") #will be contract$local after update
} else primary_id <- contract$local
#exchange_rate(primary_id=primary_id, currency=contract$currency, second_currency=contract$symbol)
instrument.tws(primary_id=primary_id, currency=contract$currency, multiplier=1,
tick_size=0.01, identifiers=identifiers, counter_currency=contract$symbol,
type=c("exchange_rate","currency"), assign_i=FALSE)
#currency(primary_id=contract$symbol, currency=contract$currency, exchange=contract$exch, type='currency')
}) #End switch on sectype
#TODO: Implement for bonds and other instruments
#if (updateInstrument==FALSE) warning(paste('Created ', primary_id, ' instrument because it could not be found.',sep=''))
} #End if (is.twsContract(symbol))
#If it was a twsContract, we
#(1) copied it to a temporary contract (contract)
#(2) figured out the symbol, and primary_id
#(3) built a temporary instrument (instr)
if (is.instrument(symbol)) { #assign to instr, and redefine symbol
instr <- symbol
primary_id <- instr$primary_id #TODO: check for suffix_id
if (!is.null(instr$underlying_id)) {
symbol <- instr$underlying_id
} else if (!is.null(instr$counter_currency)) {
symbol <- instr$counter_currency
} else symbol <- instr$primary_id
#if it was an instrument, we copied it to instr, figured out the primary_id, and the symbol
} else if (!is.twsContract(symbol)) {
#not an instrument or contract
#(if it was initially a twsContract or instrument,
#symbol has been overwritten with symbol name)
if (length(symbol) > 1) {
#TODO: allow for vector of symbols, instruments, twsContracts, or twsInstruments
#TODO2: allow for named lists.
stop('symbol must be an instrument, twsInstrument, twsContract, or the name of an instrument')
} else {
#we'll get here if the symbol argument given was a string (e.g. "SPY") or a twsContract
if (is.null(primary_id)) { #i.e. if it wasn't a twsContract
#if it has a space, it's probably a B-share
#e.g. primary_id of "BRK B" would be "BRKb"
tmpss <- strsplit(symbol, " ")[[1]]
primary_id <- if (length(tmpss) == 2) {
paste(tmpss[1], tolower(tmpss[2]), sep="")
} else primary_id <- make.names(symbol)
}
if (is.null(instr) && length(primary_id) ==1 ) {
#instr will be null if we were given a string.
instr <- try(getInstrument(primary_id,silent=TRUE),silent=TRUE)
}
}
}
####
#Now unless we were given a string, we have value for symbol, primary_id, instr, and contract.
#if it was a string, we only have primary_id, and probably have instr
#(if we got instr from a string, it may not have succeeded. we'll check for that next.)
if (inherits(instr,'try-error') || !is.instrument(instr)) {
#TODO: allow for EUR/USD format also.
pid <- parse_id(symbol)
if ( (nchar(symbol) == 6 ) && any(pid$type == 'root') && !identical(integer(0), grep(symbol, toupper(symbol))) ) { #6 letters, all uppercase
ccys <- c(substr(symbol, 1, 3),substr(symbol,4,6))
contract <- twsCASH(ccys[1], ccys[2])
primary_id=paste(contract$symbol, contract$currency, sep="") #consistent with blotter, but I think it should be sep="."
instr <- instrument.tws(primary_id=primary_id,
currency=contract$currency,
multiplier=1,
tick_size=0.01,
identifiers=NULL,
counter_currency=contract$symbol,
type=c("exchange_rate","currency"), assign_i=FALSE)
} else if (!identical(grep('\\.',symbol), integer(0)) && nchar(symbol) == 7) {
#if it has 7 characters and one of them is a period, treat it as an FX pair (e.g. EUR.USD)
ccys <- strsplit(symbol, "\\.")[[1]]
contract <- twsCASH(ccys[1], ccys[2])
primary_id=paste(contract$symbol, contract$currency, sep="") #consistent with blotter, but I think it should be sep="."
instr <- instrument.tws(primary_id=primary_id,
currency=contract$currency,
multiplier=1,
tick_size=0.01,
identifiers=NULL,
counter_currency=contract$symbol,
type=c("exchange_rate","currency"), assign_i=FALSE)
} else if (nchar(symbol) == 4 && substr(symbol,4,4) == "." ) {
contract <-twsCASH(substr(symbol,1,3))
#instr <- Instr_From_Contr(contract)
primary_id=paste(contract$symbol, contract$currency, sep="") #consistent with blotter, but I think it should be sep="."
instr <- instrument.tws(primary_id=primary_id,
currency=contract$currency,
multiplier=1,
tick_size=0.01,
identifiers=NULL,
counter_currency=contract$symbol,
type=c("exchange_rate","currency"), assign_i=FALSE)
} else {
#warning(paste("Unable to find or infer instrument, ",
# symbol, ".\n Trying with type = \"stock\"", sep=""))
ccys <- ls_currencies()
instr <- instrument.auto(primary_id=primary_id, silent=TRUE, assign_i=FALSE)
ccys <- ls_currencies()[!ls_currencies() %in% ccys]
if (!identical(ccys, character(0))) rm_currencies(ccys) #if instrument.auto created a currecy, remove it
instr$currency <- "" # since we don't know it, we'll have to let IB guess for us (IB may be wrong!)
}
}
if (is.instrument(instr) && !is.twsContract(instr$IB) && is.null(contract)) { #make contract
primary_id <- instr$primary_id
pid <- parse_id(instr$primary_id)
#figure out sectype
if (is.null(instr$sectype) ) {
if (is.null(instr$type) ||
(!is.null(instr$type) && instr$type == "unknown") )
{ #future_series or option_series created with instrument.auto when no root existed
instr$multiplier <- ""
if (any(pid$type == 'future')) {
instr$type <- 'future_series' #a future object would parse out to 'root', not 'future'
} else if (any(pid$type == 'option')) {
instr$type <- 'option_series' #an option object would parse out to 'root', not 'option'
} else if (any(pid$type == 'root')) {
instr$type <- 'stock'
ambiguous <- primary_id == toupper(primary_id) #will be TRUE except for B Shares like BRKb
#if (!silent) warning(paste(instr$primary_id, "is of an ambiguous format. ",
# "Trying with type = \"stock\""))
instr$multiplier <- 1
}
} else pid <- NULL
#currencies don't have type by FinancialInstrument default. #FIXME: They do now; this can be updated
if (inherits(instr,'currency') ||
(!is.null(instr$type) && any(instr$type == 'currency') ) ) {
sectype <- "CASH"
if (!is.null(instr$counter_currency)) {
symbol <- instr$counter_currency
} else if (!is.null(instr$second_currency)) {
symbol <- instr$second_currency
} else if (nchar(instr$primary_id) == 6) { #TODO: make sure it's 6 letters
symbol <- substr(instr$primary_id,1,3)
} else if (nchar(instr$primary_id) == 7) {
symbol <- strsplit(instr$primary_id,"\\.")[[1]][1]
} else if (nchar(instr$primary_id) == 7) { #e.g. if it was EUR/USD, then the last line didn't change it
symbol <- strsplit(instr$primary_id,"/")[[1]][1]
} else symbol <- instr$primary_id
} else if (inherits(instr,'option') ||
any(instr$type == "option") ||
any(instr$type == "option_series") ||
any(instr$type == "OPT") ) {
sectype <- "OPT"
if (!is.null(instr$underlying_id)
&& !instr$underlying_id == "") {
symbol <- instr$underlying_id
} else symbol <- instr$root_id
#TODO: treat option and option_series differently
} else if (inherits(instr,'future_series') ||
any(instr$type == "future_series") ||
any(pid$type == "SSF")) {
sectype <- "FUT"
if(is.null(instr$root_id)) instr$root_id <- parse_id(primary_id)$root
if(is.null(instr$suffix_id)) instr$suffix_id <- parse_id(primary_id)$suffix
symbol <- instr$root_id
} else if (inherits(instr,'future') ||
any(instr$type == 'future')) {
sectype <- 'FUT'
symbol <- primary_id <- gsub("\\.","",primary_id)
} else if (inherits(instr,'stock') || inherits(instr, 'fund') ||
any(instr$type == "stock") || any(instr$type == 'fund') ||
any(instr$type == "STK")) {
sectype <- "STK"
} else if (inherits(instr,'synthetic') ||
any((instr$type == 'synthetic')) ||
any((instr$type == 'IND'))) {
sectype <- 'IND'
} else {
stop(paste('Cannot determine sectype; ', symbol ,
' does not appear to be a stock, ',
'option, future or currency.', sep=""))
}
} else sectype = instr$sectype
if (is.null(contract$conId) || contract$conId == 0) { #This if statement isn't necessary
conId <- 0
pid <- parse_id(primary_id)
if ((any(instr$type == "future_series") || any(instr$type == "option_series") ) && is.null(instr$expires) && is.null(instr$expiry)) {
if (!silent) warning("Expiry not defined for future or option... Inferring from id.")
instr$expires <- format(as.Date(paste(pid$month,pid$year,15),origin='1970-01-01',format='%b%Y%d'),format='%Y%m')
}
if (any(instr$type == "option_series") ) {
if (is.null(instr$strike)) {
if (!silent) warning("strike is not defined for option... Inferring from id.")
instr$strike <- pid$strike
}
if (!is.null(instr$callput)) {
right <- switch(instr$callput, call=,c=,C="C",put=,p=,P="P")
} else if (!is.null(instr$right)) {
right <- switch(instr$right, call=,c=,C="C",put=,p=,P="P") #instr$right
} else {
right <- pid$right
if (!silent) warning("right of option is neither call nor put... Inferring from id.")
right <- instr$right
}
}
} else conId <- contract$conId
#set multiplier
multiplier <- ""
if (sectype == "STK") { # || sectype == "CASH") {
exchange <- 'SMART'
} else if (sectype == "CASH") {
exchange <- "IDEALPRO"
} else if (sectype == 'IND') {
exchange <- instr$exchange
} else {
multiplier <- instr$multiplier
exchange <- instr$exchange #Should exchange and primary both be the same ?
}
primary <- "" # should this be instr$exchange ?
if (is.null(instr$expires) && !is.null(instr$expiry)) {
expiry <- paste(instr$expiry)
} else if (!is.null(instr$expires)) {
expiry <- paste(instr$expires)
} else expiry <- ""
IBexpiry <- expiry
if(sectype == "FUT") {
if (nchar(IBexpiry) == 10) {
IBexpiry <- format(as.Date(IBexpiry, origin='1970-01-01', format="%Y-%m-%d"),"%Y%m")
} else if (nchar(IBexpiry) == 7) IBexpiry <- gsub("-","",IBexpiry)
}
#IB uses the Friday before expiration Saturday for expiry
#except for EOM options.
if (!is.null(IBexpiry) && is.character(IBexpiry) && IBexpiry != "") {
if (nchar(IBexpiry) == 8) {
expdate <- as.Date(IBexpiry, origin='1970-01-01', format="%Y%m%d")
if (weekdays(expdate) == "Saturday") {
IBexpiry <- format(expdate - 1,"%Y%m%d")
}
} else if (nchar(IBexpiry) == 10) {
expdate <- as.Date(IBexpiry, origin='1970-01-01', format="%Y-%m-%d")
if (weekdays(expdate) == "Saturday") {
IBexpiry <- format(expdate - 1, "%Y%m%d")
}
}
} else IBexpiry = ""
strike <- instr$strike
currency <- instr$currency
# right <- instr$right
#TODO: try to add other info here: local,etc.
#change the NULL values to empty character strings
if (is.null(primary) || primary == "N/A") primary <- ""
if (is.null(exchange)) {
if (sectype == 'STK') {
exchange <- 'SMART'
} else if (sectype == 'CASH') {
exchange <- 'IDEALPRO'
} else exchange <- ''
}
if (is.null(expiry)) expiry <- ""
if (is.null(strike)) strike <- ""
if (is.null(right)) right <- ""
#local <- paste(symbol, TODO
#create/get initial contract
#FIXME: Should exch="" here? or instr$exchange? or 'SMART'?
contract <- twsContract(conId=conId, symbol=symbol, exch=exchange,primary=primary,
sectype=sectype, expiry=IBexpiry, strike=strike, currency=currency,
right=right, local="", multiplier=multiplier, combo_legs_desc="",
comboleg="", include_expired=include_expired)
} else if (is.null(contract) && is.instrument(instr)) contract <- instr$IB
#done getting twsContract object
####################################################################
#Establish a connection, and download contract details from IB. on error: disconnect
if ( (contract$sectype != "CASH") ||
((contract$sectype == "CASH") && !is.instrument(instr)) ||
(is.instrument(instr) && instr$currency != instr$primary_id) ) {
#|| (contract$symbol != contract$currency) ) {
# || is.exchange_rate(instr) #no function for this
if (is.null(tws) || (is.twsConnection(tws) && !isConnected(tws)) )
tws <- ConnectIB(c(100:104, 150))
tryCatch(
{
if (suppressWarnings(isConnected(tws))) {
if (verbose) cat(paste('Connected with clientId ', tws$clientId, '.\n',sep=""))
if (tws$clientId == 150) warning("IB Trader Workstation should be restarted.")
#request that IB fill in missing info.
details <- try(suppressWarnings(reqContractDetails(tws,contract)),silent=TRUE)
if (length(details) == 0) {
if ( (contract$include_expired == 0 ||
contract$include_expired == "0" ||
!isTRUE(contract$include_expired)) &&
(is.null(contract$sectype) ||
(!is.null(contract$sectype) && any(contract$sectype == c("FUT","OPT","FOP","BAG")))) )
{
if (verbose) cat("Trying to resolve error in contract details. Using include_expired=1\n")
contract$include_expired <- "1"
details <- try(suppressWarnings(reqContractDetails(tws,contract)),silent=TRUE)
}
}
if (length(details) == 0 && !identical(integer(0), grep("\\.", contract$symbol) )) {
if ( is.null(contract$sectype) || (!is.null(contract$sectype) && (any(contract$sectype == c('STK','IND')))))
{
contract$symbol <- strsplit(contract$symbol, "\\.")[[1]][1]
details <- try(suppressWarnings(reqContractDetails(tws,contract)), silent=TRUE)
if (length(details) > 0 && verbose) cat("Resolved error in contract details by omitting exchange info from ticker.\n")
}
}
if (length(details) == 0) {
if ( is.null(contract$sectype) || (!is.null(contract$sectype) && (contract$sectype == 'STK')))
{
if (verbose) cat("Trying to resolve error in contract details. Using sectype='IND'\n")
contract$sectype <- 'IND'
contract$exch <- ""
details <- try(suppressWarnings(reqContractDetails(tws,contract)), silent=TRUE)
}
}
if (length(details) > 0 && !is.instrument(getInstrument(details[[1]]$contract$currency,type='currency',silent=TRUE))) {
if (verbose) cat("Checking to see if other 'type's have a pre-defined currency.\n")
tmpcontract <- contract
tmpcontract$sectype <- switch(tmpcontract$sectype, STK='IND', 'STK')
tmpcontract$exch <- switch(tmpcontract$sectype, IND="", STK=,OPT="SMART", CASH='IDEALPRO')
tmpdetails <- try(suppressWarnings(reqContractDetails(tws,tmpcontract)), silent=TRUE)
if (length(tmpdetails) > 0 && is.instrument(getInstrument(tmpdetails[[1]]$contract$currency,type='currency',silent=TRUE))) {
details <- tmpdetails
instr$type <- switch(details[[1]]$contract$sectype, STK='stock',IND='synthetic',OPT='option',FUT='future',CASH='exchange_rate')
}
}
} else cat('Could not connect to tws.\n') #shouldn't get this message because we should get an error first
},finally=try(twsDisconnect(tws), silent=TRUE)) #End tryCatch
if (length(details) == 0) {
uc <- contract
details <- NULL
addIBslot <- FALSE
stop(paste('Could not create valid twsContract.\n',
contract$symbol, ' may not be a valid ', contract$sectype,
'.\nDisconnected.\n', sep=""))
} else {
details <- details[[1]]
uc <- details[["contract"]] #updated contract
uc$include_expired <- contract$include_expired #FIXME: IBrokers:::reqContractDetails overwrites include_expired
if (uc$sectype != 'FUT' && uc$sectype != 'OPT') uc$include_expired <- ""
if (verbose) {
cat(paste('Request complete: ',
paste(uc$symbol, uc$sectype, uc$currency), '.\nDisconnected.\n', sep=""))
}
}
} else {
warning(paste(primary_id, 'is not a tradeable currency pair.'))
addIBslot = FALSE
uc <- contract
details <- NULL
}
if(ambiguous && !silent) warning(paste(instr$primary_id, "is of an ambiguous format. Make sure the type is what you wanted."))
if (any(parse_id(gsub(" ","",uc$local))$type == "SSF") && !any(parse_id(primary_id)$type == "SSF") && !silent) {
warning('Returning SSF. If this is not what you want make sure your expiration month is valid.')
}
#make sure the currency is defined for this product
tmpccy <- try(getInstrument(uc$currency, silent=TRUE),silent=TRUE)
if ( (inherits(tmpccy, 'try-error') || !inherits(tmpccy,'currency') )
&& assign_c) {
#FIXME: is.currency calls getInstrument on whatever is passed to it, but
#getInstrument throws a ton of warnings if you pass something with length > 1
#So, 2 problems: is.currency is FALSE if you don't pass it a string.
#and, getInstrument doesn't check length of pattern before grep'ing
if (!is.null(uc) && !is.null(uc$currency)) {
currency(uc$currency)
if(!silent) warning(paste("Creating currency ", uc$currency))
}
}
#If the instrument doesn't exist, create it, unless assign_i==FALSE
#tmpinstr <- try(getInstrument(primary_id),silent=TRUE)
if (is.null(instr) || inherits(instr, 'try-error') || !is.instrument(instr)) {
#chances are, you got here by giving symbol a name instead of an instrument or contract
# if (inherits(tmpinstr,'try-error') || !is.instrument(tmpinstr)) {
updateInstrument <- TRUE
cat(paste("Attempting to create instrument", primary_id,'.\n'))
instr <- NULL #this line shouldn't be necessary, but it doesn't hurt
} else {
if (addIBslot && !updateInstrument) {
instr$IB <- uc
if (!is.null(instr$type))
tclass <- unique(c('twsInstrument', instr$type, 'instrument'))
class(instr) <- tclass
if (assign_i) {
assign(primary_id, instr, pos=FinancialInstrument:::.instrument)
}
}
}
if (updateInstrument) { # && assign_i) {
instr$primary_id <- primary_id
instr$currency <- uc$currency
#instr$identifiers <- unique(c(instr$identifiers, list(conId=uc$conId, local=gsub(" ","",uc$local))))
# Get nammed and unnamed unique identifiers separately
ident <- c(instr$identifiers, list(conId=uc$conId, local=gsub(" ","",uc$local)))
unnamed <- which(names(ident)=="")
uident <- unique(ident[unnamed])
ident.names <- unique(names(ident)[names(ident) != ""])
ident <- ident[ident.names]
instr$identifiers <- c(uident, ident)
instr$local <- uc$local
instr$IB.primary.exch <- uc$primary
instr$exchange <- uc$exch #ok to overwrite 'SMART' ?
mN <- details$marketName
instr$marketName <- if (mN == "NMS") {
if (!silent) warning('marketName of "NMS" was replaced by symbol')
uc$symbol
} else mN
switch(uc$sectype,
IND={
instr$type <- unique(c(instr$type,'synthetic'))
instr$multiplier <- 1
},
STK={
instr$type <- unique(c(instr$type,'stock'))
instr$multiplier <- 1
},
OPT={
instr$type <- unique(c(instr$type,'option'))
instr$multiplier <- as.numeric(uc$multiplier)
instr$expires <- if (nchar(uc$expiry) == 8) {
paste(substr(uc$expiry,1,4),substr(uc$expiry,5,6),substr(uc$expiry,7,8),sep="-")
} else uc$expiry
instr$strike <- uc$strike
instr$right <- uc$right
},
FUT={
instr$type <- unique(c(instr$type,'future'))
instr$multiplier <- as.numeric(uc$multiplier)
instr$expires <- if (nchar(uc$expiry) == 8) {
paste(substr(uc$expiry,1,4),substr(uc$expiry,5,6),substr(uc$expiry,7,8),sep="-")
} else uc$expiry
iblocal <- uc$local
tmpx <- suppressWarnings(try(as.numeric(iblocal)))
if (!inherits(tmpx, 'try-error') && !is.na(tmpx) && is.numeric(tmpx)) { #make suffix_id
tmpd <- as.Date(instr$expires)
Y <- format(tmpd, "%y")
M <- month.abb[as.numeric(format(tmpd, "%m"))]
instr$suffix_id <- paste(M2C(M), Y, sep="")
rm('tmpd', 'Y', 'M')
}
rm('tmpx')
si <- if (is.null(instr$suffix_id)) {
parse_id(gsub(" ","",iblocal), root=details$marketName)$suffix
} else instr$suffix_id
primary_id <- paste(contract$symbol,si,sep="_")
primary_id <- gsub(" ","",primary_id)
instr$primary_id <- primary_id
instr$suffix_id <- gsub(" ","",si)
},
CASH={
instr$type <- unique(c(instr$type,'currency'))
instr$multiplier <- 1
},{} ) #End switch on sectype
#the rest of these may not work in the future, because, as I understand it,
#the IB API event that provides them has been deprecated.
if (uc$sectype != "CASH" || (instr$currency != instr$primary_id)) {
#we don't have this info for non-tradeable base currency
instr$tick_size <- as.numeric(details$minTick)
instr$priceMagnifier <- as.numeric(details$priceMagnifier)
instr$longName <- details$longName
instr$industry <- details$industry
if (!is.null(details) && details$contractMonth != "")
instr$contract_month <- details$contractMonth
instr$category <- details$category
instr$subcategory <- details$subcategory
instr$timeZoneId <- details$timeZoneId
formatHours <- function(tH) {
tH <- strsplit(tH, ":")[[1]]
tH <- tH[length(tH)]
tH <- strsplit(tH, ",")[[1]]
tH <- strsplit(tH, "-")
tH <- do.call(c, lapply(tH, function(x) paste(paste(substr(x, 1, 2), substr(x, 3, 4), "00", sep=":"), collapse="/T")))
tH <- paste("T", tH, sep="")
names(tH) <- paste('session', 1:length(tH), sep="")
tH
}
tH <- details$tradingHours
lH <- details$liquidHours
instr$tradingHours <- tH
instr$liquidHours <- lH
if (nchar(tH) > 0) instr$tradingHours <- formatHours(tH)
if (nchar(lH) > 0) instr$liquidHours <- formatHours(lH)
tH <- instr$tradingHours
lH <- instr$liquidHours
if (nchar(details$tradingHours) > 0) {
if (details$tradingHours == details$liquidHours) {
if (length(instr$tradingHours) == 3) { #use middle one as primary
instr$primary_start <- sub("T", "", strsplit(tH[2], "/")[[1]][1])
instr$primary_end <- sub("T", "", strsplit(tH[2], "/")[[1]][2])
instr$electronic_start <- gsub("T", "", strsplit(tH[1], "/")[[1]][1])
instr$electronic_end <- strsplit(gsub("T", "", tH[3]), "/")[[1]][2]
} else if (length(instr$tradingHours) == 2) { #use second one as primary
instr$primary_start <- sub("T", "", strsplit(tH[2], "/")[[1]][1])
instr$primary_end <- sub("T", "", strsplit(tH[2], "/")[[1]][2])
instr$electronic_start <- sub("T", "", strsplit(tH[1], "/")[[1]][1])
instr$electronic_end <- sub("T", "", strsplit(tH[1], "/")[[1]][2])
} else if (length(instr$tradingHours) == 1) {
times <- gsub("T", "", strsplit(tH, "/")[[1]])
instr$primary_start <- instr$electronic_start <- times[1]
instr$primary_end <- instr$electronic_end <- times[2]
}
} else {
ltimes <- gsub("T", "", strsplit(lH, "/")[[1]])
instr$primary_start <- ltimes[1]
instr$primary_end <- ltimes[2]
ttimes <- gsub("T", "", strsplit(tH, "/")[[1]])
instr$electronic_start <- ttimes[1]
instr$electronic_end <- ttimes[2]
}
}
instr$validExchanges <- details$validExchanges
} #End deprecated
tmptype <- switch(instr$type[1],
future=c('future_series','future'),
option=c('option_series','option'),
instr$type)
if (addIBslot) {
instr$IB <- uc
tclass <- unique(c(tmptype,'twsInstrument','instrument'))
} else tclass <- unique(c(tmptype,"instrument"))
#update info about where & when the instrument was updated
instr$defined.by <- paste(c(instr$defined.by, "IB"), collapse=";")
db <- instr$defined.by
if (!is.null(db)) {
db <- unlist(strsplit(db,";"))
db <- rev(unique(c("IB", rev(db))))
db <- paste(db,collapse=";")
} else db <- "IB"
instr$updated <- Sys.time()
class(instr) <- tclass
#Put instr back in the .instrument environment
if (assign_i || output=='nothing') {
if (!is.null(instr$primary_id) &&
instr$primary_id != "" &&
instr$currency != "" &&
instr$multiplier != "")
assign(primary_id, instr, pos=FinancialInstrument:::.instrument)
}
}
switch (output[1],
contract =,
contr =,
Contract = {uc},
instrument =,
Instrument =,
twsInstrument =,
instr={instr},
symbol =,
symbols =,
Symbol =,
primary_id = {primary_id},
nothing={invisible()} )
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.