├── .Rbuildignore ├── .gitignore ├── DESCRIPTION ├── IBrokers2.Rproj ├── NAMESPACE ├── NAMESPACE.new ├── R ├── IBrokersRef.R ├── Scanner.R ├── ScannerSubscription.R ├── calculateImpliedVolatility.R ├── calculateOptionPrice.R ├── call_back.R ├── cancelOrder.R ├── eWrapper.MktData.CSV.R ├── eWrapper.MktDepth.CSV.R ├── eWrapper.R ├── eWrapper.data.R ├── eWrapper.snapshot.R ├── eWrapper.updateAccount.R ├── errorHandler.R ├── eventHandlers.R ├── exerciseOptions.R ├── get_account.R ├── get_open_orders.R ├── placeOrder.R ├── processMsg.R ├── reqAccountUpdates.R ├── reqContractDetails.R ├── reqCurrentTime.R ├── reqExecutions.R ├── reqFundamentalData.R ├── reqHistoricalData.R ├── reqIds.R ├── reqManagedAccts.R ├── reqMktData.R ├── reqMktDepth.R ├── reqNewsBulletins.R ├── reqOpenOrders.R ├── reqRealTimeBars.R ├── serverVersion.R ├── setServerLogLevel.R ├── trade_realtime.R ├── trade_wrapper.R ├── twsBAG.R ├── twsComboLeg.R ├── twsConnect.R ├── twsConnectionTime.R ├── twsContract.R ├── twsCurrency.R ├── twsDisconnect.R ├── twsEquity.R ├── twsExecution.R ├── twsExecutionFilter.R ├── twsFuture.R ├── twsFutureOpt.R ├── twsIDs.R ├── twsIndex.R ├── twsMethods.R ├── twsOption.R ├── twsOrder.R ├── twsOrderState.R ├── twsPortfolioValue.R ├── twsTickType.R └── zzz.R ├── README.Rmd ├── README.html ├── README.md ├── man └── hello.Rd ├── scripts ├── IB_scripts.R ├── IB_trading.R ├── IB_trading_Stevens_2019.R ├── Jerzy_Pawlowski_Stevens_2019.Rmd ├── Jerzy_Pawlowski_Stevens_2019.html ├── TWS Kovalevsky.R ├── app_ibtrading.R ├── ibrokers_callback.R ├── ibrokers_processMsg.R ├── ibrokers_reqRealTimeBars.R ├── temp.R └── twsIncoming.txt └── vignettes ├── IBrokers.R ├── IBrokers.Rnw ├── IBrokers.pdf ├── IBrokersREFCARD.R ├── IBrokersREFCARD.Rnw ├── IBrokersREFCARD.pdf ├── IBrokersRef.pdf ├── RealTime.R ├── RealTime.Rnw ├── RealTime.pdf ├── ToDoList.md ├── eWrapper_object.png ├── functions_IBrokers2.png ├── ib_trade_processing.png ├── ibrokers_design.Rmd ├── ibrokers_design.html ├── ibrokers_design.md ├── market_event_processing.png ├── market_event_processing2.png ├── real_time_trading.Rmd ├── real_time_trading.html ├── real_time_trading.md ├── real_time_trading.png ├── trade_processing.png └── trade_wrapper_object.png /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rhistory 2 | .RData 3 | # RStudio files 4 | .Rproj.user/ 5 | .Rproj.user 6 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: IBrokers2 2 | Type: Package 3 | Title: R API to Interactive Brokers (clone of IBrokers) 4 | Version: 0.1 5 | Date: 2018-11-14 6 | Depends: 7 | xts, 8 | quantmod 9 | Imports: 10 | quantmod 11 | Author: Jeffrey A. Ryan 12 | Maintainer: Jerzy Pawlowski 13 | Description: Provides native R access to Interactive Brokers Trader Workstation API (clone of IBrokers) 14 | License: GPL-3 15 | NeedsCompilation: no 16 | VignetteBuilder: knitr 17 | LazyData: true 18 | ByteCompile: true 19 | Repository: GitHub 20 | URL: https://github.com/algoquant/IBrokers2 21 | RoxygenNote: 6.1.0 22 | Encoding: UTF-8 23 | -------------------------------------------------------------------------------- /IBrokers2.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | exportPattern("^[[:alpha:]]+") 2 | # useDynLib(IBrokers2) 3 | import(zoo, xts) 4 | 5 | export(trade_wrapper, 6 | create_ewrapper, 7 | trade_realtime, 8 | get_account) 9 | export(reqRealTimeBars) 10 | export(twsConnect, 11 | twsConnect2, # experimental connection object 12 | ibgConnect, 13 | twsDisconnect, 14 | 15 | is.twsConnection, 16 | isConnected, 17 | 18 | twsConnectionTime, 19 | serverVersion, 20 | setServerLogLevel, 21 | reqCurrentTime, 22 | 23 | .reqIds, # send only 24 | reqIds, 25 | 26 | reqContractDetails, 27 | 28 | .reqAccountUpdates, # send only 29 | reqAccountUpdates, 30 | cancelAccountUpdates, 31 | 32 | twsPortfolioValue, 33 | 34 | # FA accounts only - untested as there is a missing EWrapper method here 35 | reqManagedAccts, 36 | requestFA, 37 | replaceFA, 38 | 39 | twsExecutionFilter, 40 | reqExecutions, 41 | 42 | reqScannerParameters, 43 | twsScannerSubscription, 44 | reqScannerSubscription, 45 | 46 | twsContract, 47 | is.twsContract, 48 | as.twsContract, 49 | 50 | twsBAG, 51 | twsComboLeg, 52 | 53 | twsCurrency, 54 | twsCASH, 55 | twsEquity, 56 | twsSTK, 57 | twsIndex, 58 | twsIND, 59 | twsCFD, 60 | twsFuture, 61 | twsFUT, 62 | twsFutureOpt, 63 | twsFOP, 64 | twsOption, 65 | twsOPT, 66 | 67 | reqHistoricalData, 68 | cancelHistoricalData, 69 | reqHistory, # convenience wrapper 70 | 71 | reqMktData, 72 | cancelMktData, 73 | .calculateImpliedVolatility, 74 | calculateImpliedVolatility, 75 | .calculateOptionPrice, 76 | calculateOptionPrice, 77 | 78 | 79 | reqMktDepth, 80 | cancelMktDepth, 81 | 82 | reqRealTimeBars, 83 | cancelRealTimeBars, 84 | 85 | twsOrder, 86 | .placeOrder, # send only 87 | placeOrder, 88 | cancelOrder, 89 | 90 | .reqOpenOrders, 91 | reqOpenOrders, 92 | .reqAllOpenOrders, 93 | .reqAutoOpenOrders, 94 | exerciseOptions, 95 | 96 | reqNewsBulletins, 97 | cancelNewsBulletins, 98 | 99 | twsCALLBACK, 100 | twsDEBUG, 101 | processMsg, 102 | 103 | eWrapper, 104 | 105 | eWrapper.data, 106 | eWrapper.RealTimeBars, 107 | 108 | eWrapper.RealTimeBars.CSV, 109 | eWrapper.MktData.CSV, 110 | eWrapper.MktDepth.CSV 111 | ) 112 | 113 | export(.twsIncomingMSG, 114 | .twsOutgoingMSG, 115 | .twsERR, 116 | .twsTickType, 117 | .twsOrderID 118 | ) 119 | 120 | export(IBrokersRef) 121 | 122 | S3method(print,twsConnection) 123 | S3method(print,twsconn) 124 | S3method("[[", twsconn) 125 | S3method(close,twsConnection) 126 | S3method(close,twsconn) 127 | 128 | S3method(print,twsContract) 129 | S3method(as.twsContract, list) 130 | S3method(as.twsContract, twsContract) 131 | S3method(as.twsContract, twsContractDetails) 132 | S3method(print,twsContractDetails) 133 | 134 | S3method(print,twsScannerSubscription) 135 | S3method(print,eventPortfolioValue) 136 | S3method(print,eventAccountValue) 137 | 138 | S3method(twsPortfolioValue, eWrapper) 139 | S3method(twsPortfolioValue, AccountUpdate) 140 | 141 | S3method(summary, AccountUpdate) 142 | 143 | -------------------------------------------------------------------------------- /NAMESPACE.new: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(eWrapper_new) 4 | export(eWrapper_realtimebars) 5 | export(reqRealTimeBars) 6 | -------------------------------------------------------------------------------- /R/IBrokersRef.R: -------------------------------------------------------------------------------- 1 | IBrokersRef <- function() { 2 | ref <- system.file("doc/IBrokersREFCARD.pdf",package="IBrokers") 3 | if(.Platform$OS.type == "windows") 4 | shell.exec(ref) 5 | else system(paste(shQuote(getOption("pdfviewer")), shQuote(ref)), 6 | wait = FALSE) 7 | } 8 | -------------------------------------------------------------------------------- /R/Scanner.R: -------------------------------------------------------------------------------- 1 | .reqScannerParameters <- function(twsconn) { 2 | if( !is.twsConnection(twsconn)) 3 | stop('invalid twsConnection') 4 | 5 | VERSION <- "1" 6 | 7 | writeBin(c(.twsOutgoingMSG$REQ_SCANNER_PARAMETERS, VERSION), twsconn[[1]]) 8 | } 9 | 10 | reqScannerParameters <- function(twsconn) { 11 | .reqScannerParameters(twsconn) 12 | 13 | con <- twsconn[[1]] 14 | eW <- eWrapper() 15 | 16 | while(TRUE) { 17 | socketSelect(list(con), FALSE, NULL) 18 | curMsg <- readBin(con, character(), 1L) 19 | msg <- processMsg(curMsg, con, eW) 20 | if( curMsg == .twsIncomingMSG$SCANNER_PARAMETERS) 21 | return(invisible(msg[2])) 22 | } 23 | } 24 | 25 | .reqScannerSubscription <- function(twsconn, subscription, tickerId=1) { 26 | if( !is.twsConnection(twsconn)) 27 | stop('invalid twsConnection') 28 | if( !inherits(subscription, "twsScannerSubscription")) 29 | stop('invalid twsScannerSubscription') 30 | 31 | VERSION <- "3" 32 | 33 | msg <- c(.twsOutgoingMSG$REQ_SCANNER_SUBSCRIPTION, 34 | VERSION, 35 | tickerId, 36 | subscription$numberOfRows, 37 | subscription$instrument, 38 | subscription$locationCode, 39 | subscription$scanCode, 40 | subscription$abovePrice, 41 | subscription$belowPrice, 42 | subscription$aboveVolume, 43 | subscription$marketCapAbove, 44 | subscription$marketCapBelow, 45 | subscription$moodyRatingAbove, 46 | subscription$moodyRatingBelow, 47 | subscription$spRatingAbove, 48 | subscription$spRatingBelow, 49 | subscription$maturityDateAbove, 50 | subscription$maturityDateBelow, 51 | subscription$couponRateAbove, 52 | subscription$couponRateBelow, 53 | subscription$excludeConvertible, 54 | subscription$averageOptionVolumeAbove, 55 | subscription$scannerSettingPairs, 56 | subscription$stockTypeFilter) 57 | 58 | writeBin(as.character(msg), twsconn[[1]]) 59 | } 60 | 61 | reqScannerSubscription <- function(twsconn, subscription, tickerId=1) { 62 | scanner <- data.frame(reqId=NULL, 63 | rank =NULL, 64 | symbol=NULL, 65 | expiry=NULL, 66 | strike=NULL, 67 | right=NULL, 68 | exch=NULL, 69 | currency=NULL, 70 | local=NULL, 71 | marketName=NULL, 72 | tradingClass=NULL, 73 | distance=NULL, 74 | benchmark=NULL, 75 | projection=NULL, 76 | legsStr=NULL) 77 | .reqScannerSubscription(twsconn, subscription, tickerId) 78 | on.exit(cancelScannerSubscription(twsconn, tickerId)) 79 | 80 | con <- twsconn[[1]] 81 | while(TRUE) { 82 | socketSelect(list(con), FALSE, NULL) 83 | curMsg <- readBin(con, character(), 1L) 84 | if(curMsg == .twsIncomingMSG$SCANNER_DATA) { 85 | cD <- twsContractDetails() 86 | version <- readBin(con, character(), 1L) 87 | reqId <- readBin(con, character(), 1L) 88 | numberOfElements <- as.integer(readBin(con, character(), 1L)) 89 | for (i in 1:numberOfElements) { 90 | msg <- readBin(con, character(), 16L) 91 | rank <- msg[1] 92 | cD$contract$conId <- msg[2] 93 | cD$contract$symbol <- msg[3] 94 | cD$contract$sectype <- msg[4] 95 | cD$contract$expiry <- msg[5] 96 | cD$contract$strike <- msg[6] 97 | cD$contract$right <- msg[7] 98 | cD$contract$exch <- msg[8] 99 | cD$contract$currency <- msg[9] 100 | cD$contract$local <- msg[10] 101 | cD$marketName <- msg[11] 102 | cD$tradingClass <- msg[12] 103 | distance <- msg[13] 104 | benchmark <- msg[14] 105 | projection <- msg[15] 106 | legsStr <- msg[16] 107 | ctr <- cD$contract 108 | scanner <- rbind(scanner, 109 | data.frame(reqId,rank,symbol=ctr$symbol, 110 | expiry=ctr$expiry,strike=ctr$strike, 111 | right=ctr$right,exch=ctr$exch, 112 | currency=ctr$currency,local=ctr$local, 113 | marketName=cD$marketName,tradingClass=cD$tradingClass, 114 | distance,benchmark,projection, 115 | legsStr,stringsAsFactors=FALSE)) 116 | 117 | } 118 | return(scanner) 119 | } else processMsg(curMsg, con, eWrapper(NULL)) 120 | } 121 | } 122 | 123 | cancelScannerSubscription <- function(twsconn, tickerId=1) { 124 | if( !is.twsConnection(twsconn)) 125 | stop('invalid twsConnection') 126 | 127 | VERSION <- "1" 128 | 129 | msg <- c(.twsOutgoingMSG$CANCEL_SCANNER_SUBSCRIPTION, 130 | VERSION, 131 | tickerId) 132 | writeBin(as.character(msg), twsconn[[1]]) 133 | } 134 | -------------------------------------------------------------------------------- /R/ScannerSubscription.R: -------------------------------------------------------------------------------- 1 | twsScannerSubscription <- function(numberOfRows=-1, 2 | instrument="", 3 | locationCode="", 4 | scanCode="", 5 | abovePrice="", 6 | belowPrice="", 7 | aboveVolume="", 8 | averageOptionVolumeAbove="", 9 | marketCapAbove="", 10 | marketCapBelow="", 11 | moodyRatingAbove="", 12 | moodyRatingBelow="", 13 | spRatingAbove="", 14 | spRatingBelow="", 15 | maturityDateAbove="", 16 | maturityDateBelow="", 17 | couponRateAbove="", 18 | couponRateBelow="", 19 | excludeConvertible="", 20 | scannerSettingPairs="", 21 | stockTypeFilter="") 22 | { 23 | if(missing(scanCode)) 24 | warning("'scanCode' needs to be specified") 25 | 26 | structure( 27 | list(numberOfRows=numberOfRows, 28 | instrument=instrument, 29 | locationCode=locationCode, 30 | scanCode=scanCode, 31 | abovePrice=abovePrice, 32 | belowPrice=belowPrice, 33 | aboveVolume=aboveVolume, 34 | averageOptionVolumeAbove=averageOptionVolumeAbove, 35 | marketCapAbove=marketCapAbove, 36 | marketCapBelow=marketCapBelow, 37 | moodyRatingAbove=moodyRatingAbove, 38 | moodyRatingBelow=moodyRatingBelow, 39 | spRatingAbove=spRatingAbove, 40 | spRatingBelow=spRatingBelow, 41 | maturityDateAbove=maturityDateAbove, 42 | maturityDateBelow=maturityDateBelow, 43 | couponRateAbove=couponRateAbove, 44 | couponRateBelow=couponRateBelow, 45 | excludeConvertible=excludeConvertible, 46 | scannerSettingPairs=scannerSettingPairs, 47 | stockTypeFilter=stockTypeFilter), 48 | class="twsScannerSubscription") 49 | } 50 | 51 | print.twsScannerSubscription <- function(x, ...) { 52 | str(x) 53 | } 54 | -------------------------------------------------------------------------------- /R/calculateImpliedVolatility.R: -------------------------------------------------------------------------------- 1 | .calculateImpliedVolatility <- 2 | function(twsconn, Contract, optionPrice, underPrice, reqId=1) { 3 | if( !is.twsConnection(twsconn)) 4 | stop('invalid tws connection') 5 | 6 | if( !is.twsContract(Contract)) 7 | stop('invalid twsContract') 8 | 9 | VERSION <- "1" 10 | msg <- c(.twsOutgoingMSG$REQ_CALC_IMPLIED_VOLAT, 11 | VERSION, 12 | as.character(reqId), 13 | 14 | # contract fields 15 | Contract$conId, 16 | Contract$symbol, 17 | Contract$sectype, 18 | Contract$expiry, 19 | Contract$strike, 20 | Contract$right, 21 | Contract$multiplier, 22 | Contract$exch, 23 | Contract$primary, 24 | Contract$currency, 25 | Contract$local, 26 | 27 | as.character(optionPrice), 28 | as.character(underPrice)) 29 | 30 | writeBin(msg, twsconn[[1]]) 31 | } 32 | 33 | calculateImpliedVolatility <- 34 | function (twsconn, Contract, optionPrice, underPrice, reqId = 1) 35 | { 36 | .calculateImpliedVolatility(twsconn, Contract, optionPrice, 37 | underPrice, reqId) 38 | eW <- eWrapper(NULL) 39 | eW$tickOptionComputation <- function(msg, string, ...) { 40 | as.numeric(string[4]) 41 | } 42 | con <- twsconn[[1]] 43 | while (TRUE) { 44 | socketSelect(list(con), FALSE, NULL) 45 | curMsg <- readBin(con, "character", 1) 46 | msg <- processMsg(curMsg, con, eW, NULL, "") 47 | if (curMsg == .twsIncomingMSG$TICK_OPTION_COMPUTATION) { 48 | return(msg) 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /R/calculateOptionPrice.R: -------------------------------------------------------------------------------- 1 | .calculateOptionPrice <- 2 | function(twsconn, Contract, volatility, underPrice, reqId=1) { 3 | if( !is.twsConnection(twsconn)) 4 | stop('invalid tws connection') 5 | 6 | if( !is.twsContract(Contract)) 7 | stop('invalid twsContract') 8 | 9 | VERSION <- "1" 10 | msg <- c(.twsOutgoingMSG$REQ_CALC_OPTION_PRICE, 11 | VERSION, 12 | as.character( reqId), 13 | 14 | # contract fields 15 | Contract$conId, 16 | Contract$symbol, 17 | Contract$sectype, 18 | Contract$expiry, 19 | Contract$strike, 20 | Contract$right, 21 | Contract$multiplier, 22 | Contract$exch, 23 | Contract$primary, 24 | Contract$currency, 25 | Contract$local, 26 | 27 | as.character( volatility), 28 | as.character( underPrice)) 29 | 30 | writeBin(msg, twsconn[[1]]) 31 | } 32 | 33 | calculateOptionPrice <- 34 | function (twsconn, Contract, volatility, underPrice, reqId = 1) 35 | { 36 | .calculateOptionPrice(twsconn, Contract, volatility, underPrice, reqId) 37 | eW <- eWrapper(NULL) 38 | eW$tickOptionComputation <- function(curMsg, msg, ...) { 39 | as.numeric(msg[6]) # option price 40 | } 41 | con <- twsconn[[1]] 42 | while (TRUE) { 43 | socketSelect(list(con), FALSE, NULL) 44 | curMsg <- readBin(con, "character", 1) 45 | msg <- processMsg(curMsg, con, eW, NULL, "") 46 | if (curMsg == .twsIncomingMSG$TICK_OPTION_COMPUTATION) { 47 | return(msg) 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /R/call_back.R: -------------------------------------------------------------------------------- 1 | # The function IBrokers2::call_back() performs a callback loop, 2 | # similar to IBrokers::twsCALLBACK(). 3 | # It is a clone of IBrokers::twsCALLBACK(). 4 | # It is designed to be called by IBrokers2::trade_realtime(). 5 | # The argument back_test determines if the callback loop 6 | # receives live data (back_test=FALSE), or it plays back 7 | # historical data (back_test=TRUE). 8 | 9 | #' @export 10 | call_back <- function(ib_connect, e_wrapper, timestamp, file, back_test=FALSE, sym_bol="ES", ...) { 11 | 12 | sock_et <- ib_connect[[1]] 13 | 14 | if (missing(e_wrapper)) 15 | e_wrapper <- IBrokers2::eWrapper() 16 | 17 | if (back_test) { 18 | # Code for off-line backtest 19 | # Load the data from file 20 | data_dir <- "C:/Develop/data/ib_data/" 21 | load(paste0(data_dir, sym_bol, "_ohlc.RData")) 22 | 23 | n_rows <- NROW(oh_lc) 24 | e_wrapper$da_ta$n_rows <- n_rows 25 | n_cols <- e_wrapper$da_ta$n_cols 26 | n_contracts <- e_wrapper$da_ta$n_contracts 27 | name_s <- e_wrapper$da_ta$name_s 28 | 29 | ohlc_data <- coredata(oh_lc) 30 | ohlc_data <- cbind(rep(1, n_rows), rep(1, n_rows), xts::.index(oh_lc), ohlc_data) 31 | 32 | # Create data buffer bar_data, a list of matrices in the e_wrapper environment 33 | # The old buffer bar_data needs to be resized 34 | e_wrapper$da_ta$bar_data <- rep(list(matrix(rep(NA_real_, n_rows*n_cols), ncol=n_cols)), n_contracts) 35 | names(e_wrapper$da_ta$bar_data) <- name_s 36 | for (it in 1:NROW(name_s)) { 37 | col_n <- paste(name_s[it], e_wrapper$da_ta$col_names, sep=".") 38 | colnames(e_wrapper$da_ta$bar_data[[it]]) <- col_n 39 | } # end for 40 | 41 | # perform callback backtest loop 42 | for (it in 1:n_rows) { 43 | new_bar <- ohlc_data[it, ] 44 | e_wrapper$realtimeBars(curMsg=1, msg=new_bar, timestamp=new_bar[2], file=file, ib_connect=ib_connect, ...) 45 | } # end for 46 | 47 | } else { 48 | # Code for live trading 49 | tryCatch( 50 | # Callback loop 51 | while (isConnected(ib_connect)) { 52 | if (!socketSelect(list(sock_et), FALSE, 0.25)) 53 | next 54 | curMsg <- readBin(sock_et, "character", 1L) 55 | # cat("curMsg = ", curMsg, "\n") 56 | # Process the message 57 | if (!is.null(timestamp)) { 58 | processMsg(curMsg, sock_et, e_wrapper, format(Sys.time(), timestamp), file, ib_connect, ...) 59 | } else { 60 | processMsg(curMsg, sock_et, e_wrapper, timestamp, file, ib_connect, ...) 61 | } # end if 62 | }, # end while 63 | # error handler 64 | error=function(e) { close(ib_connect); stop("IB connection error. Connection closed", call.=FALSE) } 65 | ) # end tryCatch 66 | } # end if 67 | } # end call_back 68 | -------------------------------------------------------------------------------- /R/cancelOrder.R: -------------------------------------------------------------------------------- 1 | cancelOrder <- .cancelOrder <- function(twsconn, orderId) 2 | { 3 | if(!is.twsConnection(twsconn)) 4 | stop('requires twsConnection object') 5 | 6 | if(missing(orderId)) 7 | stop('valid "orderId" required') 8 | 9 | con <- twsconn[[1]] 10 | VERSION <- "1" 11 | 12 | writeBin(.twsOutgoingMSG$CANCEL_ORDER, con) 13 | writeBin(VERSION,con) 14 | writeBin(as.character(orderId),con) 15 | } 16 | 17 | ..cancelOrder <- 18 | function(conn, orderId, verbose=TRUE) { 19 | 20 | .cancelOrder(conn, orderId) 21 | 22 | con <- conn[[1]] 23 | while(1) { 24 | socketSelect(list(con), FALSE, NULL) 25 | curMsg <- readBin(con,character(),1) 26 | 27 | 28 | if(curMsg==.twsIncomingMSG$ORDER_STATUS) { 29 | orderStatus <- readBin(con, character(), 11) 30 | } else 31 | processMsg(curMsg, con, eWrapper(), timestamp=NULL, file="") 32 | } 33 | return(orderStatus) 34 | } 35 | -------------------------------------------------------------------------------- /R/eWrapper.MktData.CSV.R: -------------------------------------------------------------------------------- 1 | eWrapper.RealTimeBars.CSV <- function(n=1) { 2 | eW <- eWrapper(NULL) 3 | eW$assign.Data("data", 4 | rep(list(structure(.xts(matrix(rep(NA_real_,7),ncol=7),0), 5 | .Dimnames=list(NULL, 6 | c("Open","High", 7 | "Low","Close", 8 | "Volume","WAP","Count")))),n)) 9 | 10 | eW$realtimeBars <- function(curMsg, msg, timestamp, file, ...) 11 | { 12 | id <- as.numeric(msg[2]) 13 | file <- file[[id]] 14 | data <- eW$get.Data("data") 15 | attr(data[[id]], "index") <- as.numeric(msg[3]) 16 | nr.data <- NROW(data[[id]]) 17 | cat(paste(msg[3], # timestamp in POSIXct 18 | msg[4], # Open 19 | msg[5], # High 20 | msg[6], # Low 21 | msg[7], # Close 22 | msg[8], # Volume 23 | msg[9], # WAP 24 | msg[10], # Count 25 | sep=","), "\n", file=file, append=TRUE) 26 | data[[id]][nr.data,1:7] <- as.numeric(msg[4:10]) 27 | eW$assign.Data("data", data) 28 | c(curMsg, msg) 29 | } 30 | return(eW) 31 | } 32 | 33 | eWrapper.MktData.CSV <- function(n=1) { 34 | eW <- eWrapper(NULL) # use basic template 35 | eW$assign.Data("data", rep(list(structure(.xts(matrix(rep(NA_real_,7),ncol=7),0), 36 | .Dimnames=list(NULL, 37 | c("BidSize","BidPrice", 38 | "AskPrice","AskSize", 39 | "Last","LastSize","Volume")))),n)) 40 | 41 | eW$tickPrice <- function(curMsg, msg, timestamp, file, ...) 42 | { 43 | tickType = msg[3] 44 | msg <- as.numeric(msg) 45 | id <- as.numeric(msg[2]) 46 | file <- file[[id]] 47 | data <- eW$get.Data("data") #[[1]] # list position of symbol (by id == msg[2]) 48 | attr(data[[id]], "index") <- as.numeric(Sys.time()) 49 | nr.data <- NROW(data[[id]]) 50 | #data[[id]][1] <- timestamp 51 | if(tickType == .twsTickType$BID) { 52 | cat(paste(timestamp, 53 | msg[5], #bidSize 54 | msg[4], #bidPrice 55 | "", #askPrice 56 | "", #askSize 57 | "", #lastPrice 58 | "", #lastSize 59 | "", #Volume 60 | sep=","), "\n", file=file, append=TRUE) 61 | data[[id]][nr.data,1:2] <- msg[5:4] 62 | } else 63 | if(tickType == .twsTickType$ASK) { 64 | cat(paste(timestamp, 65 | "", #bidSize 66 | "", #bidPrice 67 | msg[4], #askPrice 68 | msg[5], #askSize 69 | "", #lastPrice 70 | "", #lastSize 71 | "", #Volume 72 | sep=","), "\n", file=file, append=TRUE) 73 | data[[id]][nr.data,3:4] <- msg[4:5] 74 | } else 75 | if(tickType == .twsTickType$LAST) { 76 | cat(paste(timestamp, 77 | "", #bidSize 78 | "", #bidPrice 79 | "", #askPrice 80 | "", #askSize 81 | msg[4], #lastPrice 82 | "", #lastSize 83 | "", #Volume 84 | sep=","), "\n", file=file, append=TRUE) 85 | data[[id]][nr.data,5] <- msg[4] 86 | } 87 | #data[[as.numeric(msg[2])]] <- data 88 | eW$assign.Data("data", data) 89 | c(curMsg, msg) 90 | } 91 | eW$tickSize <- function(curMsg, msg, timestamp, file, ...) 92 | { 93 | data <- eW$get.Data("data") 94 | tickType = msg[3] 95 | msg <- as.numeric(msg) 96 | id <- as.numeric(msg[2]) 97 | file <- file[[id]] 98 | attr(data[[id]], "index") <- as.numeric(Sys.time()) 99 | nr.data <- NROW(data[[id]]) 100 | #data[[id]][1] <- timestamp 101 | if(tickType == .twsTickType$BID_SIZE) { 102 | cat(paste(timestamp, 103 | msg[4], #bidSize 104 | "", #bidPrice 105 | "", #askPrice 106 | "", #askSize 107 | "", #lastPrice 108 | "", #lastSize 109 | "", #Volume 110 | sep=","), "\n", file=file, append=TRUE) 111 | data[[id]][nr.data,1] <- msg[4] 112 | } else 113 | if(tickType == .twsTickType$ASK_SIZE) { 114 | cat(paste(timestamp, 115 | "", #bidSize 116 | "", #bidPrice 117 | "", #askPrice 118 | msg[4], #askSize 119 | "", #lastPrice 120 | "", #lastSize 121 | "", #Volume 122 | sep=","), "\n", file=file, append=TRUE) 123 | data[[id]][nr.data,4] <- msg[4] 124 | } else 125 | if(tickType == .twsTickType$LAST_SIZE) { 126 | cat(paste(timestamp, 127 | "", #bidSize 128 | "", #bidPrice 129 | "", #askPrice 130 | "", #askSize 131 | "", #lastPrice 132 | msg[4], #lastSize 133 | "", #Volume 134 | sep=","), "\n", file=file, append=TRUE) 135 | data[[id]][nr.data,6] <- msg[4] 136 | } else 137 | if(tickType == .twsTickType$VOLUME) { 138 | cat(paste(timestamp, 139 | "", #bidSize 140 | "", #bidPrice 141 | "", #askPrice 142 | "", #askSize 143 | "", #lastPrice 144 | "", #lastSize 145 | msg[4], #Volume 146 | sep=","), "\n", file=file, append=TRUE) 147 | data[[id]][nr.data,7] <- msg[4] 148 | } 149 | eW$assign.Data("data", data) 150 | c(curMsg, msg) # processMsg sees this raw vector 151 | } 152 | 153 | return(eW) 154 | } 155 | -------------------------------------------------------------------------------- /R/eWrapper.MktDepth.CSV.R: -------------------------------------------------------------------------------- 1 | eWrapper.MktDepth.CSV <- function() { 2 | eW <- eWrapper(NULL) 3 | eW$updateMktDepth <- function(curMsg, msg, timestamp, file, ...) { 4 | #symbols <- eW$get.Data("symbols") 5 | e_update_mkt_depth_csv(NULL, msg, timestamp, file, ...) 6 | } 7 | eW 8 | } 9 | 10 | e_update_mkt_depth_csv <- function (msg, contents, timeStamp, file, ...) 11 | { 12 | id <- as.numeric(contents[2]) 13 | file <- file[[id]] 14 | cat(id,",", 15 | as.character(timeStamp),",", 16 | contents[3],",", # position 17 | contents[4],",", # 0=insert, 1=update, 2=delete (operation) 18 | contents[5],",", # 1=bid, 2=ask (side) 19 | contents[6],",", # price 20 | contents[7], # size 21 | "\n", 22 | sep="",file=file,append=TRUE) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /R/eWrapper.R: -------------------------------------------------------------------------------- 1 | eWrapper <- function(debug=FALSE, errfile=stderr()) { 2 | # environment for data to be stored/accessed between messages 3 | # an example of this functionality is for the "symbols" variable 4 | # that can be set (by default) to display contract names 5 | .Data <- new.env() 6 | get.Data <- function(x) get(x,.Data) 7 | assign.Data <- function(x, value) assign(x, value, .Data) 8 | remove.Data <- function(x) remove(x, .Data) 9 | 10 | # three branches: 11 | # the first is a version that returns nothing. Useful as a template. 12 | # the second is the non-debug version (defaults console output) 13 | # the third is the debug version (raw data console output) 14 | 15 | if(is.null(debug)) { 16 | errorMessage <- function(curMsg, msg, timestamp, file, twsconn, ...) 17 | { 18 | cat(msg,"\n", file=errfile) 19 | #c(curMsg, msg) 20 | } 21 | tickPrice <- tickSize <- 22 | tickOptionComputation <- tickGeneric <- 23 | tickString <- tickEFP <- 24 | orderStatus <- openOrder <- openOrderEnd <- 25 | updateAccountValue <- updateAccountTime <- updatePortfolio <- 26 | accountDownloadEnd <- nextValidId <- 27 | contractDetails <- bondContractDetails <- 28 | contractDetailsEnd <- execDetails <- execDetailsEnd <- 29 | updateMktDepth <- updateMktDepthL2 <- 30 | updateNewsBulletin <- managedAccounts <- 31 | receiveFA <- historicalData <- 32 | scannerParameters <- scannerData <- scannerDataEnd <- 33 | realtimeBars <- currentTime <- fundamentalData <- 34 | deltaNeutralValidation <- tickSnapshotEnd <- 35 | function(curMsg, msg, timestamp, file, ...) { c(curMsg,msg) } 36 | } else 37 | if(!debug) { 38 | tickPrice <- function(curMsg, msg, timestamp, file, ...) 39 | { 40 | symbols <- get.Data("symbols") 41 | e_tick_price(NULL,msg,timestamp,file, symbols,...) 42 | } 43 | tickSize <- function(curMsg, msg, timestamp, file, ...) 44 | { 45 | symbols <- get.Data("symbols") 46 | e_tick_size(NULL, msg, timestamp, file, symbols, ...) 47 | } 48 | tickOptionComputation <- function(curMsg, msg, timestamp, file, ...) 49 | { 50 | symbols <- get.Data("symbols") 51 | e_tick_option(NULL, msg, timestamp, file, symbols, ...) 52 | } 53 | tickGeneric <- function(curMsg, msg, timestamp, file, ...) 54 | { 55 | symbols <- get.Data("symbols") 56 | e_tick_generic(NULL, msg, timestamp, file, symbols, ...) 57 | } 58 | tickString <- function(curMsg, msg, timestamp, file, ...) 59 | { 60 | symbols <- get.Data("symbols") 61 | e_tick_string(NULL, msg, timestamp, file, symbols, ...) 62 | } 63 | tickEFP <- function(curMsg, msg, timestamp, file, ...) 64 | { 65 | symbols <- get.Data("symbols") 66 | e_tick_EFP(NULL, msg, timestamp, file, symbols, ...) 67 | } 68 | orderStatus <- function(curMsg, msg, timestamp, file, ...) { 69 | e_order_status(curMsg, msg) 70 | c(curMsg, msg) 71 | } 72 | errorMessage <- function(curMsg, msg, timestamp, file, twsconn, ...) 73 | { 74 | if(msg[3] == "1100") 75 | twsconn$connected <- FALSE 76 | if(msg[3] %in% c("1101","1102")) 77 | twsconn$connected <- TRUE 78 | cat("TWS Message:",msg,"\n") 79 | } 80 | openOrder <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 81 | openOrderEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 82 | updateAccountValue <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 83 | updatePortfolio <- function(curMsg, msg, timestamp, file, ...) { 84 | e_portfolio_value(curMsg, msg) 85 | c(curMsg, msg) 86 | } 87 | updateAccountTime <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 88 | accountDownloadEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 89 | nextValidId <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 90 | contractDetails <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 91 | bondContractDetails <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 92 | contractDetailsEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 93 | execDetails <- function(curMsg, msg, timestamp, file, ...) { 94 | e_execDetails(curMsg, msg, file, ...) 95 | #c(curMsg, msg) 96 | } 97 | execDetailsEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 98 | updateMktDepth <- function(curMsg, msg, timestamp, file, ...) 99 | { 100 | symbols <- get.Data("symbols") 101 | e_update_mkt_depth(NULL, msg, timestamp, file, symbols, ...) 102 | } 103 | updateMktDepthL2 <- function(curMsg, msg, timestamp, file, ...) 104 | { 105 | symbols <- get.Data("symbols") 106 | e_update_mkt_depthL2(NULL, msg, timestamp, file, symbols, ...) 107 | } 108 | updateNewsBulletin <- function(curMsg, msg, timestamp, file, ...) 109 | { 110 | cat("newsMsgId: ",msg[2], 111 | "newsMsgType: ",msg[3], 112 | "newsMessage: ",msg[4], 113 | "origExch:", msg[5], "\n") 114 | c(curMsg, msg) 115 | } 116 | managedAccounts <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 117 | receiveFA <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 118 | historicalData <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 119 | scannerParameters <- function(curMsg, msg, timestamp, file, ...) { 120 | cat(msg <- rawToChar(msg[ -which(msg == as.raw(0))])) 121 | c(curMsg, msg) 122 | } 123 | scannerData <- function(curMsg, reqId, rank, contract, distance, 124 | benchmark, projection, legsStr) 125 | { 126 | e_scannerData(curMsg, reqId, rank, contract, distance, benchmark, projection, legsStr) 127 | } 128 | scannerDataEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 129 | realtimeBars <- function(curMsg, msg, timestamp, file, ...) 130 | { 131 | symbols <- get.Data("symbols") 132 | e_real_time_bars(curMsg, msg, symbols, file, ...) 133 | } 134 | currentTime <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 135 | fundamentalData <- function(curMsg, msg, timestamp, file, ...) 136 | { 137 | e_fundamentalData(curMsg, msg) 138 | } 139 | deltaNeutralValidation <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 140 | tickSnapshotEnd <- function(curMsg, msg, timestamp, file, ...) { c(curMsg, msg) } 141 | } else { 142 | # DEBUG code [ twsDEBUG ] 143 | tickPrice <- tickSize <- 144 | tickOptionComputation <- tickGeneric <- 145 | tickString <- tickEFP <- 146 | orderStatus <- openOrder <- openOrderEnd <- 147 | updateAccountValue <- updateAccountTime <- updatePortfolio <- 148 | accountDownloadEnd <- nextValidId <- 149 | contractDetails <- bondContractDetails <- 150 | contractDetailsEnd <- execDetails <- execDetailsEnd <- 151 | updateMktDepth <- updateMktDepthL2 <- 152 | updateNewsBulletin <- managedAccounts <- 153 | receiveFA <- historicalData <- 154 | scannerParameters <- scannerData <- scannerDataEnd <- 155 | realtimeBars <- currentTime <- fundamentalData <- 156 | deltaNeutralValidation <- tickSnapshotEnd <- 157 | function(curMsg, msg, timestamp, file, ...) { 158 | cat(as.character(timestamp),curMsg, msg,"\n",file=file[[1]], append=TRUE,...) 159 | } 160 | errorMessage <- function(curMsg, msg, timestamp, file, twsconn, ...) { 161 | cat(as.character(timestamp),curMsg, msg,"\n",file=file[[1]], append=TRUE,...) 162 | } 163 | } 164 | 165 | eW <- list( 166 | .Data = .Data, get.Data = get.Data, assign.Data = assign.Data, remove.Data = remove.Data, 167 | tickPrice = tickPrice , 168 | tickSize = tickSize , 169 | tickOptionComputation = tickOptionComputation , 170 | tickGeneric = tickGeneric , 171 | tickString = tickString , 172 | tickEFP = tickEFP , 173 | orderStatus = orderStatus , 174 | errorMessage = errorMessage, 175 | openOrder = openOrder , 176 | openOrderEnd = openOrderEnd , 177 | updateAccountValue = updateAccountValue , 178 | updatePortfolio = updatePortfolio , 179 | updateAccountTime = updateAccountTime , 180 | accountDownloadEnd = accountDownloadEnd , 181 | nextValidId = nextValidId , 182 | contractDetails = contractDetails , 183 | bondContractDetails = bondContractDetails , 184 | contractDetailsEnd = contractDetailsEnd , 185 | execDetails = execDetails , 186 | execDetailsEnd = execDetailsEnd , 187 | updateMktDepth = updateMktDepth , 188 | updateMktDepthL2 = updateMktDepthL2 , 189 | updateNewsBulletin = updateNewsBulletin , 190 | managedAccounts = managedAccounts , 191 | receiveFA = receiveFA , 192 | historicalData = historicalData , 193 | scannerParameters = scannerParameters , 194 | scannerData = scannerData , 195 | scannerDataEnd = scannerDataEnd , 196 | realtimeBars = realtimeBars , 197 | currentTime = currentTime , 198 | fundamentalData = fundamentalData , 199 | deltaNeutralValidation = deltaNeutralValidation, 200 | tickSnapshotEnd = tickSnapshotEnd) 201 | class(eW) <- "eWrapper" 202 | invisible(eW) 203 | } 204 | -------------------------------------------------------------------------------- /R/eWrapper.data.R: -------------------------------------------------------------------------------- 1 | # eWrapper.data is a event wrapper that 2 | # updates an in memory data base of values 3 | # upon new input from the TWS 4 | # 5 | # This is only implemented for realtimeBars callbacks 6 | # at present, but will be extended in the near future 7 | # to include all events 8 | 9 | eWrapper.data <- function(n) { 10 | # internally updated data 11 | # .data. <- character(8) 12 | # 13 | # get.data <- function() return(.data.) 14 | # 15 | eW <- eWrapper(NULL) # use basic template 16 | eW$assign.Data("data", rep(list(structure(.xts(matrix(rep(NA_real_,7),ncol=7),0), 17 | .Dimnames=list(NULL, 18 | c("BidSize","BidPrice", 19 | "AskPrice","AskSize", 20 | "Last","LastSize","Volume")))),n)) 21 | 22 | eW$tickPrice <- function(curMsg, msg, timestamp, file, ...) 23 | { 24 | tickType = msg[3] 25 | msg <- as.numeric(msg) 26 | id <- msg[2] #as.numeric(msg[2]) 27 | data <- eW$get.Data("data") #[[1]] # list position of symbol (by id == msg[2]) 28 | attr(data[[id]],"index") <- as.numeric(Sys.time()) 29 | # data[[1]] <- rbind(data[[1]],.xts(matrix(rep(NA_real_,7),nc=7), Sys.time())) 30 | nr.data <- NROW(data[[id]]) 31 | #data[[id]][1] <- as.numeric(Sys.time()) #timestamp 32 | if(tickType == .twsTickType$BID) { 33 | data[[id]][nr.data,1:2] <- msg[5:4] 34 | } else 35 | if(tickType == .twsTickType$ASK) { 36 | data[[id]][nr.data,3:4] <- msg[4:5] 37 | } else 38 | if(tickType == .twsTickType$LAST) { 39 | data[[id]][nr.data,5] <- msg[4] 40 | } 41 | eW$assign.Data("data", data) 42 | c(curMsg, msg) 43 | } 44 | eW$tickSize <- function(curMsg, msg, timestamp, file, ...) 45 | { 46 | data <- eW$get.Data("data") 47 | tickType = msg[3] 48 | msg <- as.numeric(msg) 49 | id <- as.numeric(msg[2]) 50 | # data[[1]] <- rbind(data[[1]],.xts(matrix(rep(NA_real_,7),nc=7), Sys.time())) 51 | attr(data[[id]],"index") <- as.numeric(Sys.time()) 52 | nr.data <- NROW(data[[id]]) 53 | #data[[id]][1] <- as.numeric(Sys.time()) #timestamp 54 | if(tickType == .twsTickType$BID_SIZE) { 55 | data[[id]][nr.data,1] <- msg[4] 56 | } else 57 | if(tickType == .twsTickType$ASK_SIZE) { 58 | data[[id]][nr.data,4] <- msg[4] 59 | } else 60 | if(tickType == .twsTickType$LAST_SIZE) { 61 | data[[id]][nr.data,6] <- msg[4] 62 | } else 63 | if(tickType == .twsTickType$VOLUME) { 64 | data[[id]][nr.data,7] <- msg[4] 65 | } 66 | eW$assign.Data("data", data) 67 | c(curMsg, msg) 68 | } 69 | return(eW) 70 | } 71 | 72 | eWrapper.RealTimeBars <- function(nbars=1, nsymbols=1) { 73 | eW <- eWrapper(NULL) # use basic template 74 | 75 | eW$realtimeBars <- function(curMsg, msg, timestamp, file, ...) 76 | { 77 | id <- as.numeric(msg[2]) 78 | data <- eW$get.Data("data") #[[1]] # list position of symbol (by id == msg[2]) 79 | data[[id]][1] <- as.numeric(msg[3]) 80 | data[[id]][2:8] <- as.numeric(msg[4:10]) 81 | eW$assign.Data("data", data) 82 | c(curMsg, msg) 83 | } 84 | return(eW) 85 | } 86 | -------------------------------------------------------------------------------- /R/eWrapper.snapshot.R: -------------------------------------------------------------------------------- 1 | eWrapper.snapshot <- function() { 2 | eW <- eWrapper(NULL) 3 | eW$assign.Data("EOD", FALSE) 4 | sapply(c("bidSize","bidPrice", 5 | "askPrice","askSize", 6 | "lastPrice", 7 | "Open","High","Low","Close", 8 | "lastSize","Volume","lastTimeStamp"), function(X) eW$assign.Data(X, NA)) 9 | eW$tickPrice <- function(curMsg, msg, timestamp, file, ...) 10 | { 11 | tickType = msg[3] 12 | if(tickType == .twsTickType$BID) { 13 | eW$assign.Data("bidPrice", as.numeric(msg[4])) 14 | eW$assign.Data("bidSize" , as.numeric(msg[5])) 15 | } else 16 | if(tickType == .twsTickType$ASK) { 17 | eW$assign.Data("askPrice", as.numeric(msg[4])) 18 | eW$assign.Data("askSize" , as.numeric(msg[5])) 19 | } else 20 | if(tickType == .twsTickType$LAST) { 21 | eW$assign.Data("lastPrice", as.numeric(msg[4])) 22 | } else 23 | if(tickType == .twsTickType$OPEN) { 24 | eW$assign.Data("Open", as.numeric(msg[4])) 25 | } else 26 | if(tickType == .twsTickType$HIGH) { 27 | eW$assign.Data("High", as.numeric(msg[4])) 28 | } else 29 | if(tickType == .twsTickType$LOW) { 30 | eW$assign.Data("Low", as.numeric(msg[4])) 31 | } else 32 | if(tickType == .twsTickType$CLOSE) { 33 | eW$assign.Data("Close", as.numeric(msg[4])) 34 | } 35 | } 36 | eW$tickSize <- function(curMsg, msg, timestamp, file, ...) 37 | { 38 | tickType <- msg[3] 39 | if(tickType == .twsTickType$LAST_SIZE) { 40 | eW$assign.Data("lastSize", as.numeric(msg[4])) 41 | } else 42 | if(tickType == .twsTickType$VOLUME) { 43 | eW$assign.Data("Volume", as.numeric(msg[4])) 44 | } 45 | } 46 | eW$tickString <- function(curMsg, msg, timestamp, file, ...) 47 | { 48 | tickType <- msg[3] 49 | eW$assign.Data("lastTimeStamp", structure(as.numeric(msg[4]), 50 | class=c("POSIXt","POSIXct"))) 51 | } 52 | eW$tickSnapshotEnd <- function(curMsg, msg, timestamp, file, ...) 53 | { 54 | eW$assign.Data("EOD", TRUE) 55 | } 56 | return(eW) 57 | } 58 | -------------------------------------------------------------------------------- /R/eWrapper.updateAccount.R: -------------------------------------------------------------------------------- 1 | eWrapper.updateAccount <- function() { 2 | eW <- eWrapper(NULL) 3 | eW$assign.Data("PORTFOLIO_VALUE",vector("list")) 4 | eW$updateAccountValue <- function(curMsg,msg,timestamp,file,...) { 5 | PV <- eW$get.Data("PORTFOLIO_VALUE") 6 | PV$version <- as.numeric(msg[1]) 7 | 8 | } 9 | eW$updatePortfolioValue <- function(curMsg,msg,timestamp,file,...) { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /R/errorHandler.R: -------------------------------------------------------------------------------- 1 | `errorHandler` <- 2 | function(con, verbose, OK=NULL) { 3 | err <- readBin(con,character(),4) 4 | 5 | if(as.numeric(err[3]) %in% OK || as.numeric(err[3]) > 1000) { 6 | if(as.numeric(err[3]) == 1100) { 7 | 8 | #close(con) # instead of closing connection, we'll 9 | warning(err[4]) 10 | } 11 | if(verbose > 1) { 12 | warning(err[4]) 13 | return(TRUE) 14 | } else return(TRUE) 15 | } else { 16 | if(verbose > 0) #warning(paste(.twsERR[err[3],])) 17 | warning(err[4]) 18 | return(FALSE) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /R/exerciseOptions.R: -------------------------------------------------------------------------------- 1 | exerciseOptions <- function(twsconn, contract, exerciseAction=1, 2 | exerciseQuantity=1, account="", override=0, tickerId=1) { 3 | if( !is.twsConnection(twsconn)) 4 | stop('invalid twsconn') 5 | if( !is.twsContract(contract)) 6 | stop('invalid twsContract') 7 | 8 | # check parameters for valid ranges 9 | if( !as.numeric(exerciseAction) %in% 1:2) 10 | stop('valid exerciseAction is 1 or 2') 11 | if( !as.numeric(override) %in% 0:1) 12 | stop('valid overrride is 0 or 1') 13 | 14 | VERSION <- "1" 15 | 16 | msg <- c( .twsOutgoingMSG$EXERCISE_OPTION, 17 | VERSION, 18 | tickerId, 19 | contract$symbol, 20 | contract$sectype, 21 | contract$expiry, 22 | contract$strike, 23 | contract$multiplier, 24 | contract$exch, 25 | contract$currency, 26 | contract$local, 27 | exerciseAction, 28 | exerciseQuantity, 29 | account, 30 | override) 31 | 32 | writeBin(as.character(msg), twsconn[[1]]) 33 | } 34 | -------------------------------------------------------------------------------- /R/get_account.R: -------------------------------------------------------------------------------- 1 | cancelAccountUpdates <- function(ib_connect, acctCode="1") { 2 | if(!is.twsConnection(ib_connect)) 3 | stop("requires twsConnection object") 4 | .get_account(ib_connect, "0", acctCode) 5 | } # end cancelAccountUpdates 6 | 7 | 8 | .get_account <- function(ib_connect, subscribe=TRUE, acctCode="1") { 9 | if (!is.twsConnection(ib_connect)) 10 | stop("requires twsConnection object") 11 | 12 | sock_et <- ib_connect[[1]] 13 | VERSION <- "2" 14 | 15 | # send messages to TWS 16 | writeBin(.twsOutgoingMSG$REQ_ACCOUNT_DATA, sock_et) 17 | writeBin(VERSION, sock_et) 18 | writeBin(as.character(as.numeric(subscribe)), sock_et) 19 | writeBin(as.character(acctCode), sock_et) 20 | } # end .get_account 21 | 22 | 23 | # Run callback loop without CALLBACK function 24 | # eventWrapper is not used 25 | get_account <- function(ib_connect, 26 | subscribe=TRUE, 27 | acctCode="1", 28 | file_connects=NULL, 29 | eventWrapper=eWrapper(), 30 | CALLBACK=twsCALLBACK, ...) { 31 | if (!is.twsConnection(ib_connect)) 32 | stop("requires twsConnection object") 33 | 34 | .get_account(ib_connect, subscribe, acctCode) 35 | 36 | on.exit(.get_account(ib_connect, "0", acctCode)) 37 | 38 | verbose <- FALSE 39 | acct <- list() 40 | sock_et <- ib_connect[[1]] 41 | e_wrapper <- eWrapper(NULL) 42 | e_wrapper$assign.Data("data", structure(list(), class="eventAccountValue")) 43 | 44 | # Define callback function called by processMsg 45 | e_wrapper$updatePortfolio <- function (curMsg, msg, ...) { 46 | version <- as.numeric(msg[1]) 47 | contract <- twsContract(conId=msg[2], symbol=msg[3], 48 | sectype=msg[4], exch=msg[9], primary=msg[9], expiry=msg[5], 49 | strike=msg[6], currency=msg[10], right=msg[7], 50 | local=msg[11], multiplier=msg[8], combo_legs_desc="", 51 | comboleg="", include_expired="") 52 | portfolioValue <- list() 53 | portfolioValue$position <- as.numeric(msg[12]) 54 | portfolioValue$marketPrice <- as.numeric(msg[13]) 55 | portfolioValue$marketValue <- as.numeric(msg[14]) 56 | portfolioValue$averageCost <- as.numeric(msg[15]) 57 | portfolioValue$unrealizedPNL <- as.numeric(msg[16]) 58 | portfolioValue$realizedPNL <- as.numeric(msg[17]) 59 | portfolioValue$accountName <- msg[18] 60 | p <- structure(list(contract=contract, portfolioValue=portfolioValue), class="eventPortfolioValue") 61 | p 62 | } # end updatePortfolio 63 | 64 | # Define callback function called by processMsg 65 | e_wrapper$updateAccountValue <- function (curMsg, msg, ...) { 66 | data <- e_wrapper$get.Data("data") 67 | data[[msg[2]]] <- c(value=msg[3], currency=msg[4]) 68 | e_wrapper$assign.Data("data", data) 69 | } # end updateAccountValue 70 | 71 | 72 | # acct_msgs <- with(.twsIncomingMSG, 73 | # c(ACCT_VALUE,PORTFOLIO_VALUE,ACCT_UPDATE_TIME)) 74 | 75 | # Callback loop 76 | timestamp <- NULL 77 | while (TRUE) { 78 | socketSelect(list(sock_et), FALSE, NULL) 79 | curMsg <- readBin(sock_et, "character", 1) 80 | cat("curMsg: ", curMsg, "\n") 81 | # if (!curMsg %in% acct_msgs) { 82 | # if (curMsg == .twsIncomingMSG$ERR_MSG) { 83 | # if (!errorHandler(sock_et, verbose, OK=c(165, 300, 84 | # 366, 2104, 2106, 2107))) { 85 | # warning("error in get_account details") 86 | # break 87 | # } 88 | # } 89 | # else { 90 | # processMsg(curMsg, sock_et, e_wrapper, timestamp, file_connects) 91 | # if (curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) 92 | # break 93 | # } 94 | # } 95 | if (curMsg == .twsIncomingMSG$PORTFOLIO_VALUE) { 96 | acct[[length(acct) + 1]] <- processMsg(curMsg, sock_et, e_wrapper, timestamp, file_connects) 97 | } else { 98 | processMsg(curMsg, sock_et, e_wrapper, timestamp, file_connects) 99 | } 100 | if (curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) 101 | break 102 | } # end while 103 | 104 | return(structure(list(e_wrapper$get.Data("data"), acct), class="AccountUpdate")) 105 | 106 | # CALLBACK(ib_connect, eventWrapper, NULL, file_connects) 107 | } # end get_account 108 | -------------------------------------------------------------------------------- /R/get_open_orders.R: -------------------------------------------------------------------------------- 1 | cancelAccountUpdates <- function(ib_connect, acctCode="1") { 2 | if(!is.twsConnection(ib_connect)) 3 | stop("requires twsConnection object") 4 | .get_open_orders(ib_connect, "0", acctCode) 5 | } # end cancelAccountUpdates 6 | 7 | 8 | .get_open_orders <- function(ib_connect, subscribe=TRUE) { 9 | if (!IBrokers2::is.twsConnection(ib_connect)) 10 | stop("requires twsConnection object") 11 | 12 | sock_et <- ib_connect[[1]] 13 | VERSION <- "1" 14 | 15 | # send messages to TWS 16 | writeBin(c(IBrokers2::.twsOutgoingMSG$REQ_OPEN_ORDERS, VERSION), sock_et) 17 | writeBin(as.character(as.numeric(subscribe)), sock_et) 18 | } # end .get_open_orders 19 | 20 | 21 | # Run callback loop without CALLBACK function 22 | # eventWrapper is not used 23 | get_open_orders <- function(ib_connect, 24 | subscribe=TRUE) { 25 | 26 | if (!IBrokers2::is.twsConnection(ib_connect)) 27 | stop("requires twsConnection object") 28 | 29 | .get_open_orders(ib_connect, subscribe=TRUE) 30 | 31 | # on.exit(.get_open_orders(ib_connect, subscribe=FALSE)) 32 | 33 | verbose <- FALSE 34 | acct <- list() 35 | sock_et <- ib_connect[[1]] 36 | 37 | socketSelect(list(sock_et), FALSE, NULL) 38 | curMsg <- readBin(sock_et, "character", 1L) 39 | msg <- readBin(sock_et, "character", 84) 40 | cat("curMsg: ", curMsg, "\n") 41 | 42 | .get_open_orders(ib_connect, subscribe=FALSE) 43 | c(curMsg=curMsg, msg=msg) 44 | 45 | } # end get_open_orders 46 | -------------------------------------------------------------------------------- /R/placeOrder.R: -------------------------------------------------------------------------------- 1 | placeOrder <- .placeOrder <- 2 | function(twsconn,Contract,Order) 3 | { 4 | if(!is.twsConnection(twsconn)) 5 | stop('requires twsConnection object') 6 | 7 | if(!is.twsContract(Contract)) 8 | stop('requires twsContract object for Contract arg') 9 | 10 | if(!inherits(Order, 'twsOrder')) 11 | stop('requires twsOrder object for Order arg') 12 | 13 | con <- twsconn[[1]] 14 | 15 | #VERSION <- "28" # Version as of API 9.62 16 | VERSION <- "29" # Version as of API 9.63 17 | #VERSION <- "30" # Version as of API 9.64 18 | if(Order$orderId == "") 19 | Order$orderId <- reqIds(twsconn) 20 | 21 | # write order {{{ 22 | order <- c(.twsOutgoingMSG$PLACE_ORDER, 23 | VERSION, 24 | as.character(Order$orderId), 25 | Contract$symbol, 26 | Contract$sectype, 27 | Contract$expiry, 28 | Contract$strike, 29 | Contract$right, 30 | Contract$multiplier, 31 | Contract$exch, 32 | Contract$primary, 33 | Contract$currency, 34 | Contract$local, 35 | 36 | # as of 9.63 37 | Contract$secIdType, 38 | Contract$secId, 39 | 40 | Order$action, 41 | Order$totalQuantity, 42 | Order$orderType, 43 | Order$lmtPrice, 44 | Order$auxPrice, 45 | Order$tif, 46 | Order$ocaGroup, 47 | Order$account, 48 | Order$openClose, 49 | Order$origin, 50 | Order$orderRef, 51 | Order$transmit, 52 | Order$parentId, 53 | Order$blockOrder, 54 | Order$sweepToFill, 55 | Order$displaySize, 56 | Order$triggerMethod, 57 | Order$outsideRTH, 58 | Order$hidden) 59 | 60 | if(Contract$sectype == "BAG") { 61 | if(is.null(Contract$comboleg)) { 62 | order <- c(order, 0) 63 | } else { 64 | comboLeg <- Contract$comboleg 65 | order <- c(order, length(comboLeg)) 66 | for(i in 1:length(comboLeg)) { 67 | Leg <- comboLeg[[i]] 68 | order <- c(order, 69 | Leg$conId, 70 | Leg$ratio, 71 | Leg$action, 72 | Leg$exch, 73 | Leg$openClose, 74 | Leg$shortSaleSlot, 75 | Leg$designatedLocation) 76 | } 77 | } 78 | } 79 | 80 | order <- c(order, 81 | "", # DEPRECATED FIELD 82 | Order$discretionaryAmt, 83 | Order$goodAfterTime, 84 | Order$goodTillDate, 85 | Order$faGroup, 86 | Order$faMethod, 87 | Order$faPercentage, 88 | Order$faProfile, 89 | Order$shortSaleSlot, 90 | Order$designatedLocation, 91 | Order$ocaType, 92 | Order$rule80A, 93 | Order$settlingFirm, 94 | Order$allOrNone, 95 | Order$minQty, 96 | Order$percentOffset, 97 | Order$eTradeOnly, 98 | Order$firmQuoteOnly, 99 | Order$nbboPriceCap, 100 | Order$auctionStrategy, 101 | Order$startingPrice, 102 | Order$stockRefPrice, 103 | Order$delta, 104 | Order$stockRangeLower, 105 | Order$stockRangeUpper, 106 | Order$overridePercentageConstraints, 107 | Order$volatility, 108 | Order$volatilityType, 109 | Order$deltaNeutralOrderType, 110 | Order$deltaNeutralAuxPrice, 111 | Order$continuousUpdate, 112 | Order$referencePriceType, 113 | Order$trailStopPrice, 114 | Order$scaleInitLevelSize, 115 | Order$scaleSubsLevelSize, 116 | Order$scalePriceIncrement, 117 | Order$clearingAccount, 118 | Order$clearingIntent, 119 | Order$notHeld, 120 | "0", # Order$underComp .. not yet supported by IBrokers 121 | "", # Order$algoStrategy .. not yet supported by IBrokers 122 | Order$whatIf 123 | ) 124 | # }}} 125 | 126 | writeBin(order, con) 127 | assign(".Last.orderId", as.integer(Order$orderId), .IBrokersEnv) 128 | invisible(as.integer(Order$orderId)) 129 | } 130 | 131 | ..placeOrder <- 132 | function(conn, 133 | Contract, 134 | Order, 135 | verbose=TRUE, 136 | eventExecutionData, 137 | eventOpenOrder, 138 | eventOrderStatus, 139 | CALLBACK, ...) { 140 | 141 | if(!is.twsConnection(conn)) 142 | stop('requires twsConnection object') 143 | 144 | if(!is.twsContract(Contract)) 145 | stop('requires twsContract object for Contract arg') 146 | 147 | if(!inherits(Order, 'twsOrder')) 148 | stop('requires twsOrder object for Order arg') 149 | 150 | if(missing(CALLBACK)) { 151 | if(missing(eventOrderStatus)) 152 | eventOrderStatus <- e_order_status 153 | 154 | if(missing(eventOpenOrder)) 155 | eventOpenOrder <- e_open_order 156 | 157 | if(missing(eventExecutionData)) 158 | eventExecutionData <- e_execution_data 159 | } 160 | else if(is.null(CALLBACK)) { 161 | eventOrderStatus <- NULL 162 | eventOpenOrder <- NULL 163 | eventExecutionData <- NULL 164 | } 165 | 166 | con <- conn[[1]] 167 | 168 | VERSION <- "28" # Version as of API 9.62 169 | 170 | # write order {{{ 171 | order <- c(.twsOutgoingMSG$PLACE_ORDER, 172 | VERSION, 173 | as.character(Order$orderId), 174 | Contract$symbol, 175 | Contract$sectype, 176 | Contract$expiry, 177 | Contract$strike, 178 | Contract$right, 179 | Contract$multiplier, 180 | Contract$exch, 181 | Contract$primary, 182 | Contract$currency, 183 | Contract$local, 184 | Order$action, 185 | Order$totalQuantity, 186 | Order$orderType, 187 | Order$lmtPrice, 188 | Order$auxPrice, 189 | Order$tif, 190 | Order$ocaGroup, 191 | Order$account, 192 | Order$openClose, 193 | Order$origin, 194 | Order$orderRef, 195 | Order$transmit, 196 | Order$parentId, 197 | Order$blockOrder, 198 | Order$sweepToFill, 199 | Order$displaySize, 200 | Order$triggerMethod, 201 | Order$outsideRTH, 202 | Order$hidden, 203 | "", # DEPRECATED FIELD 204 | Order$discretionaryAmt, 205 | Order$goodAfterTime, 206 | Order$goodTillDate, 207 | Order$faGroup, 208 | Order$faMethod, 209 | Order$faPercentage, 210 | Order$faProfile, 211 | Order$shortSaleSlot, 212 | Order$designatedLocation, 213 | Order$ocaType, 214 | Order$rule80A, 215 | Order$settlingFirm, 216 | Order$allOrNone, 217 | Order$minQty, 218 | Order$percentOffset, 219 | Order$eTradeOnly, 220 | Order$firmQuoteOnly, 221 | Order$nbboPriceCap, 222 | Order$auctionStrategy, 223 | Order$startingPrice, 224 | Order$stockRefPrice, 225 | Order$delta, 226 | Order$stockRangeLower, 227 | Order$stockRangeUpper, 228 | Order$overridePercentageConstraints, 229 | Order$volatility, 230 | Order$volatilityType, 231 | Order$deltaNeutralOrderType, 232 | Order$deltaNeutralAuxPrice, 233 | Order$continuousUpdate, 234 | Order$referencePriceType, 235 | Order$trailStopPrice, 236 | Order$scaleInitLevelSize, 237 | Order$scaleSubsLevelSize, 238 | Order$scalePriceIncrement, 239 | Order$clearingAccount, 240 | Order$clearingIntent, 241 | Order$notHeld, 242 | "0", # Order$underComp .. not yet supported by IBrokers 243 | "", # Order$algoStrategy .. not yet supported by IBrokers 244 | Order$whatIf 245 | ) 246 | # }}} 247 | 248 | writeBin(order, con) 249 | 250 | waiting <- TRUE 251 | 252 | if(missing(CALLBACK) || is.null(CALLBACK)) { 253 | while(waiting) { 254 | curMsg <- readBin(con,character(),1) 255 | 256 | if (length(curMsg) > 0) { 257 | if (curMsg == .twsIncomingMSG$ERR_MSG) { 258 | if (!errorHandler(con, verbose, OK = c(165, 259 | 399, 300, 366, 2104, 2106, 2107))) { 260 | cat("\n") 261 | stop("Unable to complete market data request") 262 | } 263 | } 264 | if (curMsg == .twsIncomingMSG$OPEN_ORDER) { 265 | contents <- readBin(con, character(), 84) 266 | if (is.null(eventOrderStatus)) { 267 | cat(curMsg, paste(contents), "\n") 268 | } else cat(str(eventOpenOrder(curMsg, contents, ...))) 269 | } 270 | if (curMsg == .twsIncomingMSG$ORDER_STATUS) { 271 | contents <- readBin(con, character(), 11) 272 | if (is.null(eventOrderStatus)) { 273 | cat(curMsg, paste(contents), "\n") 274 | } else eventOrderStatus(curMsg, contents, ...) 275 | } 276 | if (curMsg == .twsIncomingMSG$EXECUTION_DATA) { 277 | contents <- readBin(con, character(), 21) 278 | if (is.null(eventOrderStatus)) { 279 | cat(curMsg, paste(contents), "\n") 280 | } else cat(str(eventExecutionData(curMsg, contents, ...))) 281 | } 282 | } 283 | } 284 | } else CALLBACK(con, ...) 285 | } 286 | -------------------------------------------------------------------------------- /R/processMsg.R: -------------------------------------------------------------------------------- 1 | # single event-loop modeled after official TWS-API 2 | # can be used as CALLBACK argument or modified 3 | # to process selected/all possible incoming messages 4 | 5 | twsDEBUG <- function(twsCon, eWrapper, timestamp, file, playback=1, ...) 6 | { 7 | eWrapper <- eWrapper(debug=TRUE) 8 | twsCALLBACK(twsCon, eWrapper, timestamp, file, playback, ...) 9 | } 10 | 11 | # tws <- twsConnect();CON2 <- twsConnect(2) 12 | # reqMktData(CON2, twsSTK("AAPL"), event=eWrapper(TRUE), CALLBACK=NA, tickerId="2") 13 | # reqMktData(tws, twsSTK("IBM"), event=eWrapper(symbols=c("AAPL","IBM"))) 14 | # close(tws); close(CON2) 15 | # uncomment the elements of twsCALLBACK as appropriate 16 | #' @export 17 | twsCALLBACK <- function(twsCon, eWrapper, timestamp, file, playback=1, ...) { 18 | if(missing(eWrapper)) 19 | eWrapper <- eWrapper() 20 | con <- twsCon[[1]] 21 | 22 | if(inherits(twsCon, 'twsPlayback')) { 23 | sys.time <- NULL 24 | while(TRUE) { 25 | if(!is.null(timestamp)) { 26 | # MktData 27 | last.time <- sys.time 28 | sys.time <- as.POSIXct(strptime(paste(readBin(con, character(), 2), collapse=' '), timestamp)) 29 | if(!is.null(last.time)) { 30 | Sys.sleep((sys.time-last.time)*playback) 31 | } 32 | curMsg <- readBin(con, character(), 1) 33 | if(length(curMsg) < 1) 34 | next 35 | processMsg(curMsg, con, eWrapper, format(sys.time, timestamp), file, ...) 36 | } else { 37 | # RealTimeBars 38 | curMsg <- readBin(con, character(), 1) 39 | if(length(curMsg) < 1) 40 | next 41 | processMsg(curMsg, con, eWrapper, timestamp, file, ...) 42 | if(curMsg == .twsIncomingMSG$REAL_TIME_BARS) Sys.sleep(5 * playback) 43 | } 44 | } 45 | } 46 | else { 47 | #dataCON <- get("DATACON", .GlobalEnv)[[1]] 48 | # This is the code that runs in live trading 49 | tryCatch( 50 | # Callback loop 51 | while(isConnected(twsCon)) { 52 | if (!socketSelect(list(con), FALSE, 0.25)) 53 | next 54 | curMsg <- readBin(con, "character", 1L) 55 | # Process the message 56 | if (!is.null(timestamp)) { 57 | processMsg(curMsg, con, eWrapper, format(Sys.time(), timestamp), file, twsCon, ...) 58 | } else { 59 | processMsg(curMsg, con, eWrapper, timestamp, file, twsCon, ...) 60 | } 61 | }, # end while 62 | # error handler 63 | error=function(e) { close(twsCon); stop("IB connection error. Connection closed", call.=FALSE) } 64 | ) # end tryCatch 65 | } # end if 66 | } # end twsCALLBACK 67 | 68 | 69 | #' @export 70 | processMsg <- function(curMsg, con, eWrapper, timestamp, file, twsconn, ...) { 71 | if(curMsg == .twsIncomingMSG$TICK_PRICE) { 72 | msg <- readBin(con, "character", 6) 73 | eWrapper$tickPrice(curMsg, msg, timestamp, file, ...) 74 | } else 75 | if(curMsg == .twsIncomingMSG$TICK_SIZE) { 76 | msg <- readBin(con, "character", 4) 77 | eWrapper$tickSize(curMsg, msg, timestamp, file, ...) 78 | } else 79 | if(curMsg == .twsIncomingMSG$ORDER_STATUS) { 80 | msg <- readBin(con, "character", 11) 81 | eWrapper$orderStatus(curMsg, msg, timestamp, file, ...) 82 | } else 83 | if(curMsg == .twsIncomingMSG$ERR_MSG) { 84 | msg <- readBin(con, "character", 4) 85 | eWrapper$errorMessage(curMsg, msg, timestamp, file, twsconn, ...) 86 | } else 87 | if(curMsg == .twsIncomingMSG$OPEN_ORDER) { 88 | msg <- readBin(con, "character", 84) 89 | eWrapper$openOrder(curMsg, msg, timestamp, file, ...) 90 | } else 91 | if(curMsg == .twsIncomingMSG$ACCT_VALUE) { 92 | msg <- readBin(con, "character", 5) 93 | eWrapper$updateAccountValue(curMsg, msg, timestamp, file, ...) 94 | } else 95 | if(curMsg == .twsIncomingMSG$PORTFOLIO_VALUE) { 96 | msg <- readBin(con, "character", 18) 97 | eWrapper$updatePortfolio(curMsg, msg, timestamp, file, ...) 98 | } else 99 | if(curMsg == .twsIncomingMSG$ACCT_UPDATE_TIME) { 100 | #msg <- readBin(con, character(), 2) 101 | msg <- readBin(con, "character", 2) 102 | eWrapper$updateAccountTime(curMsg, msg, timestamp, file, ...) 103 | } else 104 | if(curMsg == .twsIncomingMSG$NEXT_VALID_ID) { 105 | #msg <- readBin(con, character(), 2) 106 | msg <- readBin(con, "character", 2) 107 | eWrapper$nextValidId(curMsg, msg, timestamp, file, ...) 108 | } else 109 | if(curMsg == .twsIncomingMSG$CONTRACT_DATA) { 110 | #msg <- readBin(con, character(), 21) 111 | msg <- readBin(con, "character", 28) 112 | eWrapper$contractDetails(curMsg, msg, timestamp, file, ...) 113 | } else 114 | if(curMsg == .twsIncomingMSG$EXECUTION_DATA) { 115 | #msg <- readBin(con, character(), 24) 116 | msg <- readBin(con, "character", 24) 117 | eWrapper$execDetails(curMsg, msg, timestamp, file, ...) 118 | } else 119 | if(curMsg == .twsIncomingMSG$MARKET_DEPTH) { 120 | #msg <- readBin(con, character(), 7) 121 | msg <- readBin(con, "character", 7) 122 | eWrapper$updateMktDepth(curMsg, msg, timestamp, file, ...) 123 | } else 124 | if(curMsg == .twsIncomingMSG$MARKET_DEPTH_L2) { 125 | #msg <- readBin(con, character(), 8) 126 | msg <- readBin(con, "character", 8) 127 | eWrapper$updateMktDepthL2(curMsg, msg, timestamp, file, ...) 128 | } else 129 | if(curMsg == .twsIncomingMSG$NEWS_BULLETINS) { 130 | #msg <- readBin(con, character(), 5) 131 | msg <- readBin(con, "character", 5) 132 | eWrapper$newsBulletins(curMsg, msg, timestamp, file, ...) 133 | } else 134 | if(curMsg == .twsIncomingMSG$MANAGED_ACCTS) { 135 | #msg <- readBin(con, character(), 2) 136 | msg <- readBin(con, "character", 2) 137 | eWrapper$managedAccounts(curMsg, msg, timestamp, file, ...) 138 | } else 139 | if(curMsg == .twsIncomingMSG$RECEIVE_FA) { 140 | #msg <- readBin(con, character(), 2) # 3 with xml string 141 | msg <- readBin(con, "character", 2) 142 | stop("xml data currently unsupported") 143 | eWrapper$receiveFA(curMsg, msg, timestamp, file, ...) 144 | } else 145 | if(curMsg == .twsIncomingMSG$HISTORICAL_DATA) { 146 | header <- readBin(con, character(), 5) 147 | nbin <- as.numeric(header[5]) * 9 148 | msg <- readBin(con, character(), nbin) 149 | eWrapper$historicalData(curMsg, msg, timestamp, file, ...) 150 | } else 151 | if(curMsg == .twsIncomingMSG$BOND_CONTRACT_DATA) { 152 | warning("BOND_CONTRACT_DATA unimplemented as of yet") 153 | eWrapper$bondContractDetails(curMsg, msg, timestamp, file, ...) 154 | } else 155 | if(curMsg == .twsIncomingMSG$SCANNER_PARAMETERS) { 156 | version <- readBin(con, character(), 1L) 157 | msg <- readBin(con, raw(), 1e6L) 158 | eWrapper$scannerParameters(curMsg, msg, timestamp, file, ...) 159 | } else 160 | if(curMsg == .twsIncomingMSG$SCANNER_DATA) { 161 | cD <- twsContractDetails() 162 | version <- readBin(con, character(), 1L) 163 | tickerId <- readBin(con, character(), 1L) 164 | numberOfElements <- as.integer( readBin(con, character(), 1L) ) 165 | for(i in 1:numberOfElements) { 166 | msg <- readBin(con, character(), 16L) 167 | rank <- msg[1] 168 | cD$contract$conId <- msg[2] 169 | cD$contract$symbol <- msg[3] 170 | cD$contract$sectype <- msg[4] 171 | cD$contract$expiry <- msg[5] 172 | cD$contract$strike <- msg[6] 173 | cD$contract$right <- msg[7] 174 | cD$contract$exch <- msg[8] 175 | cD$contract$currency <- msg[9] 176 | cD$contract$local <- msg[10] 177 | cD$marketName <- msg[11] 178 | cD$tradingClass <- msg[12] 179 | distance <- msg[13] 180 | benchmark <- msg[14] 181 | projection <- msg[15] 182 | legsStr <- msg[16] 183 | eWrapper$scannerData(curMsg, tickerId, rank, cD, distance, 184 | benchmark, projection, legsStr) 185 | } 186 | } else 187 | if(curMsg == .twsIncomingMSG$TICK_OPTION_COMPUTATION) { 188 | msg <- readBin(con, "character", 11) 189 | # if(msg[3] == .twsTickType$MODEL_OPTION) { 190 | # #msg <- c(msg, readBin(con, character(), 2)) 191 | # } else msg <- c(msg,NA,NA) 192 | eWrapper$tickOptionComputation(curMsg, msg, timestamp, file, ...) 193 | } else 194 | if(curMsg == .twsIncomingMSG$TICK_GENERIC) { 195 | msg <- readBin(con, "character", 4) 196 | eWrapper$tickGeneric(curMsg, msg, timestamp, file, ...) 197 | } else 198 | if(curMsg == .twsIncomingMSG$TICK_STRING) { 199 | msg <- readBin(con, "character", 4) 200 | eWrapper$tickString(curMsg, msg, timestamp, file, ...) 201 | } else 202 | if(curMsg == .twsIncomingMSG$TICK_EFP) { 203 | msg <- readBin(con, "character", 10) 204 | eWrapper$tickEFP(curMsg, msg, timestamp, file, ...) 205 | } else 206 | if(curMsg == .twsIncomingMSG$CURRENT_TIME) { 207 | msg <- readBin(con, "character", 2) 208 | eWrapper$currentTime(curMsg, msg, timestamp, file, ...) 209 | } else 210 | if(curMsg == .twsIncomingMSG$REAL_TIME_BARS) { 211 | # browser() 212 | # cat("Reading bar of data, curMsg = ", curMsg, "\n") 213 | msg <- readBin(con, "character", 10) 214 | eWrapper$realtimeBars(curMsg, msg, timestamp, file, twsconn, ...) 215 | } else 216 | if(curMsg == .twsIncomingMSG$FUNDAMENTAL_DATA) { 217 | msg <- readBin(con, "character", 3) 218 | eWrapper$fundamentalData(curMsg, msg, timestamp, file, ...) 219 | } else 220 | if(curMsg == .twsIncomingMSG$CONTRACT_DATA_END) { 221 | msg <- readBin(con, "character", 2) 222 | eWrapper$contractDetailsEnd(curMsg, msg, timestamp, file, ...) 223 | } else 224 | if(curMsg == .twsIncomingMSG$OPEN_ORDER_END) { 225 | msg <- readBin(con, "character", 1) 226 | eWrapper$openOrderEnd(curMsg, msg, timestamp, file, ...) 227 | } else 228 | if(curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) { 229 | msg <- readBin(con, "character", 2) 230 | eWrapper$accountDownloadEnd(curMsg, msg, timestamp, file, ...) 231 | } else 232 | if(curMsg == .twsIncomingMSG$EXECUTION_DATA_END) { 233 | msg <- readBin(con, "character", 2) 234 | eWrapper$execDetailsEnd(curMsg, msg, timestamp, file, ...) 235 | } else 236 | if(curMsg == .twsIncomingMSG$DELTA_NEUTRAL_VALIDATION) { 237 | msg <- readBin(con, "character", 5) 238 | eWrapper$deltaNeutralValidation(curMsg, msg, timestamp, file, ...) 239 | } else 240 | if(curMsg == .twsIncomingMSG$TICK_SNAPSHOT_END) { 241 | #msg <- readBin(con, character(), 2) 242 | msg <- readBin(con, "character", 2) 243 | eWrapper$tickSnapshotEnd(curMsg, msg, timestamp, file, ...) 244 | } else { 245 | # default handler/error 246 | warning(paste("Unknown incoming message: ",curMsg,". Please reset connection",sep=""), call.=FALSE) 247 | } 248 | # end of messages 249 | } # end processMsg 250 | -------------------------------------------------------------------------------- /R/reqAccountUpdates.R: -------------------------------------------------------------------------------- 1 | cancelAccountUpdates <- function(conn, acctCode="1") { 2 | if(!is.twsConnection(conn)) 3 | stop("requires twsConnection object") 4 | .reqAccountUpdates(conn, "0", acctCode) 5 | } # end cancelAccountUpdates 6 | 7 | 8 | .reqAccountUpdates <- function(conn, subscribe=TRUE, acctCode="1") { 9 | if (!is.twsConnection(conn)) 10 | stop("requires twsConnection object") 11 | 12 | con <- conn[[1]] 13 | VERSION <- "2" 14 | 15 | # send messages to TWS 16 | writeBin(.twsOutgoingMSG$REQ_ACCOUNT_DATA, con) 17 | writeBin(VERSION, con) 18 | writeBin(as.character(as.numeric(subscribe)), con) 19 | writeBin(as.character(acctCode), con) 20 | } # end .reqAccountUpdates 21 | 22 | 23 | # Run callback loop without CALLBACK function 24 | # eventWrapper not used 25 | reqAccountUpdates <- function(conn, 26 | subscribe=TRUE, 27 | acctCode="1", 28 | eventWrapper=eWrapper(), 29 | CALLBACK=twsCALLBACK, ...) { 30 | if (!is.twsConnection(conn)) 31 | stop("requires twsConnection object") 32 | 33 | .reqAccountUpdates(conn, subscribe, acctCode) 34 | 35 | on.exit(.reqAccountUpdates(conn, "0", acctCode)) 36 | 37 | verbose <- FALSE 38 | acct <- list() 39 | con <- conn[[1]] 40 | eW <- eWrapper(NULL) 41 | eW$assign.Data("data", structure(list(), class="eventAccountValue")) 42 | 43 | eW$updatePortfolio <- function (curMsg, msg, ...) { 44 | version <- as.numeric(msg[1]) 45 | contract <- twsContract(conId = msg[2], symbol = msg[3], 46 | sectype = msg[4], exch = msg[9], primary = msg[9], expiry = msg[5], 47 | strike = msg[6], currency = msg[10], right = msg[7], 48 | local = msg[11], multiplier = msg[8], combo_legs_desc = "", 49 | comboleg = "", include_expired = "") 50 | portfolioValue <- list() 51 | portfolioValue$position <- as.numeric(msg[12]) 52 | portfolioValue$marketPrice <- as.numeric(msg[13]) 53 | portfolioValue$marketValue <- as.numeric(msg[14]) 54 | portfolioValue$averageCost <- as.numeric(msg[15]) 55 | portfolioValue$unrealizedPNL <- as.numeric(msg[16]) 56 | portfolioValue$realizedPNL <- as.numeric(msg[17]) 57 | portfolioValue$accountName <- msg[18] 58 | p <- structure(list(contract = contract, portfolioValue = portfolioValue), class = "eventPortfolioValue") 59 | p 60 | } # end updatePortfolio 61 | 62 | eW$updateAccountValue <- function (curMsg, msg, ...) { 63 | data <- eW$get.Data("data") 64 | data[[msg[2]]] <- c(value=msg[3], currency=msg[4]) 65 | eW$assign.Data("data", data) 66 | } # end updateAccountValue 67 | 68 | 69 | # acct_msgs <- with(.twsIncomingMSG, 70 | # c(ACCT_VALUE,PORTFOLIO_VALUE,ACCT_UPDATE_TIME)) 71 | 72 | # Callback loop 73 | timestamp <- NULL 74 | while (TRUE) { 75 | socketSelect(list(con), FALSE, NULL) 76 | curMsg <- readBin(con, character(), 1) 77 | # if (!curMsg %in% acct_msgs) { 78 | # if (curMsg == .twsIncomingMSG$ERR_MSG) { 79 | # if (!errorHandler(con, verbose, OK = c(165, 300, 80 | # 366, 2104, 2106, 2107))) { 81 | # warning("error in reqAccountUpdates details") 82 | # break 83 | # } 84 | # } 85 | # else { 86 | # processMsg(curMsg, con, eW, timestamp, file) 87 | # if (curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) 88 | # break 89 | # } 90 | # } 91 | if (curMsg == .twsIncomingMSG$PORTFOLIO_VALUE) { 92 | acct[[length(acct) + 1]] <- processMsg(curMsg, con, eW, timestamp, file) 93 | } else { 94 | processMsg(curMsg, con, eW, timestamp, file) 95 | } 96 | if (curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) 97 | break 98 | } # end while 99 | 100 | return(structure(list(eW$get.Data("data"), acct), class="AccountUpdate")) 101 | 102 | # CALLBACK(conn, eventWrapper, NULL, file) 103 | } # end reqAccountUpdates 104 | -------------------------------------------------------------------------------- /R/reqContractDetails.R: -------------------------------------------------------------------------------- 1 | .reqContractDetails <- function(conn, Contract, reqId="1") 2 | { 3 | if(!is.twsConnection(conn)) 4 | stop("requires twsConnection object") 5 | 6 | if(!inherits(Contract, "twsContract")) 7 | stop("requires twsContract object") 8 | 9 | con <- conn[[1]] 10 | 11 | VERSION <- "5" 12 | VERSION <- "6" 13 | 14 | request <- c(.twsOutgoingMSG$REQ_CONTRACT_DATA, 15 | VERSION, 16 | reqId, 17 | Contract$conId, 18 | Contract$symbol, 19 | Contract$sectype, 20 | Contract$expiry, 21 | Contract$strike, 22 | Contract$right, 23 | Contract$multiplier, 24 | Contract$exch, 25 | Contract$currency, 26 | Contract$local, 27 | Contract$include_expired, 28 | Contract$secIdType, 29 | Contract$secId) 30 | writeBin(as.character(request), con) 31 | } 32 | 33 | reqContractDetails <- 34 | function(conn, Contract, reqId="1", verbose=FALSE, 35 | eventWrapper=eWrapper(), CALLBACK=twsCALLBACK, ...) { 36 | 37 | .reqContractDetails(conn, Contract, reqId) 38 | 39 | if(is.null(CALLBACK)) 40 | invisible(return(NULL)) 41 | 42 | # create an internal eWrapper to *only* handle contract request data, 43 | # all else is discarded. 44 | eW <- eWrapper(NULL) 45 | eW$contractDetails <- function(curMsg, msg, timestamp, file, ...) { 46 | # custom contractData function called from processMsg 47 | twsContractDetails(version=msg[1], 48 | #reqId=msg[2], 49 | contract=twsContract(conId=msg[12+1], 50 | symbol=msg[3], 51 | sectype=msg[4], 52 | expiry=msg[5], 53 | primary=msg[21], 54 | strike=msg[5+1], 55 | right=msg[6+1], 56 | exch=msg[7+1], 57 | currency=msg[8+1], 58 | multiplier=msg[14+1], 59 | include_expired=Contract$include_expired, 60 | combo_legs_desc="", comboleg="", 61 | local=msg[9+1]), 62 | marketName=msg[10+1], 63 | tradingClass=msg[11+1], 64 | conId=msg[12+1], 65 | minTick=msg[13+1], 66 | orderTypes=unlist(strsplit(msg[15+1],",")), 67 | validExchanges=unlist(strsplit(msg[16+1],",")), 68 | priceMagnifier=msg[17+1], 69 | underConId=msg[18+1], 70 | longName=msg[19+1], 71 | contractMonth=msg[22], 72 | industry=msg[23], 73 | category=msg[24], 74 | subcategory=msg[25], 75 | timeZoneId=msg[26], 76 | tradingHours=msg[27], 77 | liquidHours=msg[28]) 78 | } 79 | 80 | contracts <- list() 81 | con <- conn[[1]] 82 | while (TRUE) { 83 | socketSelect(list(con), FALSE, NULL) 84 | curMsg <- readBin(con, character(), 1) 85 | if(curMsg != .twsIncomingMSG$CONTRACT_DATA) { 86 | if(curMsg == .twsIncomingMSG$ERR_MSG) { 87 | if(!errorHandler(con,verbose,OK=c(165,300,366,2104,2106,2107))){ 88 | warning("error in contract details") 89 | break 90 | } 91 | } else { 92 | processMsg(curMsg, con, eW, timestamp, file) 93 | if(curMsg == .twsIncomingMSG$CONTRACT_DATA_END) 94 | break 95 | } 96 | } 97 | if(curMsg == .twsIncomingMSG$CONTRACT_DATA) { 98 | contracts[[length(contracts)+1]] <- 99 | processMsg(curMsg, con, eW, timestamp, file) 100 | } 101 | 102 | } 103 | return(contracts) 104 | } 105 | -------------------------------------------------------------------------------- /R/reqCurrentTime.R: -------------------------------------------------------------------------------- 1 | .reqCurrentTime <- 2 | function(conn) { 3 | if(!isConnected(conn)) 4 | stop('peer has gone away. check your IB connection',call.=FALSE) 5 | if(!is.twsConnection(conn)) 6 | stop('requires twsConnection object') 7 | 8 | con <- conn[[1]] 9 | 10 | writeBin(.twsOutgoingMSG$REQ_CURRENT_TIME,con) 11 | writeBin('1',con) 12 | 13 | } 14 | 15 | reqCurrentTime <- 16 | function(twsconn) { 17 | .reqCurrentTime(twsconn) 18 | con <- twsconn[[1]] 19 | e_current_time <- eWrapper() 20 | e_current_time$currentTime <- function(curMsg, msg, timestamp, file, ...) { msg[2] } 21 | while (isConnected(twsconn)) { 22 | socketSelect(list(con), FALSE, NULL) 23 | curMsg <- readBin(con, character(), 1) 24 | currentTime <- processMsg(curMsg, 25 | con, 26 | eWrapper=e_current_time, 27 | twsconn=twsconn, 28 | timestamp=NULL, file="") 29 | if(curMsg == .twsIncomingMSG$CURRENT_TIME) 30 | break 31 | } 32 | structure(as.numeric(currentTime), class=c("POSIXt", "POSIXct")) 33 | # tz <- Sys.getenv("TZ") 34 | # on.exit(Sys.setenv(TZ=tz)) 35 | # Sys.setenv(TZ='GMT') 36 | # xts:::as.POSIXct.numeric(as.numeric(currentTime),tz='GMT',origin='1970-01-01') 37 | } 38 | 39 | -------------------------------------------------------------------------------- /R/reqExecutions.R: -------------------------------------------------------------------------------- 1 | reqExecutions <- function(twsconn, reqId="0", ExecutionFilter) { 2 | if(!is.twsConnection(twsconn)) 3 | stop("invalid 'twsConnection' object") 4 | 5 | con <- twsconn[[1]] 6 | 7 | VERSION <- "3" 8 | outgoing <- c(.twsOutgoingMSG$REQ_EXECUTIONS, 9 | VERSION, 10 | as.character(reqId), 11 | ExecutionFilter$clientId, 12 | ExecutionFilter$acctCode, 13 | ExecutionFilter$time, 14 | ExecutionFilter$symbol, 15 | ExecutionFilter$secType, 16 | ExecutionFilter$exchange, 17 | ExecutionFilter$side) 18 | writeBin(outgoing, con) 19 | } 20 | -------------------------------------------------------------------------------- /R/reqFundamentalData.R: -------------------------------------------------------------------------------- 1 | reqFundamentalData <- function(twsconn, reqId, contract, reportType) { 2 | if( !is.twsConnection(twsconn)) 3 | stop('invalid twsConnection') 4 | if( !is.twsContract(contract)) 5 | stop('invalid twsContract') 6 | 7 | VERSION <- "1" 8 | 9 | msg <- c( .twsOutgoingMSG$REQ_FUNDAMENTAL_DATA, 10 | VERSION, 11 | reqId, 12 | 13 | # contract fields 14 | contract$symbol, 15 | contract$sectype, 16 | contract$exch, 17 | contract$primary, 18 | contract$currency, 19 | contract$local, 20 | 21 | reportType) 22 | 23 | writeBin( as.character(msg), twsconn[[1]]) 24 | } 25 | 26 | cancelFundamentalData <- function(twsconn, reqId) { 27 | if( !is.twsConnection(twsconn)) 28 | stop('invalid twsConnection') 29 | 30 | VERSION <- "1" 31 | 32 | msg <- c( .twsOutgoingMSG$CANCEL_FUNDAMENTAL_DATA, 33 | VERSION, 34 | reqId) 35 | 36 | writeBin( as.character(msg), twsconn[[1]]) 37 | } 38 | -------------------------------------------------------------------------------- /R/reqHistoricalData.R: -------------------------------------------------------------------------------- 1 | reqHistoricalData <- 2 | function(conn, Contract,endDateTime, 3 | barSize='1 day',duration='1 M', 4 | useRTH='1',whatToShow='TRADES',timeFormat='1',tzone="", 5 | verbose=TRUE, tickerId='1', 6 | eventHistoricalData, file) 7 | { 8 | if(!missing(endDateTime) && length(endDateTime) > 1) { 9 | if(!timeBased(endDateTime)) 10 | stop("endDateTime length greater than 2 needs to be timeBased") 11 | sleep <- 0 12 | rHDargs <- list(conn=conn,Contract=Contract, 13 | barSize=barSize, duration=duration, 14 | useRTH=useRTH, whatToShow=whatToShow, 15 | timeFormat=timeFormat, tzone=tzone, verbose=verbose, tickerId=tickerId) 16 | if(!missing(eventHistoricalData)) 17 | rHDargs$eventHistoricalData <- eventHistoricalData 18 | if(!missing(file)) 19 | rHDargs$file <- file 20 | x <- lapply(format(endDateTime,"%Y%m%d 23:59:59"), 21 | function(eDT) { 22 | rHDargs$endDateTime <- eDT 23 | xx <- try(do.call('reqHistoricalData', rHDargs), silent=TRUE) 24 | Sys.sleep(10) 25 | if(inherits(xx, "try-error")) 26 | return(NULL) 27 | return(xx) 28 | }) 29 | x <- do.call('rbind.xts',x) 30 | return(x[-which(duplicated(.index(x)))]) 31 | } 32 | 33 | #conn <- twsConnect(123456, blocking=TRUE) # need a blocking connection 34 | con <- conn[[1]] 35 | cancelHistoricalData <- function(con, tickerId) 36 | { 37 | if (!isOpen(con)) 38 | stop("invalid TWS connection") 39 | 40 | writeBin(.twsOutgoingMSG$CANCEL_HISTORICAL_DATA, con) 41 | writeBin("1", con) 42 | writeBin(as.character(tickerId), con) 43 | } 44 | if(!isOpen(con)) stop("connection to TWS has been closed") 45 | on.exit(cancelHistoricalData(con,as.character(tickerId))) 46 | 47 | #if(class(conn) != 'twsConnection') stop('tws connection object required') 48 | if(!is.twsConnection(conn)) 49 | stop('tws connection object required') 50 | #if(class(Contract) != 'twsContract') stop('twsContract required') 51 | if(!is.twsContract(Contract)) 52 | stop('twsContract required') 53 | 54 | validBarSize <- c('1 secs','5 secs','15 secs','30 secs', 55 | '1 min', '2 mins','3 mins','5 mins','15 mins', 56 | '30 mins','1 hour','1 day','1 week','1 month', 57 | '3 months','1 year') 58 | if(!barSize %in% validBarSize) 59 | stop(paste('unknown barSize try: ',paste(validBarSize,sep=";"))) 60 | 61 | 62 | if(missing(endDateTime) || is.null(endDateTime)) 63 | endDateTime <- strftime( 64 | as.POSIXlt(as.POSIXct('1970-01-01')+ 65 | as.numeric(reqCurrentTime(conn))), 66 | format='%Y%m%d %H:%M:%S',usetz=FALSE) 67 | 68 | VERSION <- "4" 69 | 70 | signals <- c(.twsOutgoingMSG$REQ_HISTORICAL_DATA, # '20' 71 | VERSION, 72 | as.character(tickerId), 73 | Contract$symbol, Contract$sectype, 74 | Contract$expiry, Contract$strike, 75 | Contract$right, Contract$multiplier, 76 | Contract$exch, Contract$primary, 77 | Contract$currency, Contract$local, 78 | Contract$include_expired, 79 | endDateTime, barSize, duration, useRTH, 80 | whatToShow, timeFormat) 81 | # signals <- c('20','4','1', 82 | # 'QQQQ','STK','', 83 | # '0.0','','', 84 | # 'SMART','ISLAND','USD', 85 | # '','0','20080219 21:11:41 GMT', 86 | # '1 day','1 M','1', 87 | # 'TRADES','1') 88 | 89 | writeBin(signals, con) 90 | 91 | waiting <- TRUE # waiting for valid response? 92 | response <- character(0) # currently read response 93 | 94 | if(verbose) { 95 | cat('waiting for TWS reply on',Contract$symbol,'...') 96 | iter <- 1 97 | flush.console() 98 | } 99 | 100 | while(waiting) { 101 | if( !socketSelect(list(con), FALSE, 0.25)) 102 | next 103 | curMsg <- readBin(con,character(),1) 104 | if(verbose) { 105 | cat('.') 106 | if(iter %% 30 == 0) cat('\n') 107 | flush.console() 108 | iter <- iter + 1 109 | #Sys.sleep(0.25) 110 | } 111 | 112 | if(length(curMsg) > 0) { 113 | # watch for error messages 114 | if(curMsg == .twsIncomingMSG$ERR_MSG) { 115 | if(!errorHandler(con,verbose,OK=c(165,300,366,2104,2106,2107))) { 116 | cat('failed.\n') 117 | #stop('Unable to complete historical data request', call.=FALSE) 118 | on.exit() 119 | invisible(return()) 120 | } 121 | } 122 | # watch for historical data start 123 | if(curMsg == .twsIncomingMSG$HISTORICAL_DATA) { 124 | header <- readBin(con,character(),5) 125 | nbin <- as.numeric(header[5])*9 126 | req.from <- header[3] 127 | req.to <- header[4] 128 | Sys.sleep(2) # add delay for Windows issues - readBin on M$ is bad, bad, bad... 129 | response <- readBin(con,character(),nbin) 130 | waiting <- FALSE 131 | if(verbose) { 132 | cat(' done.\n') 133 | flush.console() 134 | } 135 | on.exit() 136 | } 137 | } 138 | } 139 | 140 | if(missing(eventHistoricalData)) { 141 | # the default: return an xts object 142 | cm <- matrix(response,ncol=9,byrow=TRUE) 143 | cm[,8] <- ifelse(cm[,8]=='false',0,1) 144 | if(timeFormat==2 && !nchar(cm[1,1]) > 8) { # IB ignores the timeFormat if daily returns 145 | dts <- structure(as.numeric(cm[,1]), class=c("POSIXct","POSIXt"), tzone=tzone) 146 | } else { 147 | dts <- structure(as.numeric(as.POSIXlt(gsub('(\\d{4})(\\d{2})(\\d{2})','\\1-\\2-\\3',cm[,1],perl=TRUE))), 148 | class=c("POSIXct","POSIXt"), tzone=tzone) 149 | } 150 | 151 | # if file is specified - dump to file instead 152 | if(!missing(file)) { 153 | cm[,1] <- dts 154 | write.table(cm, 155 | file=file, 156 | quote=FALSE, 157 | row.names=FALSE, 158 | col.names=FALSE, 159 | sep=',') 160 | invisible(return()) 161 | } 162 | 163 | #x <- xts(matrix(as.numeric(cm[,-1]),nc=8),order.by=structure(as.numeric(as.POSIXlt(dts)), class=c("POSIXt", "POSIXct"))) 164 | x <- xts(matrix(as.numeric(cm[,-1]),ncol=8),order.by=dts, tzone=tzone) 165 | localsymbol <- reqContractDetails(conn, Contract)[[1]]$contract$local 166 | colnames(x) <- paste(localsymbol, c('Open','High','Low','Close','Volume', 167 | 'WAP','hasGaps','Count'), sep='.') 168 | xtsAttributes(x) <- list(from=req.from,to=req.to, 169 | src='IB',updated=Sys.time()) 170 | return(x) 171 | } else 172 | if(is.null(eventHistoricalData)) { 173 | # return raw TWS data including header 174 | return(c(header,response)) 175 | } else { 176 | # pass to callback function 177 | FUN <- match.fun(eventHistoricalData) 178 | return(FUN(c(header,response))) 179 | } 180 | 181 | } 182 | 183 | cancelHistoricalData <- function(conn, tickerId) 184 | { 185 | if(!inherits(conn, "twsConnection")) 186 | if(!is.twsConnection(conn)) 187 | stop("twsConnection object required") 188 | 189 | con <- conn[[1]] 190 | 191 | if (!isOpen(con)) 192 | stop("invalid TWS connection") 193 | 194 | writeBin(.twsOutgoingMSG$CANCEL_HISTORICAL_DATA, con) 195 | writeBin("1", con) 196 | writeBin(as.character(tickerId), con) 197 | } 198 | 199 | reqHistory <- function(conn, Contract, barSize="1 min", ...) 200 | { 201 | if(barSize == "1 min") { 202 | endDateTime <- Sys.Date()-seq(360, 0, -5) 203 | duration <- "5 D" 204 | } else 205 | if(barSize == "15 mins") { 206 | endDateTime <- Sys.Date()-seq(360, 0, -10) 207 | duration <- "10 D" 208 | } 209 | reqHistoricalData(conn, Contract, barSize=barSize, duration=duration, endDateTime=endDateTime, ...) 210 | } 211 | -------------------------------------------------------------------------------- /R/reqIds.R: -------------------------------------------------------------------------------- 1 | .reqIds <- function(conn, numIds=1) 2 | { 3 | if(inherits(conn, "twsconn")) { 4 | id <- conn$nextValidId 5 | conn$nextValidId <- as.character(as.numeric(id)+1L) 6 | return(id) 7 | } 8 | if (!is.twsConnection(conn)) 9 | stop("requires twsConnection object") 10 | con <- conn[[1]] 11 | 12 | VERSION <- "1" 13 | writeBin(.twsOutgoingMSG$REQ_IDS, con) 14 | writeBin(VERSION, con) 15 | writeBin(as.character(numIds), con) 16 | } 17 | 18 | reqIds <- function(conn, numIds=1) 19 | { 20 | if(inherits(conn, "twsconn")) { 21 | id <- conn$nextValidId 22 | conn$nextValidId <- as.character(as.numeric(id)+1L) 23 | return(id) 24 | } 25 | .reqIds(conn, numIds) 26 | 27 | con <- conn[[1]] 28 | e_next_id <- eWrapper() 29 | e_next_id$nextValidId <- function(curMsg, msg, timestamp, file, ...) { msg[2] } 30 | 31 | while(TRUE) { 32 | socketSelect(list(con), FALSE, NULL) 33 | curMsg <- readBin(con, character(), 1) 34 | 35 | nextValidID <- processMsg(curMsg, 36 | con, 37 | eWrapper=e_next_id, 38 | timestamp=NULL,file="") 39 | if(curMsg == .twsIncomingMSG$NEXT_VALID_ID) 40 | break 41 | } 42 | return(nextValidID) 43 | } 44 | 45 | -------------------------------------------------------------------------------- /R/reqManagedAccts.R: -------------------------------------------------------------------------------- 1 | reqManagedAccts <- function(twsconn) { 2 | if( !is.twsConnection(twsconn)) 3 | stop('invalid twsConnection') 4 | 5 | VERSION <- "1" 6 | 7 | writeBin(c(.twsOutgoingMSG$REQ_MANAGED_ACCTS, 8 | VERSION), 9 | twsconn[[1]]) 10 | } 11 | 12 | requestFA <- function(twsconn, faDataType) { 13 | if( !is.twsConnection(twsconn)) 14 | stop('invalid twsConnection') 15 | 16 | VERSION <- "1" 17 | 18 | writeBin(c(.twsOutgoingMSG$REQ_FA, 19 | VERSION, 20 | as.character(faDataType)), 21 | twsconn[[1]]) 22 | } 23 | 24 | replaceFA <- function(twsconn, faDataType, xml) { 25 | if( !is.twsConnection(twsconn)) 26 | stop('invalid twsConnection') 27 | 28 | VERSION <- "1" 29 | 30 | writeBin( c(.twsOutgoingMSG$REPLACE_FA, 31 | VERSION, 32 | as.character(faDataType), 33 | as.character(xml)), 34 | twsconn[[1]]) 35 | } 36 | -------------------------------------------------------------------------------- /R/reqMktDepth.R: -------------------------------------------------------------------------------- 1 | `reqMktDepth` <- 2 | function (conn, Contract, tickerId = "1", numRows="20", 3 | timeStamp=TRUE, playback=1, 4 | file='', verbose=TRUE, 5 | eventWrapper=eWrapper(), 6 | CALLBACK=twsCALLBACK,...) 7 | { 8 | if (!is.twsConnection(conn)) 9 | stop("tws connection object required") 10 | 11 | if(!is.twsPlayback(conn)) { 12 | # if playback from a file, don't test or require contract 13 | if(class(Contract) == "twsContract") Contract <- list(Contract) 14 | 15 | for(n in 1:length(Contract)) { 16 | if (class(Contract[[n]]) != "twsContract") 17 | stop("twsContract required") 18 | } 19 | } 20 | 21 | con <- conn[[1]] 22 | if (!isOpen(con)) 23 | stop("connection to TWS has been closed") 24 | 25 | cancelMktDepth <- function(con,tickerId) { 26 | if(inherits(con, 'sockconn')) { 27 | for(i in 1:length(tickerId)) { 28 | writeBin(.twsOutgoingMSG$CANCEL_MKT_DEPTH,con) 29 | writeBin('1',con) 30 | writeBin(tickerId[i],con) 31 | } 32 | } else { 33 | # reset to beginning of file 34 | seek(con,0) 35 | } 36 | } 37 | 38 | if(!is.character(timeStamp) & timeStamp) { 39 | timeStamp <- "%Y%m%d %H:%M:%OS" 40 | } else { 41 | timeStamp <- NULL 42 | } 43 | 44 | if(is.null(CALLBACK)) 45 | CALLBACK <- twsDEBUG 46 | 47 | VERSION <- "3" 48 | 49 | ticker_id <- as.character(tickerId) 50 | 51 | if(inherits(con, 'sockconn')) { 52 | # write to live TWS Connection 53 | for(n in 1:length(Contract)) { 54 | signals <- c(.twsOutgoingMSG$REQ_MKT_DEPTH, 55 | VERSION, 56 | ticker_id, 57 | Contract[[n]]$symbol, 58 | Contract[[n]]$sectype, 59 | Contract[[n]]$expiry, 60 | Contract[[n]]$strike, 61 | Contract[[n]]$right, 62 | Contract[[n]]$multiplier, 63 | Contract[[n]]$exch, 64 | Contract[[n]]$currency, 65 | Contract[[n]]$local, 66 | numRows) 67 | 68 | 69 | for (i in 1:length(signals)) { 70 | writeBin(signals[i], con) 71 | } 72 | ticker_id <- as.character(as.numeric(tickerId)+n) 73 | } 74 | msg_expected_length <- NA 75 | } else { 76 | msg_expected_length <- as.numeric(readBin(con, character(), 1)) 77 | } 78 | 79 | if(!missing(CALLBACK) && is.na(list(CALLBACK))) { 80 | if(inherits(conn, 'twsPlayback')) { 81 | seek(conn[[1]], 0) 82 | stop("CALLBACK=NA is not available for playback") 83 | } 84 | return(as.character(as.numeric(tickerId):length(Contract))) 85 | } 86 | on.exit(cancelMktDepth(con, as.character(as.numeric(tickerId):length(Contract)))) 87 | 88 | CALLBACK(conn, eWrapper=eventWrapper, timestamp=timeStamp, file=file, 89 | playback=playback, ...) 90 | } 91 | 92 | `cancelMktDepth` <- function(conn,tickerId) { 93 | if(!inherits(conn, "twsConnection")) 94 | stop("twsConnection object required") 95 | 96 | con <- conn[[1]] 97 | 98 | for(i in 1:length(tickerId)) { 99 | writeBin(.twsOutgoingMSG$CANCEL_MKT_DEPTH,con) 100 | writeBin('1',con) 101 | writeBin(tickerId[i],con) 102 | } 103 | } 104 | 105 | -------------------------------------------------------------------------------- /R/reqNewsBulletins.R: -------------------------------------------------------------------------------- 1 | reqNewsBulletins <- function(twsconn, allMsgs=TRUE) { 2 | if( !is.twsConnection(twsconn)) 3 | stop('requires twsConnection object') 4 | 5 | allMsgs <- as.character(as.integer(allMsgs)) 6 | VERSION <- "1" 7 | 8 | writeBin( c(.twsOutgoingMSG$REQ_NEWS_BULLETINS, VERSION, allMsgs), twsconn[[1]]) 9 | } 10 | 11 | cancelNewsBulletins <- function(twsconn) { 12 | if( !is.twsConnection(twsconn)) 13 | stop('requires twsConnection object') 14 | 15 | VERSION <- "1" 16 | 17 | writeBin( c(.twsOutgoingMSG$CANCEL_NEWS_BULLETINS, VERSION), twsconn[[1]]) 18 | } 19 | -------------------------------------------------------------------------------- /R/reqOpenOrders.R: -------------------------------------------------------------------------------- 1 | .reqOpenOrders <- function(twsconn) { 2 | if( !is.twsConnection(twsconn)) 3 | stop('requires twsConnection object') 4 | 5 | con <- twsconn[[1]] 6 | 7 | VERSION <- "1" 8 | 9 | writeBin(c(.twsOutgoingMSG$REQ_OPEN_ORDERS,VERSION), con) 10 | } 11 | 12 | reqOpenOrders <- function(twsconn) { 13 | .reqOpenOrders(twsconn) 14 | 15 | con <- twsconn[[1]] 16 | eW <- eWrapper() 17 | 18 | while(TRUE) { 19 | socketSelect(list(con), FALSE, NULL) 20 | curMsg <- readBin(con, character(), 1L) 21 | processMsg(curMsg, con, eW) 22 | } 23 | } 24 | 25 | .reqAutoOpenOrders <- function(twsconn, bAutoBind=TRUE) { 26 | if( !is.twsConnection(twsconn)) 27 | stop('requires twsConnection object') 28 | 29 | bAutoBind <- as.character(as.integer(bAutoBind)) 30 | con <- twsconn[[1]] 31 | 32 | VERSION <- "1" 33 | 34 | writeBin(c(.twsOutgoingMSG$REQ_AUTO_OPEN_ORDERS,VERSION,bAutoBind), con) 35 | } 36 | 37 | .reqAllOpenOrders <- function(twsconn) { 38 | if( !is.twsConnection(twsconn)) 39 | stop('requires twsConnection object') 40 | 41 | con <- twsconn[[1]] 42 | 43 | VERSION <- "1" 44 | 45 | writeBin(c(.twsOutgoingMSG$REQ_ALL_OPEN_ORDERS,VERSION), con) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /R/reqRealTimeBars.R: -------------------------------------------------------------------------------- 1 | .reqRealTimeBars <- function(conn, Contract, 2 | whatToShow="TRADES", 3 | barSize="5",useRTH=TRUE, 4 | tickerId = "1") { 5 | if(!is.twsConnection(conn)) 6 | stop("tws connection object required") 7 | if(is.twsContract(Contract)) 8 | Contract <- list(Contract) 9 | 10 | for(n in 1:length(Contract)) { 11 | if(!is.twsContract(Contract[[n]])) 12 | stop("twsContract required") 13 | } 14 | con <- conn[[1]] 15 | if(!isOpen(con)) 16 | stop("connection to TWS has been closed") 17 | 18 | 19 | VERSION <- "1" 20 | if(length(tickerId) != length(Contract)) 21 | tickerId <- seq(as.numeric(tickerId), length.out=length(Contract)) 22 | 23 | ticker_id <- as.character(tickerId) 24 | 25 | for(n in 1:length(Contract)) { 26 | request <- c(.twsOutgoingMSG$REQ_REAL_TIME_BARS, VERSION, ticker_id[n], 27 | Contract[[n]]$symbol, 28 | Contract[[n]]$sectype, 29 | Contract[[n]]$expiry, 30 | Contract[[n]]$strike, 31 | Contract[[n]]$right, 32 | Contract[[n]]$multiplier, 33 | Contract[[n]]$exch, 34 | Contract[[n]]$primary, 35 | Contract[[n]]$currency, 36 | Contract[[n]]$local,barSize,whatToShow, 37 | as.character(as.numeric(useRTH))) 38 | writeBin(request, con) 39 | # ticker_id <- as.character(as.numeric(tickerId)) 40 | # ticker_ids[n] <- ticker_id 41 | } 42 | ticker_id 43 | } 44 | 45 | #' @export 46 | reqRealTimeBars <- function(conn, Contract, 47 | whatToShow="TRADES", 48 | barSize="5",useRTH=TRUE, 49 | playback = 1, 50 | tickerId = "1", 51 | file = "", 52 | verbose=TRUE, 53 | eventWrapper=eWrapper(), 54 | CALLBACK=twsCALLBACK, ...) { 55 | if(!is.twsPlayback(conn)) { 56 | tickerId <- .reqRealTimeBars(conn, Contract, whatToShow, barSize, useRTH, tickerId) 57 | } 58 | 59 | if(is.twsContract(Contract)) 60 | Contract <- list(Contract) 61 | 62 | con <- conn[[1]] 63 | cancelRealTimeBars <- function(con,tickerId) { 64 | if(inherits(con,'sockconn')) { 65 | for(i in 1:length(tickerId)) { 66 | writeBin(.twsOutgoingMSG$CANCEL_REAL_TIME_BARS,con) 67 | writeBin('1',con) 68 | writeBin(tickerId[i],con) 69 | } 70 | } else { 71 | seek(con, 0) 72 | } 73 | } 74 | 75 | if(is.null(CALLBACK)) 76 | CALLBACK <- twsDEBUG # function to simply return raw data 77 | 78 | if(!missing(CALLBACK) && is.na(list(CALLBACK))) { 79 | if(is.twsPlayback(conn)) { 80 | seek(conn[[1]], 0) 81 | stop("CALLBACK=NA is not available for playback") 82 | } 83 | return(tickerId) 84 | } 85 | on.exit(cancelRealTimeBars(con, tickerId)) 86 | 87 | symbol.or.local <- function(x) { 88 | # used to find best name for id in output 89 | symbol <- x$symbol 90 | local <- x$local 91 | if(local=="") { 92 | return(symbol) 93 | } else return(local) 94 | } 95 | eventWrapper$assign.Data("symbols", sapply(Contract, symbol.or.local)) 96 | # data is list of vectors TimeStamp, Open, High, Low, Close, Volume, VWAP, Count 97 | # eventWrapper$assign.Data("data", rep(list(rep(NA, 8)), length(Contract))) 98 | 99 | timeStamp <- NULL 100 | if(!is.list(file)) 101 | file <- list(file) 102 | if(length(file) != length(Contract)) 103 | file <- rep(file, length(Contract)) 104 | CALLBACK(conn, eWrapper=eventWrapper, timestamp=timeStamp, file=file, 105 | playback=playback, ...) 106 | } # end reqRealTimeBars 107 | 108 | `cancelRealTimeBars` <- function(conn,tickerId) { 109 | if(!is.twsConnection(conn)) 110 | stop("twsConnection object required") 111 | 112 | con <- conn[[1]] 113 | 114 | for(i in 1:length(tickerId)) { 115 | writeBin(.twsOutgoingMSG$CANCEL_REAL_TIME_BARS,con) 116 | writeBin('1',con) 117 | writeBin(tickerId[i],con) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /R/serverVersion.R: -------------------------------------------------------------------------------- 1 | serverVersion <- function(con) { 2 | if(!is.twsConnection(con)) 3 | stop('con must be a twsConnection object') 4 | 5 | con$server.version 6 | } 7 | -------------------------------------------------------------------------------- /R/setServerLogLevel.R: -------------------------------------------------------------------------------- 1 | setServerLogLevel <- function(conn, logLevel=2) 2 | { 3 | if(!is.twsConnection(conn)) 4 | stop('twsConnection object required') 5 | VERSION <- "1" 6 | con <- conn[[1]] 7 | writeBin(c(.twsOutgoingMSG$SET_SERVER_LOGLEVEL, 8 | VERSION, as.character(logLevel)), con) 9 | } 10 | -------------------------------------------------------------------------------- /R/trade_realtime.R: -------------------------------------------------------------------------------- 1 | .trade_realtime <- function(ib_connect, Contract, 2 | whatToShow="TRADES", 3 | barSize="5",useRTH=TRUE, 4 | tickerId="1") { 5 | if(!is.twsConnection(ib_connect)) 6 | stop("tws connection object required") 7 | if(is.twsContract(Contract)) 8 | Contract <- list(Contract) 9 | 10 | for(n in 1:length(Contract)) { 11 | if(!is.twsContract(Contract[[n]])) 12 | stop("twsContract required") 13 | } 14 | sock_et <- ib_connect[[1]] 15 | if(!isOpen(sock_et)) 16 | stop("connection to TWS has been closed") 17 | 18 | 19 | VERSION <- "1" 20 | if(length(tickerId) != length(Contract)) 21 | tickerId <- seq(as.numeric(tickerId), length.out=length(Contract)) 22 | 23 | ticker_id <- as.character(tickerId) 24 | 25 | for(n in 1:length(Contract)) { 26 | request <- c(.twsOutgoingMSG$REQ_REAL_TIME_BARS, VERSION, ticker_id[n], 27 | Contract[[n]]$symbol, 28 | Contract[[n]]$sectype, 29 | Contract[[n]]$expiry, 30 | Contract[[n]]$strike, 31 | Contract[[n]]$right, 32 | Contract[[n]]$multiplier, 33 | Contract[[n]]$exch, 34 | Contract[[n]]$primary, 35 | Contract[[n]]$currency, 36 | Contract[[n]]$local,barSize,whatToShow, 37 | as.character(as.numeric(useRTH))) 38 | writeBin(request, sock_et) 39 | # ticker_id <- as.character(as.numeric(tickerId)) 40 | # ticker_ids[n] <- ticker_id 41 | } 42 | ticker_id 43 | } # end .trade_realtime 44 | 45 | 46 | #' @export 47 | trade_realtime <- function(ib_connect, 48 | Contract, 49 | whatToShow="TRADES", 50 | barSize="5", 51 | useRTH=TRUE, 52 | back_test=FALSE, 53 | tickerId="1", 54 | file="", 55 | verbose=TRUE, 56 | eventWrapper=trade_wrapper(), 57 | CALLBACK=twsCALLBACK, ...) { 58 | 59 | if (!back_test) { 60 | # Extract socket from IB connection 61 | sock_et <- ib_connect[[1]] 62 | 63 | # Submit requests to IB 64 | if (!is.twsPlayback(ib_connect)) { 65 | # Request account updates 66 | # writeBin(.twsOutgoingMSG$REQ_ACCOUNT_DATA, sock_et) 67 | # writeBin("2", sock_et) 68 | # writeBin("1", sock_et) 69 | # writeBin("1", sock_et) 70 | # Request open orders 71 | # writeBin(c(.twsOutgoingMSG$REQ_OPEN_ORDERS, "1"), sock_et) 72 | # Submit data requests 73 | tickerId <- .trade_realtime(ib_connect, Contract, whatToShow, barSize, useRTH, tickerId) 74 | } # end if 75 | 76 | if(is.twsContract(Contract)) 77 | Contract <- list(Contract) 78 | 79 | # Define cancel function 80 | cancel_trade_realtime <- function(sock_et, tickerId) { 81 | if(inherits(sock_et, 'sockconn')) { 82 | for(i in 1:length(tickerId)) { 83 | writeBin(.twsOutgoingMSG$CANCEL_REAL_TIME_BARS, sock_et) 84 | writeBin('1', sock_et) 85 | writeBin(tickerId[i], sock_et) 86 | } 87 | } else { 88 | seek(sock_et, 0) 89 | } 90 | } # end cancel_trade_realtime 91 | 92 | if(is.null(CALLBACK)) 93 | CALLBACK <- twsDEBUG # function to simply return raw data 94 | 95 | if(!missing(CALLBACK) && is.na(list(CALLBACK))) { 96 | if(is.twsPlayback(ib_connect)) { 97 | seek(ib_connect[[1]], 0) 98 | stop("CALLBACK=NA is not available for playback") 99 | } 100 | return(tickerId) 101 | } 102 | 103 | # Run exit code 104 | on.exit(cancel_trade_realtime(sock_et, tickerId)) 105 | 106 | symbol.or.local <- function(x) { 107 | # used to find best name for id in output 108 | symbol <- x$symbol 109 | local <- x$local 110 | if(local=="") { 111 | return(symbol) 112 | } else return(local) 113 | } # end symbol.or.local 114 | eventWrapper$as_sign("symbols", sapply(Contract, symbol.or.local)) 115 | # data is list of vectors TimeStamp, Open, High, Low, Close, Volume, VWAP, Count 116 | # eventWrapper$assign.Data("data", rep(list(rep(NA, 8)), length(Contract))) 117 | 118 | timeStamp <- NULL 119 | if(!is.list(file)) 120 | file <- list(file) 121 | if(length(file) != length(Contract)) 122 | file <- rep(file, length(Contract)) 123 | } # end if (!back_test) 124 | 125 | # Run callback function 126 | CALLBACK(ib_connect, e_wrapper=eventWrapper, timestamp=timeStamp, file=file, back_test=back_test, ...) 127 | } # end trade_realtime 128 | 129 | 130 | `cancel_trade_realtime` <- function(ib_connect,tickerId) { 131 | if(!is.twsConnection(ib_connect)) 132 | stop("twsConnection object required") 133 | 134 | sock_et <- ib_connect[[1]] 135 | 136 | for(i in 1:length(tickerId)) { 137 | writeBin(.twsOutgoingMSG$CANCEL_REAL_TIME_BARS, sock_et) 138 | writeBin('1', sock_et) 139 | writeBin(tickerId[i], sock_et) 140 | } 141 | } # end cancel_trade_realtime 142 | -------------------------------------------------------------------------------- /R/twsBAG.R: -------------------------------------------------------------------------------- 1 | twsBAG <- 2 | function(...) { 3 | combolegs <- list(...) 4 | twsContract(0,"USD","BAG","SMART","","","0.0","USD","","","",NULL,combolegs,"0","","") 5 | } 6 | 7 | -------------------------------------------------------------------------------- /R/twsComboLeg.R: -------------------------------------------------------------------------------- 1 | twsComboLeg <- function(conId=0, 2 | ratio=0, 3 | action=c("BUY","SELL","SSHORT"), 4 | exchange=NULL, 5 | openClose=0, 6 | shortSaleSlot=0, 7 | designatedLocation="") 8 | { 9 | structure(list(conId=conId, 10 | ratio=ratio, 11 | action=action[1], 12 | exchange=exchange, 13 | openClose=openClose, 14 | shortSaleSlot=shortSaleSlot, 15 | designatedLocation=designatedLocation, 16 | SAME=0,OPEN=1,CLOSE=2,UNKNOWN=3), 17 | class="twsComboLeg") 18 | } 19 | -------------------------------------------------------------------------------- /R/twsConnect.R: -------------------------------------------------------------------------------- 1 | ibgConnect <- function(clientId=1, host="localhost", 2 | port=4001, verbose=TRUE, 3 | timeout=5, filename=NULL, 4 | blocking=.Platform$OS.type=="windows") { 5 | twsConnect(clientId, host, port, verbose, timeout, filename) 6 | } 7 | 8 | twsConnect <- twsConnect2 <- function(clientId=1, host="localhost", 9 | port=7496, verbose=TRUE, 10 | timeout=5, filename=NULL, 11 | blocking=.Platform$OS.type=="windows") { 12 | if(is.null(getOption('digits.secs'))) 13 | options(digits.secs=6) 14 | 15 | if(is.character(clientId)) 16 | filename <- clientId 17 | 18 | if(is.null(filename)) { 19 | start.time <- Sys.time() 20 | s <- socketConnection(host = host, port = port, 21 | open='ab', blocking=blocking) 22 | 23 | on.exit(close(s)) 24 | if(!isOpen(s)) { 25 | close(s) 26 | stop(paste("couldn't connect to TWS on port",port)) 27 | } 28 | CLIENT_VERSION <- "47" 29 | 30 | writeBin(c(CLIENT_VERSION,as.character(clientId)), s) 31 | 32 | eW <- eWrapper(NULL) 33 | eW$.Data <- environment() 34 | SERVER_VERSION <- NEXT_VALID_ID <- NULL 35 | eW$nextValidId <- function(curMsg, msg, timestamp, file, ...) { 36 | eW$.Data$NEXT_VALID_ID <- msg[2] 37 | } 38 | 39 | while(TRUE) { 40 | if( !is.null(NEXT_VALID_ID)) 41 | break 42 | if( !socketSelect(list(s), FALSE, 0.1)) 43 | next 44 | curMsg <- readBin(s, character(), 1) 45 | 46 | if(is.null(SERVER_VERSION)) { 47 | SERVER_VERSION <- curMsg[1] 48 | CONNECTION_TIME <- readBin(s, character(), 1) 49 | next 50 | } 51 | 52 | if(curMsg == .twsIncomingMSG$ERR_MSG) { 53 | errMsg <- readBin(s, character(), 4) 54 | close(s) 55 | on.exit() 56 | return( twsConnect(clientId+1, host, port, verbose, timeout, filename, blocking) ) 57 | } 58 | 59 | processMsg(curMsg, s, eW, NULL, "") 60 | 61 | if(Sys.time()-start.time > timeout) { 62 | close(s) 63 | stop('tws connection timed-out') 64 | } 65 | } 66 | on.exit() # successful connection 67 | 68 | twsconn <- new.env() 69 | twsconn$conn <- s 70 | twsconn$clientId <- clientId 71 | twsconn$nextValidId <- NEXT_VALID_ID 72 | twsconn$port <- port 73 | twsconn$server.version <- SERVER_VERSION 74 | twsconn$connected.at <- CONNECTION_TIME 75 | twsconn$connected <- NULL # not yet used 76 | class(twsconn) <- c("twsconn","environment") 77 | return(twsconn) 78 | } else { 79 | #file is defined - not a real connection 80 | fh <- file(filename,open='r') 81 | dat <- scan(fh, what=character(), quiet=TRUE) 82 | close(fh) 83 | 84 | tmp <- tempfile() 85 | fh <- file(tmp, open='ab') 86 | 87 | writeBin(dat, fh) 88 | 89 | close(fh) 90 | s <- file(tmp, open='rb') 91 | 92 | twsconn <- new.env() 93 | twsconn$conn <- s 94 | twsconn$clientId <- NULL 95 | twsconn$nextValidId <- NULL 96 | twsconn$port <- NULL 97 | twsconn$server.version <- NULL 98 | twsconn$connected.at <- filename 99 | class(twsconn) <- c("twsplay","twsconn","environment") 100 | return(twsconn) 101 | } 102 | } 103 | 104 | .twsConnect <- 105 | function (clientId=1, host='localhost', port = 7496, verbose=TRUE, 106 | timeout=5, filename=NULL, 107 | blocking=TRUE) 108 | { 109 | if(is.null(getOption('digits.secs'))) 110 | options(digits.secs=6) 111 | 112 | if(is.character(clientId)) 113 | filename <- clientId 114 | 115 | if(is.null(filename)) { 116 | start.time <- Sys.time() 117 | s <- socketConnection(host = host, port = port, 118 | open='ab', blocking=blocking) 119 | 120 | if(!isOpen(s)) { 121 | close(s) 122 | stop(paste("couldn't connect to TWS on port",port)) 123 | } 124 | 125 | CLIENT_VERSION <- "45" 126 | writeBin(c(CLIENT_VERSION,as.character(clientId)), s) 127 | Sys.sleep(1) 128 | 129 | while(TRUE) { 130 | curMsg <- readBin(s, character(), 1) 131 | if(length(curMsg) > 0) { 132 | if(curMsg == .twsIncomingMSG$ERR_MSG) { 133 | if(!errorHandler(s,verbose)) stop() 134 | } else { 135 | SERVER_VERSION <- curMsg 136 | CONNECTION_TIME <- readBin(s,character(),1) 137 | NEXT_VALID_ID <- readBin(s,character(),3)[3] 138 | break 139 | } 140 | } 141 | if(Sys.time()-start.time > timeout) { 142 | close(s) 143 | stop('tws connection timed-out') 144 | } 145 | } 146 | on.exit() # successful connection 147 | 148 | structure(list(s, 149 | clientId=clientId,port=port, 150 | server.version=SERVER_VERSION, 151 | connected.at=CONNECTION_TIME), 152 | class = "twsConnection") 153 | } else { 154 | #file is defined - not a real connection 155 | fh <- file(filename,open='r') 156 | dat <- scan(fh, what=character(), quiet=TRUE) 157 | close(fh) 158 | 159 | tmp <- tempfile() 160 | fh <- file(tmp, open='ab') 161 | 162 | #writeBin(c(as.character(length(dat)),dat), fh) 163 | writeBin(dat, fh) 164 | #for(i in dat) writeBin(i, fh) 165 | 166 | close(fh) 167 | s <- file(tmp, open='rb') 168 | 169 | structure(list(s, 170 | clientId=NULL,port=NULL, 171 | server.version=NULL, 172 | connected.at=filename), 173 | class = c("twsPlayback","twsConnection")) 174 | 175 | } 176 | } 177 | 178 | is.twsConnection <- function(x) 179 | { 180 | inherits(x, "twsConnection") || inherits(x, "twsconn") 181 | } 182 | 183 | is.twsPlayback <- function(x) 184 | { 185 | inherits(x, "twsPlayback") || inherits(x, "twsplay") 186 | } 187 | 188 | isConnected <- function(twsconn) 189 | { 190 | # if( !.Call("still_alive", twsconn[[1]])) 191 | # return(FALSE) 192 | 193 | is_open <- function(con) { 194 | if(inherits(try(isOpen(con), silent=TRUE), 'try-error')) { 195 | FALSE 196 | } else TRUE 197 | } 198 | if( !is.twsConnection(twsconn)) { 199 | warning("isConnected requires a twsconn object") 200 | return(FALSE) 201 | } 202 | 203 | if( !is.null(twsconn$connected)) { 204 | return( is_open(twsconn[[1]]) && twsconn$connected ) 205 | } else { 206 | is_open(twsconn[[1]]) 207 | } 208 | 209 | # if(is.twsConnection(x)) { 210 | # if(inherits(try(isOpen(x[[1]]), silent=TRUE), 'try-error')) { 211 | # FALSE 212 | # } else TRUE 213 | # } else isOpen(x) 214 | } 215 | -------------------------------------------------------------------------------- /R/twsConnectionTime.R: -------------------------------------------------------------------------------- 1 | `twsConnectionTime` <- 2 | function(con) { 3 | if(!is.twsConnection(con)) 4 | stop('con must be a twsConnection object') 5 | 6 | return(con$connected.at) 7 | } 8 | -------------------------------------------------------------------------------- /R/twsContract.R: -------------------------------------------------------------------------------- 1 | twsContract <- 2 | function(conId,symbol,sectype,exch,primary,expiry,strike, 3 | currency,right,local,multiplier,combo_legs_desc, 4 | comboleg,include_expired,secIdType="",secId="") 5 | { 6 | if(is.null(names(match.call()[-1]))) 7 | return(do.call("twsContract", rep(list(""), 14))) 8 | 9 | structure( 10 | list(conId=conId, 11 | symbol=symbol, 12 | sectype=sectype, 13 | exch=exch, 14 | primary=primary, 15 | expiry=expiry, 16 | strike=strike, 17 | currency=currency, 18 | right=right, 19 | local=local, 20 | multiplier=multiplier, 21 | combo_legs_desc=combo_legs_desc, 22 | comboleg=comboleg, 23 | include_expired=include_expired, 24 | secIdType=secIdType, 25 | secId=secId 26 | ), 27 | class='twsContract' 28 | ) 29 | } 30 | 31 | print.eventPortfolioValue <- `print.twsContractDetails` <- `print.twsContract` <- 32 | function(x, ...) { 33 | str(unclass(x)) 34 | } 35 | print.eventAccountValue <- function(x, ...) { 36 | print(t(as.data.frame(unclass(x))), quote=FALSE) 37 | } 38 | 39 | is.twsContract <- function(x) 40 | { 41 | inherits(x, 'twsContract') 42 | } 43 | 44 | is.twsContractDetails <- function(x) 45 | { 46 | inherits(x, 'twsContractDetails') 47 | } 48 | 49 | as.twsContract <- function(x, ...) 50 | { 51 | UseMethod("as.twsContract") 52 | } 53 | 54 | as.twsContract.list <- function(x, ...) 55 | { 56 | lapply(x, as.twsContract, ...) 57 | } 58 | 59 | as.twsContract.twsContract <- function(x, ...) 60 | { 61 | x 62 | } 63 | 64 | as.twsContract.list <- function(x, ...) 65 | { 66 | lapply(x, function(xx) { 67 | if(is.twsContract(xx)) { 68 | return(xx) 69 | } else 70 | if(is.twsContractDetails(xx)) { 71 | return(as.twsContract(xx)) 72 | }}) 73 | } 74 | 75 | as.twsContract.twsContractDetails <- function(x, ...) 76 | { 77 | x$contract 78 | } 79 | 80 | as.twsContract.twsComboLeg <- function(x) { 81 | con <- twsContract() 82 | con$conId <- x$conId 83 | con$include_expired <- "1" 84 | con 85 | } 86 | 87 | twsContractDetails <- 88 | function(version=NULL, 89 | contract=twsContract(), 90 | marketName=NULL, 91 | tradingClass=NULL, 92 | conId=NULL, 93 | minTick=NULL, 94 | multiplier=NULL, 95 | orderTypes=NULL, 96 | validExchanges=NULL, 97 | priceMagnifier=NULL, 98 | underConId=NULL, 99 | longName=NULL, 100 | contractMonth=NULL, 101 | industry=NULL, 102 | category=NULL, 103 | subcategory=NULL, 104 | timeZoneId=NULL, 105 | tradingHours=NULL, 106 | liquidHours=NULL 107 | ) 108 | structure( 109 | list(version=version, 110 | contract=contract, 111 | marketName=marketName, 112 | tradingClass=tradingClass, 113 | conId=conId, 114 | minTick=minTick, 115 | orderTypes=orderTypes, 116 | validExchanges=validExchanges, 117 | priceMagnifier=priceMagnifier, 118 | underConId=underConId, 119 | longName=longName, 120 | contractMonth=contractMonth, 121 | industry=industry, 122 | category=category, 123 | subcategory=subcategory, 124 | timeZoneId=timeZoneId, 125 | tradingHours=tradingHours, 126 | liquidHours=liquidHours 127 | ), 128 | class='twsContractDetails' 129 | ) 130 | -------------------------------------------------------------------------------- /R/twsCurrency.R: -------------------------------------------------------------------------------- 1 | `twsCurrency` <- 2 | function (symbol,currency="USD",exch="IDEALPRO", primary="", strike = "0.0", 3 | right = "", local = "", multiplier = "", include_expired = "0", conId=0) 4 | { 5 | twsContract(conId,symbol, "CASH", exch, primary, expiry = "", strike, 6 | currency, right, local, multiplier, NULL, NULL, include_expired) 7 | } 8 | 9 | `twsCASH` <- twsCurrency 10 | -------------------------------------------------------------------------------- /R/twsDisconnect.R: -------------------------------------------------------------------------------- 1 | twsDisconnect <- function(twsconn) { 2 | if(!is.twsConnection(twsconn)) 3 | stop("not a 'tws' connection") 4 | close(twsconn) 5 | } 6 | 7 | close.twsConnection <- function(con, ...) 8 | { 9 | close(con[[1]]) 10 | } 11 | 12 | close.twsconn <- function(con, ...) 13 | { 14 | con$connected <- FALSE 15 | close(con$conn) 16 | } 17 | -------------------------------------------------------------------------------- /R/twsEquity.R: -------------------------------------------------------------------------------- 1 | twsSTK <- twsEquity <- 2 | function(symbol,exch="SMART",primary="",strike='0.0', 3 | currency='USD',right='',local='',multiplier='',include_expired='0',conId=0) 4 | { 5 | twsContract(conId,symbol,'STK',exch,primary,expiry='',strike, 6 | currency,right,local,multiplier,NULL,NULL,include_expired) 7 | } 8 | 9 | twsCFD <- function(symbol, exch, primary="", strike="", 10 | currency, right="", local="", multiplier="", 11 | include_expired="0", conId=0) { 12 | twsContract(conId,symbol,'CFD',exch,primary,expiry='',strike, 13 | currency,right,local,multiplier,NULL,NULL,include_expired) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /R/twsExecution.R: -------------------------------------------------------------------------------- 1 | `twsExecution` <- 2 | function(orderId, 3 | clientId, 4 | execId, 5 | time, 6 | acctNumber, 7 | exchange, 8 | side, 9 | shares, 10 | price, 11 | permId, 12 | liquidation, 13 | cumQty, 14 | avgPrice) { 15 | 16 | # special constructor if called with no args 17 | if(is.null(names(match.call()[-1]))) 18 | return(do.call('twsExecution', rep(list(NULL),13))) 19 | 20 | structure(list(orderId=orderId, 21 | clientId=clientId, 22 | execId=execId, 23 | time=time, 24 | acctNumber=acctNumber, 25 | exchange=exchange, 26 | side=side, 27 | shares=shares, 28 | price=price, 29 | permId=permId, 30 | liquidation=liquidation, 31 | cumQty=cumQty, 32 | avgPrice=avgPrice), 33 | class="twsExecution") 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /R/twsExecutionFilter.R: -------------------------------------------------------------------------------- 1 | twsExecutionFilter <- function(clientId="0", 2 | acctCode="", 3 | time="", 4 | symbol="", 5 | secType="", 6 | exchange="", 7 | side="") 8 | { 9 | structure(list(clientId=clientId, 10 | acctCode=acctCode, 11 | time=time, 12 | symbol=symbol, 13 | secType=secType, 14 | exchange=exchange, 15 | side=side), class="twsExecutionFilter") 16 | } 17 | -------------------------------------------------------------------------------- /R/twsFuture.R: -------------------------------------------------------------------------------- 1 | `twsFuture` <- 2 | function(symbol,exch,expiry,primary='', 3 | currency='USD',right='',local='',multiplier='',include_expired='0',conId=0) 4 | { 5 | twsContract(conId,symbol,'FUT',exch,primary,expiry,strike='0.0', 6 | currency,right,local,multiplier,NULL,NULL,include_expired) 7 | } 8 | 9 | `twsFUT` <- twsFuture 10 | -------------------------------------------------------------------------------- /R/twsFutureOpt.R: -------------------------------------------------------------------------------- 1 | `twsFutureOpt` <- 2 | function(symbol,exch,expiry,strike='',right='',primary='', 3 | currency='USD',local='',multiplier='',include_expired='0',conId=0) 4 | { 5 | twsContract(conId,symbol,'FOP',exch,primary,expiry,as.character(strike), 6 | currency,right,local,multiplier,NULL,NULL,include_expired) 7 | } 8 | 9 | `twsFOP` <- twsFutureOpt 10 | -------------------------------------------------------------------------------- /R/twsIndex.R: -------------------------------------------------------------------------------- 1 | twsIND <- twsIndex <- 2 | function(symbol, exch="", currency="", local="") 3 | { 4 | twsContract(conId="", 5 | symbol, 6 | 'IND', 7 | exch=exch, 8 | primary="", 9 | expiry="", 10 | strike="", 11 | currency=currency, 12 | right="", 13 | local=local, 14 | multiplier="", 15 | NULL,NULL, 16 | include_expired="") 17 | } 18 | -------------------------------------------------------------------------------- /R/twsMethods.R: -------------------------------------------------------------------------------- 1 | `print.twsConnection` <- 2 | function(x,...) { 3 | cat('\n', sep="") 5 | } 6 | 7 | print.twsconn <- function(x,...) { 8 | if( isOpen(x[[1]])) { 9 | cat('\n', sep="") 11 | } else 12 | cat('\n') 13 | } 14 | 15 | `[[.twsconn` <- function(x, i, ...) { 16 | if(i==1) 17 | return(x$conn) 18 | NULL 19 | } 20 | -------------------------------------------------------------------------------- /R/twsOption.R: -------------------------------------------------------------------------------- 1 | `twsOption` <- 2 | function(local,expiry="", 3 | strike="",right="",exch="SMART",primary="", 4 | currency="USD",symbol="",multiplier="100",include_expired="0",conId=0) 5 | { 6 | twsContract(conId,symbol,"OPT",exch,primary, 7 | expiry,strike,currency,right, 8 | local,multiplier,NULL,NULL, 9 | include_expired) 10 | } 11 | 12 | `twsOPT` <- twsOption 13 | -------------------------------------------------------------------------------- /R/twsOrder.R: -------------------------------------------------------------------------------- 1 | `.twsOrderID` <- 2 | structure(list(CUSTOMER=0, FIRM=1, 3 | OPT_UNKNOWN="?", OPT_BROKER_DEALER="b", 4 | OPT_CUSTOMER="c", OPT_FIRM="f", OPT_ISEMM="m", 5 | OPT_FARMM="n", OPT_SPECIALIST="y", 6 | AUCTION_MATCH=1, AUCTION_IMPROVEMENT=2, AUCTION_TRANSPARENT=3, 7 | EMPTY_STR=""), 8 | .Names=c('CUSTOMER', 'FIRM', 9 | 'OPT_UNKNOWN', 'OPT_BROKER_DEALER', 10 | 'OPT_CUSTOMER', 'OPT_FIRM', 'OPT_ISEMM', 11 | 'OPT_FARMM', 'OPT_SPECIALIST', 12 | 'AUCTION_MATCH', 'AUCTION_IMPROVEMENT', 'AUCTION_TRANSPARENT', 13 | 'EMPTY_STR')) 14 | 15 | `twsOrder` <- 16 | function(orderId, 17 | action="BUY", 18 | totalQuantity="10", 19 | orderType="LMT", 20 | lmtPrice="0.0", 21 | auxPrice="0.0", 22 | tif="", 23 | outsideRTH="0", #FALSE 24 | openClose="O", 25 | origin=.twsOrderID$CUSTOMER, 26 | ocaGroup="", 27 | account="", 28 | orderRef="", 29 | transmit=TRUE, 30 | parentId="0", 31 | blockOrder="0", 32 | sweepToFill="0", 33 | displaySize="0", 34 | triggerMethod="0", 35 | hidden="0", 36 | discretionaryAmt="0.0", 37 | goodAfterTime="", 38 | goodTillDate="", 39 | faGroup="", faMethod="", faPercentage="", faProfile="", 40 | shortSaleSlot="0", 41 | designatedLocation=.twsOrderID$EMPTY_STR, 42 | ocaType="0", 43 | rule80A="", 44 | settlingFirm="", 45 | clearingAccount="", clearingIntent="", 46 | allOrNone="0", 47 | minQty="", 48 | percentOffset="", 49 | eTradeOnly="0", 50 | firmQuoteOnly="0", 51 | nbboPriceCap="", 52 | auctionStrategy="0", 53 | startingPrice="", 54 | stockRefPrice="", 55 | delta="", 56 | stockRangeLower="", 57 | stockRangeUpper="", 58 | overridePercentageConstraints="0", 59 | volatility="", 60 | volatilityType="", 61 | deltaNeutralOrderType="", 62 | deltaNeutralAuxPrice="", 63 | continuousUpdate="0", 64 | referencePriceType="", 65 | trailStopPrice="", 66 | basisPoints="", 67 | basisPointsType="", 68 | scaleInitLevelSize="", 69 | scaleSubsLevelSize="", 70 | scalePriceIncrement="", 71 | notHeld=FALSE, 72 | algoStrategy="", 73 | algoParams=NULL, 74 | whatIf=FALSE, 75 | clientId="", permId="" 76 | ) 77 | { 78 | if(missing(orderId)) 79 | orderId <- "" 80 | structure( 81 | # main order fields 82 | list(orderId=orderId, 83 | clientId=clientId, 84 | permId=permId, 85 | action=action, 86 | totalQuantity=as.character(as.numeric(totalQuantity)), 87 | orderType=orderType, 88 | lmtPrice=as.character(lmtPrice), 89 | auxPrice=as.character(auxPrice), 90 | 91 | # Extended order fields 92 | tif=tif, 93 | ocaGroup=ocaGroup, 94 | ocaType=ocaType, 95 | orderRef=orderRef, 96 | transmit=as.character(as.integer(transmit)), #if FALSE, will be created but not transmitted 97 | parentId=parentId, #Parent order Id 98 | blockOrder=blockOrder, 99 | sweepToFill=sweepToFill, 100 | displaySize=displaySize, 101 | triggerMethod=triggerMethod, # 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last, 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Midpoint 102 | outsideRTH=outsideRTH, 103 | hidden=hidden, 104 | goodAfterTime=goodAfterTime, 105 | goodTillDate=goodTillDate, 106 | overridePercentageConstraints=overridePercentageConstraints, 107 | rule80A=rule80A, 108 | allOrNone=allOrNone, 109 | minQty=minQty, 110 | percentOffset=percentOffset, 111 | trailStopPrice=trailStopPrice, 112 | 113 | # FA only 114 | faGroup=faGroup, 115 | faProfile=faProfile, 116 | faMethod=faMethod, 117 | faPercentage=faPercentage, 118 | 119 | # Institutional Orders Only 120 | openClose=openClose, 121 | origin=origin, 122 | shortSaleSlot=shortSaleSlot, 123 | designatedLocation=designatedLocation, 124 | 125 | # SMART routing only 126 | discretionaryAmt=discretionaryAmt, 127 | eTradeOnly=eTradeOnly, 128 | firmQuoteOnly=firmQuoteOnly, 129 | nbboPriceCap=nbboPriceCap, 130 | 131 | # BOX or VOL orders only 132 | auctionStrategy=auctionStrategy, 133 | 134 | # BOX orders only 135 | startingPrice=startingPrice, 136 | stockRefPrice=stockRefPrice, 137 | delta=delta, 138 | 139 | # pegged to stock or VOL orders 140 | stockRangeLower=stockRangeLower, 141 | stockRangeUpper=stockRangeUpper, 142 | 143 | # VOLATILITY orders only 144 | volatility=volatility, 145 | volatilityType=volatilityType, 146 | continuousUpdate=continuousUpdate, 147 | referencePriceType=referencePriceType, 148 | deltaNeutralOrderType=deltaNeutralOrderType, 149 | deltaNeutralAuxPrice=deltaNeutralAuxPrice, 150 | 151 | # COMBO orders 152 | basisPoints=basisPoints, 153 | basisPointsType=basisPointsType, 154 | 155 | # SCALE orders 156 | scaleInitLevelSize=scaleInitLevelSize, 157 | scaleSubsLevelSize=scaleSubsLevelSize, 158 | scalePriceIncrement=scalePriceIncrement, 159 | 160 | # Clearing info 161 | account=account, 162 | settlingFirm=settlingFirm, 163 | clearingAccount=clearingAccount, 164 | clearingIntent=clearingIntent, 165 | 166 | # Algo Orders Only 167 | algoStrategy=algoStrategy, 168 | algoParams=algoParams, 169 | 170 | # what if 171 | whatIf=as.character(as.integer(whatIf)), 172 | 173 | # Not Held 174 | notHeld=as.character(as.integer(notHeld)) 175 | ), 176 | class='twsOrder' 177 | ) 178 | } 179 | 180 | 181 | `print.twsOrder` <- 182 | function(x, ...) { 183 | str(unclass(x)) 184 | } 185 | -------------------------------------------------------------------------------- /R/twsOrderState.R: -------------------------------------------------------------------------------- 1 | `twsOrderState` <- 2 | function(status=NULL, 3 | initMargin=NULL, 4 | maintMargin=NULL, 5 | equityWithLoan=NULL, 6 | commission=0.0, 7 | minCommission=0.0, 8 | maxCommission=0.0, 9 | commissionCurrency=NULL, 10 | warningText=NULL 11 | ) 12 | { 13 | structure( 14 | list(status=status, 15 | initMargin=initMargin, 16 | maintMargin=maintMargin, 17 | equityWithLoan=equityWithLoan, 18 | commission=commission, 19 | minCommission=minCommission, 20 | maxCommission=maxCommission, 21 | commissionCurrency=commissionCurrency, 22 | warningText=warningText 23 | ), 24 | class='twsOrderState' 25 | ) 26 | } 27 | 28 | 29 | `print.twsOrderState` <- 30 | function(x, ...) { 31 | str(unclass(x)) 32 | } 33 | -------------------------------------------------------------------------------- /R/twsPortfolioValue.R: -------------------------------------------------------------------------------- 1 | twsPortfolioValue <- function(x, zero.pos=TRUE, ...) { 2 | UseMethod("twsPortfolioValue") 3 | } 4 | 5 | twsPortfolioValue.eWrapper <- function(x, zero.pos=TRUE, ...) { 6 | # to extract the .Portfolio data element from 7 | # eWrappers in future releases 8 | } 9 | 10 | twsPortfolioValue.AccountUpdate <- function(x, zero.pos=TRUE, ...) { 11 | portf <- do.call(rbind, 12 | lapply(x[[2]], function(x) 13 | data.frame(local=x$contract$local, 14 | sectype=x$contract$sectype, 15 | marketValue=x[[2]]$marketValue, 16 | averageCost=x[[2]]$averageCost*x[[2]]$position, 17 | return=with(x[[2]],(marketValue/(averageCost*position)-1) * sign(position)), 18 | position=x[[2]]$position, 19 | realizedPNL=x[[2]]$realizedPNL, 20 | unrealizedPNL=x[[2]]$unrealizedPNL))) 21 | if(!zero.pos) 22 | portf[which(portf$position != 0),] 23 | else 24 | portf 25 | } 26 | 27 | summary.AccountUpdate <- function(object, ...) { 28 | twsPortfolioValue.AccountUpdate(object, ...) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /R/twsTickType.R: -------------------------------------------------------------------------------- 1 | `.twsTickType` <- 2 | structure(list( 3 | BID_SIZE = 0, 4 | BID = 1, 5 | ASK = 2, 6 | ASK_SIZE = 3, 7 | LAST = 4, 8 | LAST_SIZE = 5, 9 | HIGH = 6, 10 | LOW = 7, 11 | VOLUME = 8, 12 | CLOSE = 9, 13 | BID_OPTION = 10, 14 | ASK_OPTION = 11, 15 | LAST_OPTION = 12, 16 | MODEL_OPTION = 13, 17 | OPEN = 14, 18 | LOW_13_WEEK = 15, 19 | HIGH_13_WEEK = 16, 20 | LOW_26_WEEK = 17, 21 | HIGH_26_WEEK = 18, 22 | LOW_52_WEEK = 19, 23 | HIGH_52_WEEK = 20, 24 | AVG_VOLUME = 21, 25 | OPEN_INTEREST = 22, 26 | OPTION_HISTORICAL_VOL = 23, 27 | OPTION_IMPLIED_VOL = 24, 28 | OPTION_BID_EXCH = 25, 29 | OPTION_ASK_EXCH = 26, 30 | OPTION_CALL_OPEN_INTEREST = 27, 31 | OPTION_PUT_OPEN_INTEREST = 28, 32 | OPTION_CALL_VOLUME = 29, 33 | OPTION_PUT_VOLUME = 30, 34 | INDEX_FUTURE_PREMIUM = 31, 35 | BID_EXCH = 32, 36 | ASK_EXCH = 33, 37 | AUCTION_VOLUME = 34, 38 | AUCTION_PRICE = 35, 39 | AUCTION_IMBALANCE = 36, 40 | MARK_PRICE = 37, 41 | BID_EFP_COMPUTATION = 38, 42 | ASK_EFP_COMPUTATION = 39, 43 | LAST_EFP_COMPUTATION = 40, 44 | OPEN_EFP_COMPUTATION = 41, 45 | HIGH_EFP_COMPUTATION = 42, 46 | LOW_EFP_COMPUTATION = 43, 47 | CLOSE_EFP_COMPUTATION = 44, 48 | LAST_TIMESTAMP = 45, 49 | SHORTABLE = 46, 50 | FUNDAMENTAL_RATIOS = 47, 51 | RT_VOLUME = 48, 52 | HALTED = 49), 53 | .Names=c( "BID_SIZE","BID","ASK","ASK_SIZE","LAST","LAST_SIZE", 54 | "HIGH","LOW","VOLUME","CLOSE","BID_OPTION", 55 | "ASK_OPTION","LAST_OPTION","MODEL_OPTION","OPEN","LOW_13_WEEK", 56 | "HIGH_13_WEEK","LOW_26_WEEK","HIGH_26_WEEK","LOW_52_WEEK","HIGH_52_WEEK","AVG_VOLUME", 57 | "OPEN_INTEREST","OPTION_HISTORICAL_VOL", 58 | "OPTION_IMPLIED_VOL","OPTION_BID_EXCH","OPTION_ASK_EXCH", 59 | "OPTION_CALL_OPEN_INTEREST","OPTION_PUT_OPEN_INTEREST", 60 | "OPTION_CALL_VOLUME","OPTION_PUT_VOLUME","INDEX_FUTURE_PREMIUM", 61 | "BID_EXCH","ASK_EXCH","AUCTION_VOLUME","AUCTION_PRICE", 62 | "AUCTION_IMBALANCE","MARK_PRICE","BID_EFP_COMPUTATION","ASK_EFP_COMPUTATION", 63 | "LAST_EFP_COMPUTATION","OPEN_EFP_COMPUTATION","HIGH_EFP_COMPUTATION","LOW_EFP_COMPUTATION", 64 | "CLOSE_EFP_COMPUTATION","LAST_TIMESTAMP","SHORTABLE","FUNDAMENTAL_RATIOS","RT_VOLUME","HALTED")) 65 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .IBrokersEnv <- new.env() 2 | 3 | .onAttach <- function(libname, pkgname) { 4 | packageStartupMessage("IBrokers2 version 0.1. Implementing API Version 9.64") 5 | packageStartupMessage("\nIBrokers2 comes with NO WARRANTY. NOT INTENDED FOR LIVE TRADING!\n\n") 6 | packageStartupMessage("See ?IBrokers2 for details.") 7 | } 8 | 9 | .onLoad <- function(libname,pkgname) { 10 | } 11 | 12 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: IBrokers2 Package for Executing Real-Time Trading Strategies Via the API of Interactive Brokers 3 | author: "Jerzy Pawlowski (algoquant)" 4 | tags: Interactive Brokers, API 5 | abstract: R functions for executing real-time trading strategies via the API of Interactive Brokers (IB API). The package *IBrokers2* is derived from *IBrokers*, and is fully backward compatible with it. 6 | output: 7 | md_document: 8 | variant: markdown_github 9 | --- 10 | 11 | [![Build Status](https://travis-ci.org/algoquant/IBrokers2.svg?branch=master)](https://travis-ci.org/algoquant/IBrokers2) 12 | 13 | 14 | ### Overview 15 | 16 | The package *IBrokers2* contains *R* functions for executing real-time trading strategies via the API of Interactive Brokers (IB API). The package *IBrokers2* is derived from package *IBrokers*, and is fully backward compatible with it. This means that all the *IBrokers* functions and variables are preserved exactly in *IBrokers2*, while some additional functions have been added. The new functions mostly provide additional trade execution capabilities, for running systematic trading strategies in a callback loop. 17 | 18 | More information can be found in the document *real_time_trading.html* in the vignettes sub-directory. 19 | 20 | 21 | ### Installation and Loading 22 | 23 | Install package *IBrokers2* from github: 24 | ```{r eval=FALSE} 25 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 26 | install.packages("devtools") 27 | devtools::install_github(repo="algoquant/IBrokers2") 28 | library(IBrokers2) 29 | ``` 30 |
31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/algoquant/IBrokers2.svg?branch=master)](https://travis-ci.org/algoquant/IBrokers2) 2 | 3 | ### Overview 4 | 5 | The package *IBrokers2* contains *R* functions for executing real-time trading strategies via the API of Interactive Brokers (IB API). The package *IBrokers2* is derived from package *IBrokers*, and is fully backward compatible with it. This means that all the *IBrokers* functions and variables are preserved exactly in *IBrokers2*, while some additional functions have been added. The new functions mostly provide additional trade execution capabilities, for running systematic trading strategies in a callback loop. 6 | 7 | More information can be found in the document *real\_time\_trading.html* in the vignettes sub-directory. 8 | 9 | ### Installation and Loading 10 | 11 | Install package *IBrokers2* from github: 12 | 13 | ``` r 14 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 15 | install.packages("devtools") 16 | devtools::install_github(repo="algoquant/IBrokers2") 17 | library(IBrokers2) 18 | ``` 19 | 20 |
21 | -------------------------------------------------------------------------------- /man/hello.Rd: -------------------------------------------------------------------------------- 1 | \name{hello} 2 | \alias{hello} 3 | \title{Hello, World!} 4 | \usage{ 5 | hello() 6 | } 7 | \description{ 8 | Prints 'Hello, world!'. 9 | } 10 | \examples{ 11 | hello() 12 | } 13 | -------------------------------------------------------------------------------- /scripts/IB_trading.R: -------------------------------------------------------------------------------- 1 | #################################### 2 | ### Script for trading through Interactive Brokers API 3 | ### using package IBrokers2. 4 | 5 | ### WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! 6 | ### THESE SCRIPTS ARE FOR PAPER TRADING ONLY. 7 | ### DO NOT USE THEM FOR LIVE TRADING WITH REAL CAPITAL! 8 | 9 | ### This is only a proof of concept for testing the API code. 10 | ### This is NOT a realistic trading algorithm. 11 | ### It will lose money in actual trading. 12 | ### Do NOT use this code with real money. 13 | ### Use it ONLY for paper trading. 14 | 15 | 16 | ### Load packages 17 | 18 | # Install package *rutils* from github: 19 | devtools::install_github(repo="algoquant/rutils") 20 | library(rutils) 21 | 22 | # Install package *IBrokers2* from github: 23 | devtools::install_github(repo="algoquant/IBrokers2") 24 | library(IBrokers2) 25 | 26 | # Load the trading function written as an eWrapper: 27 | # source("C:/Develop/R/IBrokers2/R/trade_wrapper.R") 28 | 29 | 30 | ### Scripts for running a simple trading strategy in a callback loop: 31 | 32 | # The script will also save bar data into files 33 | 34 | # The simple market-making strategy is defined as follows: 35 | # Place limit buy order at previous bar Low price minus buy_spread, 36 | # Place limit sell order at previous bar High price plus sell_spread. 37 | # 38 | # The trading strategy functions are defined inside the function 39 | # realtimeBars(), which is part of the trade wrapper. 40 | # The user can customize the strategy or create a new strategy by 41 | # modifying the trading function code in the function realtimeBars() 42 | # in the file trade_wrapper.R 43 | 44 | 45 | ## Define parameters for strategies 46 | 47 | # Define instrument for trading one ES futures contract 48 | con_tracts <- list(ES=IBrokers2::twsFuture(symbol="ES", exch="GLOBEX", expiry="201912")) 49 | 50 | # Define parameters of market making strategy 51 | trade_params <- list(ES=list(model_function="make_markets", 52 | model_params=c(buy_spread=0.25, sell_spread=0.25, siz_e=1, pos_limit=10, lagg=2, lamb_da=0.05))) 53 | 54 | # Define parameters of EWMA crossover strategy 55 | trade_params <- list(ES=list(model_function="crossover_strat", 56 | model_params=c(is_contrarian=TRUE, siz_e=2, lamb_da=0.2))) 57 | 58 | 59 | # Define instruments for trading two stocks: GOOG and AAPL 60 | # con_tract <- IBrokers::twsEquity("AAPL", primary="SMART") 61 | sym_bols <- c("GOOG", "AAPL") 62 | con_tracts <- lapply(sym_bols, IBrokers2::twsEquity, primary="SMART") 63 | names(con_tracts) <- sym_bols 64 | 65 | # Define parameters for pairs trading two stocks: GOOG and AAPL 66 | # The traded instrument is second in the list so that the model 67 | # is run on contemporaneous data, after the bars for both instruments arrive. 68 | trade_params <- list(AAPL=NULL, 69 | GOOG=list(model_function="pairs_strat", 70 | model_params=c(is_contrarian=TRUE, siz_e=100, look_back=5, thresh_old=1.0, lamb_da=0.2))) 71 | 72 | 73 | ## Open the files for storing the bar data 74 | data_dir <- "C:/Develop/data/ib_data" 75 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 76 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 77 | 78 | ## Open the IB connection to TWS 79 | ac_count <- "DU1851021" 80 | ib_connect <- IBrokers2::twsConnect(port=7497) 81 | 82 | # Run the trading model (strategy): 83 | IBrokers2::trade_realtime(ib_connect=ib_connect, 84 | Contract=con_tracts, 85 | tickerId=seq_along(con_tracts), 86 | useRTH=FALSE, 87 | back_test=FALSE, 88 | eventWrapper=IBrokers2::trade_wrapper(ac_count=ac_count, 89 | con_tracts=con_tracts, 90 | trade_params=trade_params, 91 | file_connects=file_connects, 92 | warm_up=6), 93 | CALLBACK=IBrokers2::call_back, 94 | file=file_connects) 95 | 96 | # Stop the trading loop by hitting the red STOP button in RStudio 97 | 98 | # Close IB connection 99 | IBrokers2::twsDisconnect(ib_connect) 100 | 101 | # Close data files 102 | for (file_connect in file_connects) close(file_connect) 103 | 104 | 105 | # extra 106 | 107 | ### Scripts for running a simple trading strategy in a callback loop: 108 | 109 | # The script will also save bar data into files 110 | 111 | # The simple market-making strategy is defined as follows: 112 | # Place limit buy order at previous bar Low price minus buy_spread, 113 | # Place limit sell order at previous bar High price plus sell_spread. 114 | # 115 | # The strategy is defined inside the function model_fun() which 116 | # is part of the eWrapper defined by trade_wrapper(). 117 | # The user can customize this strategy by modifying the trading 118 | # code in the function model_fun(). 119 | 120 | # Define named lists for trading one contract 121 | con_tracts <- list(ES=IBrokers2::twsFuture(symbol="ES", exch="GLOBEX", expiry="201912")) 122 | trade_params <- list(ES=c(buy_spread=0.75, sell_spread=0.75, siz_e=1, lagg=2, lamb_da=0.05)) 123 | 124 | # Open the files for storing the bar data 125 | data_dir <- "C:/Develop/data/ib_data" 126 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 127 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 128 | 129 | # Open the IB connection to TWS 130 | ac_count <- "DU1851021" 131 | ib_connect <- IBrokers2::twsConnect(port=7497) 132 | 133 | # Run the trading model (strategy): 134 | IBrokers2::trade_realtime(ib_connect=ib_connect, 135 | Contract=con_tracts, 136 | useRTH=FALSE, 137 | back_test=FALSE, 138 | eventWrapper=IBrokers2::trade_wrapper(ac_count=ac_count, 139 | con_tracts=con_tracts, 140 | trade_params=trade_params, 141 | file_connects=file_connects, 142 | warm_up=10), 143 | CALLBACK=IBrokers2::call_back, 144 | file=file_connects) 145 | 146 | # Stop the trading loop by hitting the red STOP button in RStudio 147 | 148 | # Close IB connection 149 | IBrokers2::twsDisconnect(ib_connect) 150 | 151 | # Close data files 152 | for (file_connect in file_connects) close(file_connect) 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /scripts/IB_trading_Stevens_2019.R: -------------------------------------------------------------------------------- 1 | #################################### 2 | ### R scripts for the presentation by Jerzy Pawlowski, titled: 3 | # Package iBrokers2 for Real-time Trading With Interactive Brokers 4 | # Given on June 27th, 2019, at the 5 | # Stevens Conference on High-Frequency Finance and Analytics. 6 | 7 | # These are R scripts for PAPER TRADING through Interactive 8 | # Brokers API using package IBrokers2. 9 | 10 | ### WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! 11 | ### THESE SCRIPTS ARE FOR PAPER TRADING ONLY. 12 | ### DO NOT USE THEM FOR LIVE TRADING WITH REAL CAPITAL! 13 | 14 | 15 | ############ DISCLAIMER ############ 16 | 17 | # The package IBrokers2 allows users to test their own 18 | # trading strategies in paper trading, without having 19 | # to program the IB API directly. 20 | # It can be an element of a toolkit for developing 21 | # trading strategies, and testing them in paper trading. 22 | # The package IBrokers2 is NOT a software product for 23 | # inexperienced users, and it requires strong knowledge 24 | # of R and the IB API. 25 | # The package IBrokers2 does NOT provide realistic 26 | # trading strategies. 27 | # The package IBrokers2 comes with no warranty, and it 28 | # is not affiliated or endorsed by Interactive Brokers. 29 | 30 | 31 | ############ INSTRUCTIONS ############ 32 | 33 | # Please install the Interactive Brokers Trader Workstation 34 | # (TWS) on your computer. 35 | # Please install RStudio, and run the following scripts from 36 | # RStudio. 37 | # The following scripts require the user to be logged into 38 | # the TWS on the same computer as the one running the scripts. 39 | # The scripts will place trade orders to IB, and they will 40 | # also save the bar data into files on your computer. 41 | 42 | ## Load packages 43 | 44 | # Install package *rutils* from github: 45 | devtools::install_github(repo="algoquant/rutils") 46 | library(rutils) 47 | 48 | # Install package *IBrokers2* from github: 49 | devtools::install_github(repo="algoquant/IBrokers2") 50 | library(IBrokers2) 51 | 52 | # Enter your account number 53 | ac_count <- "DU1851021" 54 | 55 | 56 | ### Define parameters for a naive market-making strategy 57 | 58 | # Define instrument for trading one ES futures contract 59 | con_tracts <- list(ES=IBrokers2::twsFuture(symbol="ES", exch="GLOBEX", expiry="201909")) 60 | # Define model parameters for market making strategy 61 | trade_params <- list(ES=list(model_function="make_markets", 62 | model_params=c(buy_spread=0.25, sell_spread=0.25, siz_e=1, pos_limit=10, lagg=2, lamb_da=0.05))) 63 | 64 | # Open the files for storing the bar data 65 | data_dir <- "C:/Develop/data/ib_data" 66 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 67 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 68 | 69 | # Open the IB connection to TWS 70 | ib_connect <- IBrokers2::twsConnect(port=7497) 71 | 72 | # Run the trading model (strategy): 73 | IBrokers2::trade_realtime(ib_connect=ib_connect, 74 | Contract=con_tracts, 75 | tickerId=seq_along(con_tracts), 76 | useRTH=FALSE, 77 | back_test=FALSE, 78 | eventWrapper=IBrokers2::trade_wrapper(ac_count=ac_count, 79 | con_tracts=con_tracts, 80 | trade_params=trade_params, 81 | file_connects=file_connects, 82 | warm_up=6), 83 | CALLBACK=IBrokers2::call_back, 84 | file=file_connects) 85 | 86 | # Stop the trading loop by hitting the red STOP button in RStudio 87 | 88 | # Close IB connection 89 | IBrokers2::twsDisconnect(ib_connect) 90 | 91 | # Close data files 92 | for (file_connect in file_connects) close(file_connect) 93 | 94 | 95 | 96 | ### Define parameters for EWMA crossover strategy 97 | 98 | # Define model parameters for EWMA crossover strategy 99 | trade_params <- list(ES=list(model_function="crossover_strat", 100 | model_params=c(is_contrarian=TRUE, siz_e=2, lamb_da=0.2))) 101 | 102 | # Open the files for storing the bar data 103 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 104 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 105 | 106 | # Open the IB connection to TWS 107 | ib_connect <- IBrokers2::twsConnect(port=7497) 108 | 109 | # Run the trading model (strategy): 110 | IBrokers2::trade_realtime(ib_connect=ib_connect, 111 | Contract=con_tracts, 112 | tickerId=seq_along(con_tracts), 113 | useRTH=FALSE, 114 | back_test=FALSE, 115 | eventWrapper=IBrokers2::trade_wrapper(ac_count=ac_count, 116 | con_tracts=con_tracts, 117 | trade_params=trade_params, 118 | file_connects=file_connects, 119 | warm_up=6), 120 | CALLBACK=IBrokers2::call_back, 121 | file=file_connects) 122 | 123 | # Stop the trading loop by hitting the red STOP button in RStudio 124 | 125 | # Close IB connection 126 | IBrokers2::twsDisconnect(ib_connect) 127 | 128 | # Close data files 129 | for (file_connect in file_connects) close(file_connect) 130 | 131 | 132 | 133 | ### Define parameters for a pairs trading strategy 134 | 135 | # Define instruments for trading two stocks: GOOG and AAPL 136 | sym_bols <- c("GOOG", "AAPL") 137 | con_tracts <- lapply(sym_bols, IBrokers2::twsEquity, primary="SMART") 138 | names(con_tracts) <- sym_bols 139 | 140 | # Define model parameters for pairs trading two stocks: GOOG and AAPL 141 | # The traded instrument is GOOG versus AAPL 142 | trade_params <- list(AAPL=NULL, 143 | GOOG=list(model_function="pairs_strat", 144 | model_params=c(is_contrarian=TRUE, siz_e=100, look_back=5, thresh_old=1.0, lamb_da=0.2))) 145 | 146 | # Open the files for storing the bar data 147 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 148 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 149 | 150 | # Open the IB connection to TWS 151 | ib_connect <- IBrokers2::twsConnect(port=7497) 152 | 153 | # Run the trading model (strategy): 154 | IBrokers2::trade_realtime(ib_connect=ib_connect, 155 | Contract=con_tracts, 156 | tickerId=seq_along(con_tracts), 157 | useRTH=FALSE, 158 | back_test=FALSE, 159 | eventWrapper=IBrokers2::trade_wrapper(ac_count=ac_count, 160 | con_tracts=con_tracts, 161 | trade_params=trade_params, 162 | file_connects=file_connects, 163 | warm_up=6), 164 | CALLBACK=IBrokers2::call_back, 165 | file=file_connects) 166 | 167 | # Stop the trading loop by hitting the red STOP button in RStudio 168 | 169 | # Close IB connection 170 | IBrokers2::twsDisconnect(ib_connect) 171 | 172 | # Close data files 173 | for (file_connect in file_connects) close(file_connect) 174 | 175 | 176 | ### Close (trade out of) any unwanted positions using market orders 177 | 178 | # Open the IB connection to TWS 179 | ib_connect <- IBrokers2::twsConnect(port=7497) 180 | 181 | # Execute buy market order (example) 182 | order_id <- IBrokers2::reqIds(ib_connect) 183 | ib_order <- IBrokers2::twsOrder(order_id, orderType="MKT", action="BUY", totalQuantity=10) 184 | IBrokers2::placeOrder(ib_connect, con_tracts[[1]], ib_order) 185 | 186 | # Execute sell market order (example) 187 | order_id <- IBrokers2::reqIds(ib_connect) 188 | ib_order <- IBrokers2::twsOrder(order_id, orderType="MKT", action="SELL", totalQuantity=10) 189 | IBrokers2::placeOrder(ib_connect, con_tracts[[2]], ib_order) 190 | 191 | # Close IB connection 192 | IBrokers2::twsDisconnect(ib_connect) 193 | 194 | -------------------------------------------------------------------------------- /scripts/TWS Kovalevsky.R: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2018 Stanislav Kovalevsky 2 | 3 | Tws = R6::R6Class( 'Tws', lock_objects = F ) 4 | 5 | Tws$set( 'public', 'connect', function( port = 4001 ) { 6 | 7 | if( is.null( self$tws ) || !IBrokers::isConnected( self$tws ) ) { 8 | 9 | self$tws = IBrokers::twsConnect( clientId = 0, port = port ) 10 | 11 | } 12 | 13 | self$last_update_orders = Sys.time() 14 | self$last_update_executions = Sys.time() 15 | 16 | } ) 17 | Tws$set( 'public', 'update_positions', function( ) { 18 | 19 | sink("/dev/null") 20 | 21 | ac = IBrokers::reqAccountUpdates( self$tws ); 22 | 23 | self$ac = ac 24 | self$positions = IBrokers::twsPortfolioValue( ac ) 25 | 26 | sink() 27 | 28 | } ) 29 | Tws$set( 'public', 'get_tws_info', function( outgoing, incoming, end, verbose = F ) { 30 | 31 | con = self$tws[[1]] 32 | # send request 33 | writeBin( c( outgoing, ver = '1' ), con ) 34 | 35 | eWrapper = IBrokers::eWrapper() 36 | socketSelect( list( con ), F, NULL ) 37 | processed_messages = list() 38 | k = 1 39 | # read messages until end message found 40 | while( T ) { 41 | 42 | current_message = readBin( con, character(), 1 ) 43 | 44 | if( length( current_message ) != 0 ) { 45 | 46 | sink("/dev/null"); processed_message = IBrokers::processMsg( current_message, con, eWrapper ); sink(); 47 | 48 | if ( current_message == incoming ) { processed_messages[[ k ]] = processed_message; k = k + 1; } else { if( current_message == end ) break } 49 | 50 | } 51 | 52 | } 53 | 54 | return( processed_messages ) 55 | 56 | } ) 57 | 58 | Tws$set( 'public', 'update_executions', function() { 59 | 60 | if( Sys.time() - self$last_update_executions < as.difftime( 0.1, units = 'secs' ) ) return() 61 | 62 | # NOTE 63 | # use last execution message if multiple executions present for single order: 64 | # orderId clientId execId time acctNumber exchange side shares price permId liquidation cumQty avgPrice 65 | # 1: 88670 1 0001f4e8.5a1768f8.01.01 20171124 10:44:41 DU758675 IDEALPRO sell 30000 1.18380 1955945889 0 30000 1.183800 66 | # 2: 88670 1 0001f4e8.5a1768f9.01.01 20171124 10:44:41 DU758675 IDEALPRO sell 75582 1.18379 1955945889 0 105582 1.183793 67 | # ! second execution contains cumulative quantity and average price 68 | 69 | self$executions = self$get_tws_info( 70 | 71 | outgoing = IBrokers::.twsOutgoingMSG$'REQ_EXECUTIONS', 72 | incoming = IBrokers::.twsIncomingMSG$'EXECUTION_DATA', 73 | end = IBrokers::.twsIncomingMSG$'EXECUTION_DATA_END' 74 | 75 | ) 76 | 77 | if( length( self$executions ) > 0 ) { 78 | 79 | self$executions = lapply( self$executions, function( x ) { 80 | 81 | x = x$execution 82 | class( x ) = NULL 83 | as.data.table( t( x ) ) 84 | 85 | } ) 86 | 87 | self$executions = rbindlist( self$executions ) 88 | self$executions = setDT( lapply( self$executions, unlist ) ) 89 | self$executions = self$executions[, ':='( 90 | 91 | side = ifelse( side == 'BOT', 'buy', 'sell' ), 92 | cumQty = as.numeric( cumQty ), 93 | avgPrice = as.numeric( avgPrice ) 94 | 95 | ) ][] 96 | 97 | } else { 98 | 99 | self$executions = NULL 100 | 101 | } 102 | 103 | self$last_update_executions = Sys.time() 104 | 105 | } ) 106 | 107 | Tws$set( 'public', 'update_orders', function() { 108 | 109 | if( Sys.time() - self$last_update_orders < as.difftime( 0.1, units = 'secs' ) ) return() 110 | 111 | self$orders = self$get_tws_info( 112 | 113 | outgoing = IBrokers::.twsOutgoingMSG$'REQ_OPEN_ORDERS', 114 | incoming = IBrokers::.twsIncomingMSG$'OPEN_ORDER', 115 | end = IBrokers::.twsIncomingMSG$'OPEN_ORDER_END' 116 | 117 | ) 118 | 119 | if( length( self$orders ) > 0 ) { 120 | 121 | self$orders = data.table( do.call( rbind, self$orders ) )[, .( 122 | 123 | orderId = V3, 124 | clientId = V8, 125 | execId = NA, 126 | time = V7, 127 | acctNumber = V20, 128 | exchange = V10, 129 | side = V13, 130 | shares = V14, 131 | price = V16, 132 | permId = V25, 133 | liquidation = NA, 134 | cumQty = NA, 135 | avgPrice = NA, 136 | status = V77 137 | 138 | ) ][, -'status' ][] 139 | 140 | } else { 141 | 142 | self$orders = NULL 143 | 144 | } 145 | 146 | self$last_update_orders = Sys.time() 147 | 148 | } ) 149 | Tws$set( 'public', 'send_order', function( symbol, type, price, side, size ) { 150 | 151 | security = switch( 152 | symbol, 153 | 154 | 155 | CL = IBrokers::twsFUT( symbol, 'NYMEX', expiry = '20180122', multiplier = '1000', conId = '117170262' ), 156 | 157 | stop( paste( symbol, 'security not supported' ) ) 158 | ) 159 | side = ifelse( side == 'buy', 'BUY', 'SELL' ) 160 | size = as.character( size ) 161 | price = as.character( price ) 162 | 163 | self$order_id = as.numeric( IBrokers::reqIds( self$tws ) ) 164 | 165 | order = switch( 166 | type, 167 | 168 | MKT = IBrokers::twsOrder( self$order_id, orderType = 'MKT', action = side, totalQuantity = size, transmit = T ), 169 | LMT = IBrokers::twsOrder( self$order_id, orderType = 'LMT', lmtPrice = price, action = side, totalQuantity = size, transmit = T ), 170 | STP = IBrokers::twsOrder( self$order_id, orderType = 'STP', auxPrice = price, action = side, totalQuantity = size, transmit = T, outsideRTH = '1' ), 171 | 172 | stop( paste( type, 'type not supported' ) ) 173 | ) 174 | 175 | IBrokers::placeOrder( self$tws, security, order ) 176 | return( self$order_id ) 177 | 178 | } ) 179 | Tws$set( 'public', 'get_order', function( id_order ) { 180 | 181 | self$update_executions() 182 | execution = if( !is.null( self$executions ) ) self$executions[ orderId == id_order ][ .N ] # .N? see update_executions note 183 | 184 | Sys.sleep( 0.1 ) 185 | 186 | self$update_orders() 187 | order = if( !is.null( self$orders ) ) self$orders[ orderId == id_order ] 188 | 189 | rbind( execution, order ) 190 | 191 | } ) 192 | Tws$set( 'public', 'cancel_order', function( id_order ) { 193 | 194 | IBrokers::cancelOrder( self$tws, id_order ) 195 | 196 | } ) 197 | Tws$set( 'public', 'disconnect', function() { 198 | 199 | IBrokers::twsDisconnect( self$tws ) 200 | 201 | } ) 202 | -------------------------------------------------------------------------------- /scripts/app_ibtrading.R: -------------------------------------------------------------------------------- 1 | ############################## 2 | # This is a shiny app for simulating a rolling portfolio 3 | # optimization strategy with filtering of returns. 4 | # It uses HighFreq::back_test() 5 | # 6 | # Just press the "Run App" button on upper right of this panel. 7 | ############################## 8 | 9 | ## Below is the setup code that runs once when the shiny app is started 10 | 11 | # load packages 12 | library(IBrokers2) 13 | # Model and data setup 14 | # source the model function 15 | # source("C:/Develop/R/lecture_slides/scripts/roll_portf_new.R") 16 | # max_eigen <- 2 17 | 18 | # Load the trading function written as an eWrapper: 19 | source("C:/Develop/R/IBrokers2/R/trade_wrapper.R") 20 | 21 | 22 | # Define the contract for trading 23 | con_tract <- IBrokers2::twsFuture(symbol="ES", exch="GLOBEX", expiry="201812") 24 | 25 | # Open the file for storing the bar data 26 | data_dir <- "C:/Develop/data/ib_data" 27 | file_name <- file.path(data_dir, paste0("ES_ohlc_live_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 28 | file_connect <- file(file_name, open="w") 29 | 30 | # Open the IB connection 31 | ib_connect <- IBrokers2::twsConnect(port=7497) 32 | 33 | 34 | 35 | # End setup code 36 | 37 | 38 | ## Create elements of the user interface 39 | inter_face <- shiny::fluidPage( 40 | titlePanel("Trading via IBrokers2"), 41 | 42 | # create single row with two slider inputs 43 | fluidRow( 44 | column(width=3, sliderInput("buy_spread", label="buy spread:", 45 | min=0.0, max=2.0, value=0.25, step=0.25)), 46 | column(width=3, sliderInput("sell_spread", label="sell spread:", 47 | min=0.0, max=2.0, value=0.25, step=0.25)) 48 | ) # end fluidRow 49 | ) # end fluidPage interface 50 | 51 | 52 | ## Define the server code 53 | ser_ver <- function(input, output) { 54 | 55 | # re-calculate the data and rerun the model 56 | da_ta <- reactive({ 57 | # get model parameters from input argument 58 | buy_spread <- input$buy_spread 59 | sell_spread <- input$sell_spread 60 | 61 | # Run the trading model (strategy): 62 | IBrokers2::reqRealTimeBars(conn=ib_connect, useRTH=FALSE, 63 | Contract=con_tract, barSize="10", 64 | eventWrapper=trade_wrapper(n_instr=1, 65 | buy_spread=buy_spread, sell_spread=sell_spread), 66 | CALLBACK=twsCALLBACK, 67 | file=file_connect) 68 | 1 69 | }) # end reactive code 70 | 71 | 72 | } # end server code 73 | 74 | ## Return a Shiny app object 75 | shiny::shinyApp(ui=inter_face, server=ser_ver) 76 | -------------------------------------------------------------------------------- /scripts/ibrokers_callback.R: -------------------------------------------------------------------------------- 1 | IBrokers::twsCALLBACK <- function (twsCon, eWrapper, timestamp, file, playback = 1, ...) 2 | { 3 | if (missing(eWrapper)) 4 | eWrapper <- eWrapper() 5 | con <- twsCon[[1]] 6 | if (inherits(twsCon, "twsPlayback")) { 7 | sys.time <- NULL 8 | while (TRUE) { 9 | if (!is.null(timestamp)) { 10 | last.time <- sys.time 11 | sys.time <- as.POSIXct(strptime(paste(readBin(con, 12 | character(), 2), collapse = " "), timestamp)) 13 | if (!is.null(last.time)) { 14 | Sys.sleep((sys.time - last.time) * playback) 15 | } 16 | curMsg <- readBin(con, character(), 1) 17 | if (length(curMsg) < 1) 18 | next 19 | processMsg(curMsg, con, eWrapper, format(sys.time, timestamp), file, ...) 20 | } 21 | else { 22 | curMsg <- readBin(con, character(), 1) 23 | if (length(curMsg) < 1) 24 | next 25 | processMsg(curMsg, con, eWrapper, timestamp, file, ...) 26 | if (curMsg == .twsIncomingMSG$REAL_TIME_BARS) 27 | Sys.sleep(5 * playback) 28 | } 29 | } 30 | } 31 | else { 32 | tryCatch(while (isConnected(twsCon)) { 33 | if (!socketSelect(list(con), FALSE, 0.25)) 34 | next 35 | curMsg <- readBin(con, "character", 1L) 36 | if (!is.null(timestamp)) { 37 | processMsg(curMsg, con, eWrapper, format(Sys.time(), timestamp), file, twsCon, ...) 38 | } 39 | else { 40 | processMsg(curMsg, con, eWrapper, timestamp, file, twsCon, ...) 41 | } 42 | }, error = function(e) { 43 | close(twsCon) 44 | stop("IB connection error. Connection closed", call. = FALSE) 45 | }) 46 | } 47 | } # end twsCALLBACK 48 | -------------------------------------------------------------------------------- /scripts/ibrokers_processMsg.R: -------------------------------------------------------------------------------- 1 | processMsg <- function (curMsg, con, eWrapper, timestamp, file, twsconn, ...) { 2 | if (curMsg == .twsIncomingMSG$TICK_PRICE) { 3 | msg <- readBin(con, "character", 6) 4 | eWrapper$tickPrice(curMsg, msg, timestamp, file, ...) 5 | } 6 | else if (curMsg == .twsIncomingMSG$TICK_SIZE) { 7 | msg <- readBin(con, "character", 4) 8 | eWrapper$tickSize(curMsg, msg, timestamp, file, ...) 9 | } 10 | else if (curMsg == .twsIncomingMSG$ORDER_STATUS) { 11 | msg <- readBin(con, "character", 11) 12 | eWrapper$orderStatus(curMsg, msg, timestamp, file, ...) 13 | } 14 | else if (curMsg == .twsIncomingMSG$ERR_MSG) { 15 | msg <- readBin(con, "character", 4) 16 | eWrapper$errorMessage(curMsg, msg, timestamp, file, twsconn, ...) 17 | } 18 | else if (curMsg == .twsIncomingMSG$OPEN_ORDER) { 19 | msg <- readBin(con, "character", 84) 20 | # modified according to: 21 | # https://stackoverflow.com/questions/34703679/r-ibrokers-reqopenorders-hangs 22 | x <- eWrapper$openOrder(curMsg, msg, timestamp, file, ...) 23 | return(x) 24 | } 25 | else if (curMsg == .twsIncomingMSG$ACCT_VALUE) { 26 | msg <- readBin(con, "character", 5) 27 | eWrapper$updateAccountValue(curMsg, msg, timestamp, file, ...) 28 | } 29 | else if (curMsg == .twsIncomingMSG$PORTFOLIO_VALUE) { 30 | msg <- readBin(con, "character", 18) 31 | eWrapper$updatePortfolio(curMsg, msg, timestamp, file, 32 | ...) 33 | } 34 | else if (curMsg == .twsIncomingMSG$ACCT_UPDATE_TIME) { 35 | msg <- readBin(con, "character", 2) 36 | eWrapper$updateAccountTime(curMsg, msg, timestamp, file, ...) 37 | } 38 | else if (curMsg == .twsIncomingMSG$NEXT_VALID_ID) { 39 | msg <- readBin(con, "character", 2) 40 | eWrapper$nextValidId(curMsg, msg, timestamp, file, ...) 41 | } 42 | else if (curMsg == .twsIncomingMSG$CONTRACT_DATA) { 43 | msg <- readBin(con, "character", 28) 44 | eWrapper$contractDetails(curMsg, msg, timestamp, file, ...) 45 | } 46 | else if (curMsg == .twsIncomingMSG$EXECUTION_DATA) { 47 | msg <- readBin(con, "character", 24) 48 | eWrapper$execDetails(curMsg, msg, timestamp, file, ...) 49 | } 50 | else if (curMsg == .twsIncomingMSG$MARKET_DEPTH) { 51 | msg <- readBin(con, "character", 7) 52 | eWrapper$updateMktDepth(curMsg, msg, timestamp, file, ...) 53 | } 54 | else if (curMsg == .twsIncomingMSG$MARKET_DEPTH_L2) { 55 | msg <- readBin(con, "character", 8) 56 | eWrapper$updateMktDepthL2(curMsg, msg, timestamp, file, ...) 57 | } 58 | else if (curMsg == .twsIncomingMSG$NEWS_BULLETINS) { 59 | msg <- readBin(con, "character", 5) 60 | eWrapper$newsBulletins(curMsg, msg, timestamp, file, ...) 61 | } 62 | else if (curMsg == .twsIncomingMSG$MANAGED_ACCTS) { 63 | msg <- readBin(con, "character", 2) 64 | eWrapper$managedAccounts(curMsg, msg, timestamp, file, ...) 65 | } 66 | else if (curMsg == .twsIncomingMSG$RECEIVE_FA) { 67 | msg <- readBin(con, "character", 2) 68 | stop("xml data currently unsupported") 69 | eWrapper$receiveFA(curMsg, msg, timestamp, file, ...) 70 | } 71 | else if (curMsg == .twsIncomingMSG$HISTORICAL_DATA) { 72 | header <- readBin(con, character(), 5) 73 | nbin <- as.numeric(header[5]) * 9 74 | msg <- readBin(con, character(), nbin) 75 | eWrapper$historicalData(curMsg, msg, timestamp, file, 76 | ...) 77 | } 78 | else if (curMsg == .twsIncomingMSG$BOND_CONTRACT_DATA) { 79 | warning("BOND_CONTRACT_DATA unimplemented as of yet") 80 | eWrapper$bondContractDetails(curMsg, msg, timestamp, file, ...) 81 | } 82 | else if (curMsg == .twsIncomingMSG$SCANNER_PARAMETERS) { 83 | version <- readBin(con, character(), 1L) 84 | msg <- readBin(con, raw(), 1000000L) 85 | eWrapper$scannerParameters(curMsg, msg, timestamp, file, ...) 86 | } 87 | else if (curMsg == .twsIncomingMSG$SCANNER_DATA) { 88 | cD <- twsContractDetails() 89 | version <- readBin(con, character(), 1L) 90 | tickerId <- readBin(con, character(), 1L) 91 | numberOfElements <- as.integer(readBin(con, character(), 92 | 1L)) 93 | for (i in 1:numberOfElements) { 94 | msg <- readBin(con, character(), 16L) 95 | rank <- msg[1] 96 | cD$contract$conId <- msg[2] 97 | cD$contract$symbol <- msg[3] 98 | cD$contract$sectype <- msg[4] 99 | cD$contract$expiry <- msg[5] 100 | cD$contract$strike <- msg[6] 101 | cD$contract$right <- msg[7] 102 | cD$contract$exch <- msg[8] 103 | cD$contract$currency <- msg[9] 104 | cD$contract$local <- msg[10] 105 | cD$marketName <- msg[11] 106 | cD$tradingClass <- msg[12] 107 | distance <- msg[13] 108 | benchmark <- msg[14] 109 | projection <- msg[15] 110 | legsStr <- msg[16] 111 | eWrapper$scannerData(curMsg, tickerId, rank, cD, 112 | distance, benchmark, projection, legsStr) 113 | } 114 | } 115 | else if (curMsg == .twsIncomingMSG$TICK_OPTION_COMPUTATION) { 116 | msg <- readBin(con, "character", 11) 117 | eWrapper$tickOptionComputation(curMsg, msg, timestamp, file, ...) 118 | } 119 | else if (curMsg == .twsIncomingMSG$TICK_GENERIC) { 120 | msg <- readBin(con, "character", 4) 121 | eWrapper$tickGeneric(curMsg, msg, timestamp, file, ...) 122 | } 123 | else if (curMsg == .twsIncomingMSG$TICK_STRING) { 124 | msg <- readBin(con, "character", 4) 125 | eWrapper$tickString(curMsg, msg, timestamp, file, ...) 126 | } 127 | else if (curMsg == .twsIncomingMSG$TICK_EFP) { 128 | msg <- readBin(con, "character", 10) 129 | eWrapper$tickEFP(curMsg, msg, timestamp, file, ...) 130 | } 131 | else if (curMsg == .twsIncomingMSG$CURRENT_TIME) { 132 | msg <- readBin(con, "character", 2) 133 | eWrapper$currentTime(curMsg, msg, timestamp, file, ...) 134 | } 135 | else if (curMsg == .twsIncomingMSG$REAL_TIME_BARS) { 136 | msg <- readBin(con, "character", 10) 137 | eWrapper$realtimeBars(curMsg, msg, timestamp, file, ...) 138 | } 139 | else if (curMsg == .twsIncomingMSG$FUNDAMENTAL_DATA) { 140 | msg <- readBin(con, "character", 3) 141 | eWrapper$fundamentalData(curMsg, msg, timestamp, file, ...) 142 | } 143 | else if (curMsg == .twsIncomingMSG$CONTRACT_DATA_END) { 144 | msg <- readBin(con, "character", 2) 145 | eWrapper$contractDetailsEnd(curMsg, msg, timestamp, file, ...) 146 | } 147 | else if (curMsg == .twsIncomingMSG$OPEN_ORDER_END) { 148 | msg <- readBin(con, "character", 1) 149 | eWrapper$openOrderEnd(curMsg, msg, timestamp, file, ...) 150 | } 151 | else if (curMsg == .twsIncomingMSG$ACCT_DOWNLOAD_END) { 152 | msg <- readBin(con, "character", 2) 153 | eWrapper$accountDownloadEnd(curMsg, msg, timestamp, file, ...) 154 | } 155 | else if (curMsg == .twsIncomingMSG$EXECUTION_DATA_END) { 156 | msg <- readBin(con, "character", 2) 157 | eWrapper$execDetailsEnd(curMsg, msg, timestamp, file, ...) 158 | } 159 | else if (curMsg == .twsIncomingMSG$DELTA_NEUTRAL_VALIDATION) { 160 | msg <- readBin(con, "character", 5) 161 | eWrapper$deltaNeutralValidation(curMsg, msg, timestamp, file, ...) 162 | } 163 | else if (curMsg == .twsIncomingMSG$TICK_SNAPSHOT_END) { 164 | msg <- readBin(con, "character", 2) 165 | eWrapper$tickSnapshotEnd(curMsg, msg, timestamp, file, ...) 166 | } 167 | else { 168 | warning(paste("Unknown incoming message: ", curMsg, ". Please reset connection", 169 | sep = ""), call. = FALSE) 170 | } 171 | } # end processMsg 172 | -------------------------------------------------------------------------------- /scripts/ibrokers_reqRealTimeBars.R: -------------------------------------------------------------------------------- 1 | IBrokers::reqRealTimeBars <- function (conn, Contract, whatToShow = "TRADES", barSize = "5", 2 | useRTH = TRUE, playback = 1, tickerId = "1", file = "", verbose = TRUE, 3 | eventWrapper = eWrapper(), CALLBACK = twsCALLBACK, ...) 4 | { 5 | if (!is.twsPlayback(conn)) { 6 | tickerId <- .reqRealTimeBars(conn, Contract, whatToShow, 7 | barSize, useRTH, tickerId) 8 | } 9 | if (is.twsContract(Contract)) 10 | Contract <- list(Contract) 11 | con <- conn[[1]] 12 | cancelRealTimeBars <- function(con, tickerId) { 13 | if (inherits(con, "sockconn")) { 14 | for (i in 1:length(tickerId)) { 15 | writeBin(.twsOutgoingMSG$CANCEL_REAL_TIME_BARS, 16 | con) 17 | writeBin("1", con) 18 | writeBin(tickerId[i], con) 19 | } 20 | } 21 | else { 22 | seek(con, 0) 23 | } 24 | } 25 | if (is.null(CALLBACK)) 26 | CALLBACK <- twsDEBUG 27 | if (!missing(CALLBACK) && is.na(list(CALLBACK))) { 28 | if (is.twsPlayback(conn)) { 29 | seek(conn[[1]], 0) 30 | stop("CALLBACK=NA is not available for playback") 31 | } 32 | return(tickerId) 33 | } 34 | on.exit(cancelRealTimeBars(con, tickerId)) 35 | symbol.or.local <- function(x) { 36 | symbol <- x$symbol 37 | local <- x$local 38 | if (local == "") { 39 | return(symbol) 40 | } 41 | else return(local) 42 | } 43 | eventWrapper$assign.Data("symbols", sapply(Contract, symbol.or.local)) 44 | timeStamp <- NULL 45 | if (!is.list(file)) 46 | file <- list(file) 47 | if (length(file) != length(Contract)) 48 | file <- rep(file, length(Contract)) 49 | CALLBACK(conn, eWrapper = eventWrapper, timestamp = timeStamp, 50 | file = file, playback = playback, ...) 51 | } # end reqRealTimeBars 52 | -------------------------------------------------------------------------------- /scripts/temp.R: -------------------------------------------------------------------------------- 1 | library(IBrokers2) 2 | 3 | con_tracts <- list(es=IBrokers2::twsFuture(symbol="ES", exch="GLOBEX", expiry="201812")) 4 | limit_prices <- list(ES=c(buy_spread=1.75, sell_spread=1.75)) 5 | 6 | # Create eWrapper environment 7 | e_wrapper <- IBrokers2::eWrapper() 8 | 9 | 10 | data_dir <- "C:/Develop/data/ib_data" 11 | file_names <- file.path(data_dir, paste0(names(con_tracts), "_", format(Sys.time(), format="%m_%d_%Y_%H_%M"), ".csv")) 12 | file_connects <- lapply(file_names, function(file_name) file(file_name, open="w")) 13 | 14 | # connect 15 | ib_connect <- IBrokers2::twsConnect(port=7497) 16 | 17 | 18 | # subscribe 19 | ticker_id <- IBrokers2::.reqOpenOrders(ib_connect) 20 | ticker_id <- IBrokers2::.reqRealTimeBars(conn=ib_connect, Contract=con_tracts, useRTH=FALSE) 21 | 22 | sock_et <- ib_connect[[1]] 23 | 24 | # Read the message 25 | da_ta <- readBin(sock_et, "character", 1L) 26 | # Process the message 27 | foo <- processMsg(curMsg=da_ta, con=sock_et, eWrapper=e_wrapper, timestamp=NULL, file=file_connects, twsconn=ib_connect) 28 | 29 | 30 | 31 | 32 | tryCatch( 33 | # Callback loop 34 | while(isConnected(ib_connect)) { 35 | if (!socketSelect(list(ib_connect), FALSE, 0.25)) next 36 | # Read the message 37 | da_ta <- readBin(ib_connect, "character", 1L) 38 | # Process the message 39 | processMsg(curMsg=da_ta, twsconn=ib_connect, eWrapper=e_wrapper, timestamp=NULL, file=file_connects, con=ib_connect) 40 | }, # end while 41 | # error handler 42 | error=function(e) { close(ib_connect); stop("IB connection error. Connection closed", call.=FALSE) } 43 | ) # end tryCatch 44 | 45 | 46 | # Close IB connection 47 | IBrokers2::twsDisconnect(ib_connect) 48 | 49 | -------------------------------------------------------------------------------- /scripts/twsIncoming.txt: -------------------------------------------------------------------------------- 1 | .twsIncomingMSG codes 2 | 3 | $TICK_PRICE 4 | [1] "1" 5 | 6 | $TICK_SIZE 7 | [1] "2" 8 | 9 | $ORDER_STATUS 10 | [1] "3" 11 | 12 | $ERR_MSG 13 | [1] "4" 14 | 15 | $OPEN_ORDER 16 | [1] "5" 17 | 18 | $ACCT_VALUE 19 | [1] "6" 20 | 21 | $PORTFOLIO_VALUE 22 | [1] "7" 23 | 24 | $ACCT_UPDATE_TIME 25 | [1] "8" 26 | 27 | $NEXT_VALID_ID 28 | [1] "9" 29 | 30 | $CONTRACT_DATA 31 | [1] "10" 32 | 33 | $EXECUTION_DATA 34 | [1] "11" 35 | 36 | $MARKET_DEPTH 37 | [1] "12" 38 | 39 | $MARKET_DEPTH_L2 40 | [1] "13" 41 | 42 | $NEWS_BULLETINS 43 | [1] "14" 44 | 45 | $MANAGED_ACCTS 46 | [1] "15" 47 | 48 | $RECEIVE_FA 49 | [1] "16" 50 | 51 | $HISTORICAL_DATA 52 | [1] "17" 53 | 54 | $BOND_CONTRACT_DATA 55 | [1] "18" 56 | 57 | $SCANNER_PARAMETERS 58 | [1] "19" 59 | 60 | $SCANNER_DATA 61 | [1] "20" 62 | 63 | $TICK_OPTION_COMPUTATION 64 | [1] "21" 65 | 66 | $TICK_GENERIC 67 | [1] "45" 68 | 69 | $TICK_STRING 70 | [1] "46" 71 | 72 | $TICK_EFP 73 | [1] "47" 74 | 75 | $CURRENT_TIME 76 | [1] "49" 77 | 78 | $REAL_TIME_BARS 79 | [1] "50" 80 | 81 | $FUNDAMENTAL_DATA 82 | [1] "51" 83 | 84 | $CONTRACT_DATA_END 85 | [1] "52" 86 | 87 | $OPEN_ORDER_END 88 | [1] "53" 89 | 90 | $ACCT_DOWNLOAD_END 91 | [1] "54" 92 | 93 | $EXECUTION_DATA_END 94 | [1] "55" 95 | 96 | $DELTA_NEUTRAL_VALIDATION 97 | [1] "56" 98 | 99 | $TICK_SNAPSHOT_END 100 | [1] "57" 101 | 102 | -------------------------------------------------------------------------------- /vignettes/IBrokers.R: -------------------------------------------------------------------------------- 1 | ### R code from vignette source 'IBrokers.Rnw' 2 | 3 | ################################################### 4 | ### code chunk number 1: twsconnect (eval = FALSE) 5 | ################################################### 6 | ## library(IBrokers) 7 | ## tws <- twsConnect() 8 | ## tws 9 | ## reqCurrentTime(tws) 10 | ## serverVersion(tws) 11 | ## twsDisconnect(tws) 12 | 13 | 14 | ################################################### 15 | ### code chunk number 2: twsconnect 16 | ################################################### 17 | if(Sys.getenv("IBCON")=="1") { 18 | library(IBrokers) 19 | tws <- twsConnect(999, port=Sys.getenv("IBPORT")) 20 | tws 21 | reqCurrentTime(tws) 22 | serverVersion(tws) 23 | twsDisconnect(tws) 24 | } 25 | 26 | 27 | ################################################### 28 | ### code chunk number 3: reqmktdata (eval = FALSE) 29 | ################################################### 30 | ## tws <- twsConnect() 31 | ## twsFuture("YM","ECBOT","200809") 32 | ## reqContractDetails(tws, twsEquity("QQQQ")) 33 | 34 | 35 | ################################################### 36 | ### code chunk number 4: reqmktdata 37 | ################################################### 38 | if(Sys.getenv("IBCON")=="1") { 39 | tws <- twsConnect(999, port=Sys.getenv("IBPORT")) 40 | twsFuture("YM","ECBOT","200809") 41 | reqContractDetails(tws, twsEquity("QQQQ")) 42 | } 43 | 44 | 45 | ################################################### 46 | ### code chunk number 5: reqmktdata2 (eval = FALSE) 47 | ################################################### 48 | ## reqMktData(tws, twsEquity("QQQQ")) 49 | 50 | 51 | ################################################### 52 | ### code chunk number 6: reqmktdata3 53 | ################################################### 54 | if(Sys.getenv("IBCON")=="1") { 55 | IBrokers:::.reqMktData.vignette(tws, twsEquity("QQQQ")) 56 | twsDisconnect(tws) 57 | } 58 | 59 | 60 | ################################################### 61 | ### code chunk number 7: playbackmktdata (eval = FALSE) 62 | ################################################### 63 | ## reqMktData(tws, twsEquity("SBUX"), CALLBACK=NULL, file="SBUX.dat") 64 | ## twsp <- twsConnect(filename="SBUX.dat") 65 | 66 | 67 | ################################################### 68 | ### code chunk number 8: playbackmktdata 69 | ################################################### 70 | if(Sys.getenv("IBCON")=="1") { 71 | tws <- twsConnect(999, port=Sys.getenv("IBPORT")) 72 | IBrokers:::.reqMktData.vignette(tws, twsEquity("SBUX"), CALLBACK=NULL, file="SBUX.dat") 73 | twsDisconnect(tws) 74 | twsp <- twsConnect(filename="SBUX.dat") 75 | } 76 | 77 | 78 | ################################################### 79 | ### code chunk number 9: playback (eval = FALSE) 80 | ################################################### 81 | ## reqMktData(twsp) 82 | ## reqMktData(twsp, playback=0) 83 | 84 | 85 | ################################################### 86 | ### code chunk number 10: playback 87 | ################################################### 88 | if(Sys.getenv("IBCON")=="1") { 89 | reqMktData(twsp) 90 | reqMktData(twsp, playback=0) 91 | } 92 | 93 | 94 | ################################################### 95 | ### code chunk number 11: closeplayback 96 | ################################################### 97 | if(Sys.getenv("IBCON")=="1") { 98 | twsDisconnect(twsp) 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /vignettes/IBrokers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/IBrokers.pdf -------------------------------------------------------------------------------- /vignettes/IBrokersREFCARD.R: -------------------------------------------------------------------------------- 1 | ### R code from vignette source 'IBrokersREFCARD.Rnw' 2 | 3 | ################################################### 4 | ### code chunk number 1: setup 5 | ################################################### 6 | options(continue=" ") 7 | 8 | 9 | ################################################### 10 | ### code chunk number 2: orders (eval = FALSE) 11 | ################################################### 12 | ## placeOrder(twsconn=tws, 13 | ## Contract=twsSTK("AAPL"), 14 | ## Order=twsOrder(reqIds(tws), 15 | ## "BUY", 16 | ## 10, 17 | ## "MKT")) 18 | 19 | 20 | -------------------------------------------------------------------------------- /vignettes/IBrokersREFCARD.Rnw: -------------------------------------------------------------------------------- 1 | %\VignetteIndexEntry{IBrokersRef} 2 | \documentclass{article} 3 | 4 | % IBrokers Reference Card version 0.2-7 5 | % Copyright 2010 Jeffrey A. Ryan 6 | % Extending the excellent vi-ref card design to the R package 7 | % IBrokers 8 | % 9 | % %%%%%%% original GPL and copyright %%%%%%% 10 | % Copyright 2002-2005 Donald Bindner 11 | % This program is free software; you can redistribute it and/or 12 | % modify it under the terms of the GNU General Public License 13 | % as published by the Free Software Foundation; either version 2 14 | % of the License, or (at your option) any later version. 15 | % 16 | % This program is distributed in the hope that it will be useful, 17 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | % GNU General Public License for more details. 20 | % 21 | % You should have received a copy of the GNU General Public License 22 | % along with this program; if not, write to the Free Software 23 | % Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 24 | 25 | \usepackage{multicol} 26 | \usepackage{color} 27 | %\definecolor{eWrapper}{rgb}{0.3,0.3,0.3} 28 | %\definecolor{eWrapper}{rgb}{0.882,0.329,0.09} 29 | \definecolor{eWrapper}{rgb}{1,0.49,0.13} 30 | \definecolor{func}{rgb}{0,0,0.6} 31 | 32 | \setlength{\textheight}{7.5 in} 33 | \setlength{\textwidth}{10 in} 34 | \setlength{\hoffset}{-2 in} 35 | \setlength{\voffset}{-1 in} 36 | \setlength{\footskip}{12 pt} 37 | \setlength{\oddsidemargin}{1.5 in} 38 | \setlength{\evensidemargin}{1.5 in} 39 | \setlength{\topmargin}{.5 in} 40 | \setlength{\headheight}{12 pt} 41 | \setlength{\headsep}{0 in} 42 | 43 | \setlength{\parindent}{0 in} 44 | 45 | \ifx \pdfpagewidth \undefined 46 | \else 47 | \pdfpagewidth=11in % page width of PDF output 48 | \pdfpageheight=8.5in % page height of PDF output 49 | \fi 50 | 51 | \begin{document} 52 | \thispagestyle{empty} 53 | \fontsize{9}{10}\selectfont 54 | 55 | \newcommand{\key}[2]{#1 \hfill \texttt{\color{func} #2}\par} 56 | \newcommand{\head}[1]{{\normalsize\textbf{#1}}\\} 57 | \newcommand{\ewrappers}[1]{eWrapper methods:\par {\textsl{\color{eWrapper} #1}}\\} 58 | \newcommand{\Rclass}[1]{\mbox{\textit{#1}}} 59 | \newcommand{\Rfunc}[1]{\mbox{\texttt{#1}}} 60 | 61 | \begin{multicols}{3} 62 | <>= 63 | options(continue=" ") 64 | @ 65 | {\Large IBrokers Reference Card}\\ 66 | {\small IBrokers 0.9-0; TWS API 9.64} 67 | 68 | \vskip 15pt 69 | 70 | \vbox{\head{IBrokers R API Overview} 71 | The IBrokers API parallels the official Java API 72 | provided by Interactive Brokers, LLC to access 73 | data and execution services provided to IB 74 | clients. Commands can be run interactively 75 | or automated.\par 76 | \vskip 8pt 77 | The official API documentation is grouped 78 | by \mbox{\textsl{EClientSocket}} methods, \mbox{\textsl{EWrapper}} 79 | methods, and \mbox{\textsl{SocketClient}} objects. This document 80 | combines all related objects and methods into groups 81 | by functionality. 82 | \vskip 8pt 83 | Where appropriate, \textsl{eWrapper} methods for processing 84 | incoming messages from related calls are listed. 85 | } 86 | 87 | \vskip 10pt 88 | \vbox{\head{Connection and Server} 89 | Connecting to either the TWS or IB Gateway requires 90 | setting connection parameters external to IBrokers. Once 91 | enabled, the following commands can be used for connections 92 | and details. 93 | \vskip 5pt 94 | \key{connect}{twsConnect, ibgConnect} 95 | \key{disconnect}{twsDisconnect, close} 96 | \key{check connection}{is.twsConnection, isConnected} 97 | \key{set logging level}{setServerLogLevel} 98 | \key{check server version}{serverVersion} 99 | \key{request current time}{reqCurrentTime} 100 | \key{request connection time}{twsConnectionTime} 101 | } 102 | 103 | \vskip 10pt 104 | 105 | \vbox{\head{Contracts} 106 | All requests require validly constructed \Rclass{twsContract} 107 | objects. The basic function to create a valid object is 108 | \Rfunc{twsContract}, though IBrokers implements wrapper 109 | functions to simplify commonly requested types such as 110 | equity, cash, and futures. Depending on the context 111 | the constructors may need more or less detail. 112 | \vskip 5pt 113 | \key{create any contract}{twsContract} 114 | \key{create equity contract}{twsEquity, twsSTK} 115 | \key{create equity option contract}{twsOption, twsOPT} 116 | \key{create future contract}{twsFuture, twsFUT} 117 | \key{create future option contract}{twsFutureOpt, twsFOP} 118 | \key{create currency contract}{twsCurrency, twsCASH} 119 | \key{create combo}{twsBAG, twsComboLeg} 120 | \key{create contract for difference}{twsCFD} 121 | } 122 | 123 | \vskip 10pt 124 | 125 | \vbox{\head{Contract Details} 126 | Given a full or partial \Rclass{twsContract}, 127 | returns a list of \Rclass{twsContractDetails} objects; 128 | named lists containing contract details including a 129 | \texttt{contract} element of class \Rclass{twsContract}. Many 130 | IBrokers calls will accept \texttt{Contract} arguments of 131 | \Rclass{twsContract} or \Rclass{twsContractDetails}.\par 132 | \vskip 5pt 133 | \key{request contract(s) description}{reqContractDetails} 134 | \key{extract \Rclass{twsContract} from details}{as.twsContract} 135 | \vskip 5pt 136 | \ewrappers{contractDetails, bondContractDetails, contractDetailsEnd} 137 | } 138 | 139 | \vskip 10pt 140 | 141 | \vbox{\head{Market Data} 142 | Market Data provides for nearly real-time data 143 | from Interactive Brokers. Data is actually aggregated 144 | into one-third second `snapshot' data from the 145 | exchange, and subsequently passed along to the client.\par 146 | \vskip 5pt 147 | \key{request market data and process}{reqMktData} 148 | \key{request market data (only)}{.reqMktData} 149 | \key{cancel market data}{cancelMktData} 150 | \vskip 5pt 151 | \ewrappers{tickPrice, tickSize, 152 | tickOptionComputation, tickGeneric 153 | tickString, tickEFP, tickSnapshotEnd} 154 | } 155 | 156 | \vskip 10pt 157 | 158 | \vbox{\head{Market Depth} 159 | Depth of book varies according to contract, and may 160 | not be available for all security types.\par 161 | \vskip 5pt 162 | \key{request market depth data}{reqMktDepth} 163 | \key{cancel market depth data}{cancelMktDepth} 164 | \vskip 5pt 165 | \ewrappers{updateMktDepth, updateMktDepthL2} 166 | } 167 | 168 | \vskip 10pt 169 | 170 | \vbox{\head{Real Time Bars} 171 | Real-time bars are limited to 5-second bars by the official 172 | API. All other \texttt{barSize} values will fail. 173 | Realtime bars may not be available for all security types.\par 174 | \vskip 5pt 175 | \key{request real-time bars}{reqRealTimeBars} 176 | \key{cancel real-time bars}{cancelRealTimeBars} 177 | \vskip 5pt 178 | \ewrappers{realtimeBars} 179 | } 180 | 181 | \vskip 10pt 182 | 183 | \vbox{\head{Historical Data} 184 | Depending on the contract, only specific combinations 185 | of \texttt{barSize} and \texttt{duration} 186 | arguments are valid, and some security types have no 187 | historical data. \Rfunc{reqHistory} is 188 | an IBrokers only call, allowing for one year of 1 minute 189 | bars, respecting IB timeouts (10 seconds) 190 | and maximum bars per request (2000).\par 191 | \vskip 5pt 192 | \key{request historical data}{reqHistoricalData} 193 | \key{request maximum history}{reqHistory} 194 | \key{cancel historical request}{cancelHistoricalData} 195 | \vskip 5pt 196 | Valid \texttt{barSize} values include: \texttt{1 secs}, 197 | \texttt{15 secs}, \texttt{1 min}, \texttt{2 mins}, 198 | \texttt{3 mins}, \texttt{5 mins}, \texttt{15 mins}, 199 | \texttt{30 mins}, \texttt{1 hour}, \texttt{1 day}, 200 | \texttt{1 week}, \texttt{1 month}, \texttt{3 months}, 201 | \texttt{1 year}. 202 | \vskip 5pt 203 | Valid \texttt{duration} form is \textit{`n S'}, where 204 | \textit{n} is the number of periods of \textit{S}. The 205 | second argument may be \texttt{S} (seconds), 206 | \texttt{D} (days), \texttt{W} (weeks), 207 | \texttt{M} (months), \texttt{Y} (year). 208 | Year requests are limited to 1 year. 209 | } 210 | 211 | \vskip 10pt 212 | 213 | \vbox{\head{Fundamental Data} 214 | Reuters fundamental data 215 | \vskip 5pt 216 | \key{request fundamental data}{reqFundamentalData} 217 | \key{cancel fundamental data}{cancelFundamentalData} 218 | \vskip 5pt 219 | \ewrappers{fundamentalData} 220 | } 221 | 222 | \vskip 10pt 223 | 224 | \vbox{\head{News Bulletins} 225 | Subscribe to news bulletins from Interactive Brokers. 226 | \vskip 5pt 227 | \key{subscribe}{reqNewsBulletins} 228 | \key{unsubscribe}{cancelNewsBulletins} 229 | \vskip 5pt 230 | \ewrappers{newsBulletins} 231 | } 232 | 233 | \vskip 10pt 234 | 235 | \vbox{\head{Pricing} 236 | Calculate option values, price and implied volatility, 237 | via the TWS engine. 238 | \vskip 5pt 239 | \key{calculate option price}{calculateOptionPrice} 240 | \key{calculate option volatility}{calculateImpliedVolatility} 241 | \vskip 5pt 242 | \ewrappers{tickOptionCalculation} 243 | } 244 | 245 | %\newpage 246 | \vskip 10pt 247 | 248 | \vbox{\head{Orders} 249 | Orders via the IB API, and the IBrokers API, require 250 | three primary components: A \Rclass{twsContract} object, 251 | a \Rclass{twsOrder} object, and a \Rfunc{placeOrder} call. Additionally, 252 | a valid \mbox{orderId} is required to the twsOrder object. This is 253 | found by calling \Rfunc{reqIds} on the twsConnection 254 | object. reqIds operates directly on the connection 255 | object by retrieving and then incrementing the next valid 256 | order id in the connection object.\par 257 | \vskip 5pt 258 | \key{next valid order id}{reqIds} 259 | \key{create order object}{twsOrder} 260 | \vskip 5pt 261 | \key{place order}{placeOrder} 262 | \key{cancel order}{cancelOrder} 263 | \vskip 5pt 264 | \key{exercise options}{exerciseOptions} 265 | \vskip 5pt 266 | \key{open orders}{reqOpenOrders} 267 | \key{all open orders}{reqAllOpenOrders, reqAutoOpenOrders} 268 | \vskip 5pt 269 | \ewrappers{orderStatus, openOrder, nextValidId, execDetails} 270 | \vskip 5pt 271 | <>= 272 | placeOrder(twsconn=tws, 273 | Contract=twsSTK("AAPL"), 274 | Order=twsOrder(reqIds(tws), 275 | "BUY", 276 | 10, 277 | "MKT")) 278 | @ 279 | } 280 | 281 | \vskip 10pt 282 | 283 | \vbox{\head{Account} 284 | Account data is requested on a subscription basis. The user 285 | subscribes to a continuously updated feed from the TWS 286 | by passing the connection object and the \texttt{subscribe} 287 | argument set to \texttt{TRUE}; unsubscribe with \texttt{FALSE}. 288 | The \texttt{.reqAccountUpdates} function will return 289 | immediately and will begin or end a subscription; account 290 | messages must be handled by the user. \texttt{reqAccountUpdates} 291 | (without the prepended `dot') will subscribe, 292 | collect data, and unsubscribe -- returning an 293 | \texttt{AccountUpdate} object which may be processed 294 | with \texttt{twsPortfolioValue}. 295 | \vskip 5pt 296 | \key{get account data}{reqAccountUpdates} 297 | \key{subscribe account updates (only)}{.reqAccountUpdates} 298 | \key{cancel account updates}{cancelAccountUpdates} 299 | \vskip 5pt 300 | \key{view portfolio}{twsPortfolioValue} 301 | \vskip 5pt 302 | \ewrappers{updateAccountValue, updatePortfolio, \mbox{updateAccountTime}, 303 | accountDownloadEnd} 304 | } 305 | 306 | \vskip 10pt 307 | 308 | \vbox{\head{Executions} 309 | Returns execution details in a \textit{twsExecution} object. 310 | This method is currently only implemented as a request, with 311 | no built-in mechanism to manage response data apart from 312 | it being discarded. 313 | \vskip 5pt 314 | \key{request execution data}{reqExecutions} 315 | \key{filter argument}{reqExecutionFilter} 316 | \vskip 5pt 317 | \ewrappers{execDetails, execDetailsEnd} 318 | } 319 | 320 | \vskip 10pt 321 | 322 | \vbox{\head{Financial Advisors} 323 | Funtions for FA-enabled accounts 324 | \vskip 5pt 325 | \key{request list of accounts}{reqManagedAccts} 326 | \key{request FA configuration (XML)}{requestFA} 327 | \key{change FA configuration}{replaceFA} 328 | \vskip 5pt 329 | \ewrappers{managedAccts, receiveFA} 330 | } 331 | 332 | \vskip 10pt 333 | 334 | \vbox{\head{Scanner} 335 | Interactive Brokers scanner data ... 336 | \vskip 5pt 337 | \key{scanner params (XML)}{reqScannerParameters} 338 | \key{scanner subscription object}{twsScannerSubscription} 339 | \key{return scanner results}{reqScannerSubscription} 340 | \vskip 5pt 341 | \key{subscribe to scanner}{.reqScannerSubscription} 342 | \key{unsubscribe to scanner}{cancelScannerSubscription} 343 | \vskip 5pt 344 | \ewrappers{scannerParameters, scannerData} 345 | } 346 | 347 | \vskip 10pt 348 | 349 | \vbox{\head{eWrapper} 350 | eWrappers contain the callback methods 351 | for all incoming message types. These are closures 352 | in R that contain functions and data. These functions 353 | are called based on incoming message types from the 354 | TWS. 355 | \vskip 5pt 356 | \key{new eWrapper}{eWrapper} 357 | \key{market data to vector(s)}{eWrapper.data} 358 | \key{market data to csv}{eWrapper.MktData.CSV} 359 | \vskip 5pt 360 | } 361 | 362 | 363 | \vskip 10pt 364 | 365 | \vbox{\head{DISCLAIMER} 366 | IBROKERS IS NOT ENDORSED, AFFILIATED, OR CONNECTED TO 367 | INTERACTIVE BROKERS, LLC. INTERACTIVE BROKERS IS 368 | TRADEMARKED AND PROPERTY OF INTERACTIVE BROKERS, LLC. 369 | \vskip 5pt 370 | IBROKERS COMES WITH NO WARRANTY, EXPRESSED OR IMPLIED, 371 | AND IS FOR USE \emph{AT YOUR OWN RISK}. 372 | } 373 | \vskip 10pt 374 | \vbox{\small Copyright 2010. Jeffrey A. Ryan} 375 | \end{multicols} 376 | \end{document} 377 | -------------------------------------------------------------------------------- /vignettes/IBrokersREFCARD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/IBrokersREFCARD.pdf -------------------------------------------------------------------------------- /vignettes/IBrokersRef.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/IBrokersRef.pdf -------------------------------------------------------------------------------- /vignettes/RealTime.R: -------------------------------------------------------------------------------- 1 | ### R code from vignette source 'RealTime.Rnw' 2 | 3 | ################################################### 4 | ### code chunk number 1: reqCurrentTime (eval = FALSE) 5 | ################################################### 6 | ## writeBin(c("49","1"), con) 7 | 8 | 9 | ################################################### 10 | ### code chunk number 2: twsCALLBACK 11 | ################################################### 12 | require(IBrokers) 13 | deparse(twsCALLBACK)[30:47] 14 | 15 | 16 | -------------------------------------------------------------------------------- /vignettes/RealTime.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/RealTime.pdf -------------------------------------------------------------------------------- /vignettes/eWrapper_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/eWrapper_object.png -------------------------------------------------------------------------------- /vignettes/functions_IBrokers2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/functions_IBrokers2.png -------------------------------------------------------------------------------- /vignettes/ib_trade_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/ib_trade_processing.png -------------------------------------------------------------------------------- /vignettes/ibrokers_design.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Executing Real-time Trading Strategies Via the API of Interactive Brokers 3 | author: Jerzy Pawlowski (algoquant) 4 | tags: Interactive Brokers, API 5 | abstract: Executing real-time trading strategies Via the API of Interactive Brokers. 6 | output: 7 | md_document: 8 | variant: markdown_github 9 | --- 10 | 11 | ### Overview 12 | 13 | The package *IBrokers2* executes real-time trading strategies using the functions from package *IBrokers* plus some additional functions. The additional functions mostly provide trade execution capabilities, for running systematic trading strategies. For example, the original function *IBrokers::reqRealTimeBars()* can be used for running trading strategies, by passing to it a customized *event wrapper* (*eWrapper*) function called *IBrokers2::trade_wrapper()*. 14 | 15 | 16 | ### Implementation Details 17 | 18 | The function *IBrokers::reqRealTimeBars()* collects real-time bar data (*OHLC* data) from Interactive Brokers and saves it to a file. It relies on an *eWrapper* function to write each bar of *OHLC* data. An *eWrapper* is an *R* environment which contains variables and handler functions, and serves as a buffer for the streaming real-time market data. An *eWrapper* function creates an *eWrapper* environment, defines its member (handler) functions, and returns the *eWrapper* environment. 19 | 20 | The function *IBrokers::reqRealTimeBars()* calls *IBrokers::twsCALLBACK()*, which first creates an *eWrapper* environment by calling an *eWrapper* function, and then passes the *eWrapper* environment into *IBrokers::processMsg()* and calls it in a callback loop. The callback loop is performed inside the function *IBrokers::twsCALLBACK()*, which calls *IBrokers::processMsg()* in a loop, which in turn calls *realtimeBars()* (defined inside *IBrokers2::trade_wrapper()*). The function *IBrokers::processMsg()* calls the data handlers in the *eWrapper* environment to process and save each bar of the *OHLC* data. This way the *eWrapper* environment created by *IBrokers2::trade_wrapper()* persists as a *mutable state* in the evaluation environment of the function *twsCALLBACK()*, in between bar data arrivals. 21 | 22 | The function *IBrokers2::trade_wrapper()* is an *eWrapper* function which is customized for trading. It creates an *eWrapper* environment, defines the member function *realtimeBars()*, and returns the *eWrapper* environment. The function *realtimeBars()* is where the trading code resides. The trading code updates a trading model with new data, runs the model, and then executed trades based on its output. The function *IBrokers2::trade_wrapper()* is derived from the function *IBrokers::eWrapper.RealTimeBars.CSV()*. 23 | 24 | ![](ib_trade_processing.png){width="60%"} 25 | 26 | An example of a simple trading strategy can be run with the code in the file *IB_scripts.R* in the *scripts* sub-directory. The user can customize this strategy by modifying the trading code in *realtimeBars()*. 27 | 28 | 29 | ### System Architecture 30 | 31 | The Interactive Brokers API uses numerical codes to indicate the type of messages and the data that are being transmitted. *IBrokers* maintains several named lists with the numerical IB codes, called: *.twsIncomingMSG*, *.twsOutgoingMSG*, *.twsTickType*, and *.twsOrderID*. 32 | The variable *curMsg* is the value returned by *readBin()*. The variable *curMsg* is parsed by comparing it with the elements of *.twsIncomingMSG*. 33 | The list *.twsOutgoingMSG* is used to create strings for outgoing messages, which are then passed into *writeBin()*. 34 | 35 | 36 | 37 | ### Installation and Loading 38 | 39 | Install package *IBrokers2* from github: 40 | ```{r eval=FALSE} 41 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 42 | install.packages("devtools") 43 | devtools::install_github(repo="algoquant/IBrokers2") 44 | library(IBrokers2) 45 | ``` 46 |
47 | 48 | -------------------------------------------------------------------------------- /vignettes/ibrokers_design.md: -------------------------------------------------------------------------------- 1 | ### Overview 2 | 3 | The package *IBrokers2* executes real-time trading strategies using the functions from package *IBrokers* plus some additional functions. The additional functions mostly provide trade execution capabilities, for running systematic trading strategies. For example, the original function *IBrokers::reqRealTimeBars()* can be used for running trading strategies, by passing to it a customized *event wrapper* (*eWrapper*) function called *IBrokers2::trade\_wrapper()*. 4 | 5 | ### Implementation Details 6 | 7 | The function *IBrokers::reqRealTimeBars()* collects real-time bar data (*OHLC* data) from Interactive Brokers and saves it to a file. It relies on an *eWrapper* function to write each bar of *OHLC* data. An *eWrapper* is an *R* environment which contains variables and handler functions, and serves as a buffer for the streaming real-time market data. An *eWrapper* function creates an *eWrapper* environment, defines its member (handler) functions, and returns the *eWrapper* environment. 8 | 9 | The function *IBrokers::reqRealTimeBars()* calls *IBrokers::twsCALLBACK()*, which first creates an *eWrapper* environment by calling an *eWrapper* function, and then passes the *eWrapper* environment into *IBrokers::processMsg()* and calls it in a callback loop. The callback loop is performed inside the function *IBrokers::twsCALLBACK()*, which calls *IBrokers::processMsg()* in a loop, which in turn calls *realtimeBars()* (defined inside *IBrokers2::trade\_wrapper()*). The function *IBrokers::processMsg()* calls the data handlers in the *eWrapper* environment to process and save each bar of the *OHLC* data. This way the *eWrapper* environment created by *IBrokers2::trade\_wrapper()* persists as a *mutable state* in the evaluation environment of the function *twsCALLBACK()*, in between bar data arrivals. 10 | 11 | The function *IBrokers2::trade\_wrapper()* is an *eWrapper* function which is customized for trading. It creates an *eWrapper* environment, defines the member function *realtimeBars()*, and returns the *eWrapper* environment. The function *realtimeBars()* is where the trading code resides. The trading code updates a trading model with new data, runs the model, and then executed trades based on its output. The function *IBrokers2::trade\_wrapper()* is derived from the function *IBrokers::eWrapper.RealTimeBars.CSV()*. 12 | 13 | 14 | 15 | An example of a simple trading strategy can be run with the code in the file *IB\_scripts.R* in the *scripts* sub-directory. The user can customize this strategy by modifying the trading code in *realtimeBars()*. 16 | 17 | ### System Architecture 18 | 19 | The Interactive Brokers API uses numerical codes to indicate the type of messages and the data that are being transmitted. *IBrokers* maintains several named lists with the numerical IB codes, called: *.twsIncomingMSG*, *.twsOutgoingMSG*, *.twsTickType*, and *.twsOrderID*. The variable *curMsg* is the value returned by *readBin()*. The variable *curMsg* is parsed by comparing it with the elements of *.twsIncomingMSG*. The list *.twsOutgoingMSG* is used to create strings for outgoing messages, which are then passed into *writeBin()*. 20 | 21 | ### Installation and Loading 22 | 23 | Install package *IBrokers2* from github: 24 | 25 | ``` r 26 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 27 | install.packages("devtools") 28 | devtools::install_github(repo="algoquant/IBrokers2") 29 | library(IBrokers2) 30 | ``` 31 | 32 |
33 | -------------------------------------------------------------------------------- /vignettes/market_event_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/market_event_processing.png -------------------------------------------------------------------------------- /vignettes/market_event_processing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/market_event_processing2.png -------------------------------------------------------------------------------- /vignettes/real_time_trading.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Executing Real-time Trading Strategies Via the API of Interactive Brokers" 3 | author: "Jerzy Pawlowski (algoquant)" 4 | tags: Interactive Brokers, API 5 | abstract: The package *IBrokers2* provides *R* functions for executing real-time trading via the API of Interactive Brokers. 6 | output: 7 | md_document: 8 | variant: markdown_github 9 | --- 10 | 11 | ### Executing Real-time Trading Strategies 12 | 13 | Real-time trading means trading in a programmatic loop, in which continuous streaming market data is used to update a trading model, and the model outputs are used by an order management system to place trade orders via an API. Real-time trading is fully automated, with the only human intervention being to turn the system on and off. Real-time trading is *systematic* because trading decisions are made by a trading model, not by discretionary human traders. 14 | 15 | ![](real_time_trading.png){width="60%"} 16 | 17 | Real-time trading requires three components: acquisition of streaming market data and account data, trading model execution, and trade order management. 18 | 19 | 20 | ### Real-time Trading Using The Package *IBrokers2* 21 | 22 | The package IBrokers2 contains *R* functions for executing real-time trading via the API of Interactive Brokers (IB API). The package *IBrokers2* is derived from package *IBrokers*, and is fully backward compatible with it. This means that all the *IBrokers* functions and variables are preserved exactly in *IBrokers2*, while some additional functions have been added. The additional functions in *IBrokers2* provide functionality for the three components required for real-time trading. 23 | 24 | *IBrokers2* adapts some of the functions from *IBrokers*, to enable real-time trading capabilities. For example, the original function *IBrokers::reqRealTimeBars()* is used for running trading strategies, by passing to it a customized *event wrapper* (*eWrapper*) function called *IBrokers2::trade_wrapper()*. 25 | 26 | The function *IBrokers::reqRealTimeBars()* collects real-time bar data (*OHLC* data) from Interactive Brokers in a callback loop, and saves it to a file. Interactive Brokers by default only offers 5-second bars of *real-time* prices and volumes (but also offers *historical* data at other frequencies). The function *IBrokers::reqRealTimeBars()* relies on an *eWrapper* environment to process and save each bar of *OHLC* data. An *eWrapper* environment is an *R* environment containing data, variables, and handler (accessor) functions. *eWrapper* environments serve as a buffer for saving the streaming real-time market data. An *eWrapper* function creates an *eWrapper* environment. The standard *eWrapper* function for acquiring real-time bar data is *IBrokers::eWrapper.RealTimeBars.CSV()*. This function can be modified to perform real-time trading. 27 | 28 | The function *IBrokers::reqRealTimeBars()* calls *IBrokers::twsCALLBACK()*, which first creates an *eWrapper* environment by calling an *eWrapper* function, and then passes the *eWrapper* environment into *IBrokers::processMsg()* and calls it in a callback loop. The function *IBrokers::processMsg()* calls the data handlers in the *eWrapper* environment to process and save each bar of the *OHLC* data. This way the *eWrapper* environment created by *IBrokers2::trade_wrapper()* persists as a *mutable state* in the evaluation environment of the function *twsCALLBACK()*, in between bar data arrivals. 29 | 30 | ![](ib_trade_processing.png){width="60%"} 31 | 32 | 33 | The callback loop is performed inside the function *IBrokers::twsCALLBACK()*, by calling *IBrokers::processMsg()* in a loop, which in turn calls function *realtimeBars()* (defined inside *IBrokers2::trade_wrapper()*). 34 | 35 | The function *IBrokers2::trade_wrapper()* is an *eWrapper* function derived from the function *IBrokers::eWrapper.RealTimeBars.CSV()*, which is customized for trading. It creates an *eWrapper* environment, defines the member function *realtimeBars()*, and returns the *eWrapper* environment. The function *realtimeBars()* is where the trading code resides. The trading code updates a trading model with new data, runs the model, and then executed trades based on its output. 36 | 37 | An example of a simple trading strategy can be run with the code in the file *IB_scripts.R* in the *scripts* sub-directory. The user can customize this strategy by modifying the trading code in the function *model_fun()*, inside function *trade_wrapper()*. 38 | 39 | 40 | ### System Architecture 41 | 42 | The Interactive Brokers API uses numerical codes to indicate the type of messages and the data that are being transmitted. *IBrokers* maintains several named lists with the numerical IB codes, called: *.twsIncomingMSG*, *.twsOutgoingMSG*, *.twsTickType*, and *.twsOrderID*. 43 | The variable *curMsg* is the value returned by *readBin()*. The variable *curMsg* is parsed by comparing it with the elements of *.twsIncomingMSG*. 44 | The list *.twsOutgoingMSG* is used to create strings for outgoing messages, which are then passed into *writeBin()*. 45 | 46 | 47 | 48 | ### Installation and Loading 49 | 50 | Install package *IBrokers2* from github: 51 | ```{r eval=FALSE} 52 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 53 | install.packages("devtools") 54 | devtools::install_github(repo="algoquant/IBrokers2") 55 | library(IBrokers2) 56 | ``` 57 |
58 | 59 | -------------------------------------------------------------------------------- /vignettes/real_time_trading.md: -------------------------------------------------------------------------------- 1 | ### Executing Real-time Trading Strategies 2 | 3 | Real-time trading means trading in a programmatic loop, in which continuous streaming market data is used to update a trading model, and the model outputs are used by an order management system to place trade orders via an API. Real-time trading is fully automated, with the only human intervention being to turn the system on and off. Real-time trading is *systematic* because trading decisions are made by a trading model, not by discretionary human traders. 4 | 5 | 6 | 7 | Real-time trading requires three components: acquisition of streaming market data and account data, trading model execution, and trade order management. 8 | 9 | ### Real-time Trading Using The Package *IBrokers2* 10 | 11 | The package IBrokers2 contains *R* functions for executing real-time trading via the API of Interactive Brokers (IB API). The package *IBrokers2* is derived from package *IBrokers*, and is fully backward compatible with it. This means that all the *IBrokers* functions and variables are preserved exactly in *IBrokers2*, while some additional functions have been added. The additional functions in *IBrokers2* provide functionality for the three components required for real-time trading. 12 | 13 | *IBrokers2* adapts some of the functions from *IBrokers*, to enable real-time trading capabilities. For example, the original function *IBrokers::reqRealTimeBars()* is used for running trading strategies, by passing to it a customized *event wrapper* (*eWrapper*) function called *IBrokers2::trade\_wrapper()*. 14 | 15 | The function *IBrokers::reqRealTimeBars()* collects real-time bar data (*OHLC* data) from Interactive Brokers in a callback loop, and saves it to a file. Interactive Brokers by default only offers 5-second bars of *real-time* prices and volumes (but also offers *historical* data at other frequencies). The function *IBrokers::reqRealTimeBars()* relies on an *eWrapper* environment to process and save each bar of *OHLC* data. An *eWrapper* environment is an *R* environment containing data, variables, and handler (accessor) functions. *eWrapper* environments serve as a buffer for saving the streaming real-time market data. An *eWrapper* function creates an *eWrapper* environment. The standard *eWrapper* function for acquiring real-time bar data is *IBrokers::eWrapper.RealTimeBars.CSV()*. This function can be modified to perform real-time trading. 16 | 17 | The function *IBrokers::reqRealTimeBars()* calls *IBrokers::twsCALLBACK()*, which first creates an *eWrapper* environment by calling an *eWrapper* function, and then passes the *eWrapper* environment into *IBrokers::processMsg()* and calls it in a callback loop. The function *IBrokers::processMsg()* calls the data handlers in the *eWrapper* environment to process and save each bar of the *OHLC* data. This way the *eWrapper* environment created by *IBrokers2::trade\_wrapper()* persists as a *mutable state* in the evaluation environment of the function *twsCALLBACK()*, in between bar data arrivals. 18 | 19 | 20 | 21 | The callback loop is performed inside the function *IBrokers::twsCALLBACK()*, by calling *IBrokers::processMsg()* in a loop, which in turn calls function *realtimeBars()* (defined inside *IBrokers2::trade\_wrapper()*). 22 | 23 | The function *IBrokers2::trade\_wrapper()* is an *eWrapper* function derived from the function *IBrokers::eWrapper.RealTimeBars.CSV()*, which is customized for trading. It creates an *eWrapper* environment, defines the member function *realtimeBars()*, and returns the *eWrapper* environment. The function *realtimeBars()* is where the trading code resides. The trading code updates a trading model with new data, runs the model, and then executed trades based on its output. 24 | 25 | An example of a simple trading strategy can be run with the code in the file *IB\_scripts.R* in the *scripts* sub-directory. The user can customize this strategy by modifying the trading code in the function *model\_fun()*, inside function *trade\_wrapper()*. 26 | 27 | ### System Architecture 28 | 29 | The Interactive Brokers API uses numerical codes to indicate the type of messages and the data that are being transmitted. *IBrokers* maintains several named lists with the numerical IB codes, called: *.twsIncomingMSG*, *.twsOutgoingMSG*, *.twsTickType*, and *.twsOrderID*. The variable *curMsg* is the value returned by *readBin()*. The variable *curMsg* is parsed by comparing it with the elements of *.twsIncomingMSG*. The list *.twsOutgoingMSG* is used to create strings for outgoing messages, which are then passed into *writeBin()*. 30 | 31 | ### Installation and Loading 32 | 33 | Install package *IBrokers2* from github: 34 | 35 | ``` r 36 | if (!("package:devtools" %in% search() || require("devtools", quietly=TRUE))) 37 | install.packages("devtools") 38 | devtools::install_github(repo="algoquant/IBrokers2") 39 | library(IBrokers2) 40 | ``` 41 | 42 |
43 | -------------------------------------------------------------------------------- /vignettes/real_time_trading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/real_time_trading.png -------------------------------------------------------------------------------- /vignettes/trade_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/trade_processing.png -------------------------------------------------------------------------------- /vignettes/trade_wrapper_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algoquant/IBrokers2/2ab90a069f4d2ce082893c74df295a5fa8208e98/vignettes/trade_wrapper_object.png --------------------------------------------------------------------------------