diff --git a/README.md b/README.md index 35f02c1..3274dbc 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,43 @@ # rib -##### An R implementation of Interactive Brokers API +**An R implementation of Interactive Brokers API** -Originally inspired by [`IBrokers`](https://CRAN.R-project.org/package=IBrokers), `rib` is a native [R](https://www.r-project.org/) client implementing [Interactive Brokers](https://www.interactivebrokers.com/) API to communicate with their TWS or IBGateway. +Originally inspired by [`IBrokers`](https://CRAN.R-project.org/package=IBrokers), +`rib` is a native [R](https://www.r-project.org/) client +implementing [Interactive Brokers](https://www.interactivebrokers.com/) API +to communicate with their TWS or IBGateway. -It aims to be feature complete, though it does not support legacy versions: _i.e._ only API versions `v100` and above are currently supported. This limit may become even stricter in the future. +It aims to be feature complete, though it does not support legacy versions: +_i.e._ only API versions `v100` and above are currently supported. +This limit may become even stricter in the future. -The package design mirrors the official C++/Java [IB API](http://interactivebrokers.github.io/tws-api/), which is based on an asynchronous request-response model over a TCP socket. +The package design mirrors the official C++/Java +[IB API](http://interactivebrokers.github.io/tws-api/), +which is based on an asynchronous request-response communication model +over a TCP socket. ### Installation -To install from GitHub, assuming [`devtools`](https://CRAN.R-project.org/package=devtools) or at least [`remotes`](https://CRAN.R-project.org/package=remotes) is already installed: +To install from GitHub, +assuming [`devtools`](https://CRAN.R-project.org/package=devtools) or at least +[`remotes`](https://CRAN.R-project.org/package=remotes) is already installed: ```R remotes::install_github("lbilli/rib") ``` ### Usage -The user interacts mainly with two classes, implemented here as [`R6`](https://CRAN.R-project.org/package=R6) objects: +The user interacts mainly with two classes, implemented here as +[`R6`](https://CRAN.R-project.org/package=R6) objects: - `IBClient`: responsible to establish the connection and send requests to the server. -- `IBWrap`: base class holding the callbacks that are executed when the client processes the responses. Customized versions are derived from this class. +- `IBWrap`: base class holding the callbacks that are executed when the + client processes the responses. Customized versions are derived from this class. -Other data structures (_e.g._: `Contract`, `Order`) are implemented as `R` lists, or nested lists, mirroring the original classes. +Other data structures, such as `Contract` and `Order`, are implemented as R lists, +or nested lists, that mirror the respective classes in the official IB API. -A complete minimal working example follows. For this code to work, an instance of the IB TWS or IBGateway needs to be running on the local machine and listening on port `4002`. **Note:** _demo_ or _paper_ account recommended!! :smirk: +A complete minimal working example follows. +For this code to work, an instance of the IB TWS or IBGateway needs to be running +on the local machine, listening on port `4002`. +**Note:** _demo_ or _paper_ account recommended!! :smirk: ```R library(rib) @@ -37,7 +53,7 @@ IBWrapCustom <- R6::R6Class("IBWrapCustom", # Customized methods connectAck= function() {}, - connectionClosed= function() cat("ConnectionClosed.\n"), + connectionClosed= function() cat("Connection Closed.\n"), error= function(id, errorCode, errorString) cat(id, errorCode, errorString, "\n"), @@ -48,10 +64,10 @@ IBWrapCustom <- R6::R6Class("IBWrapCustom", ) # Instantiate wrapper and client -ew <- IBWrapCustom$new() -ic <- IBClient$new(ew) +wrap <- IBWrapCustom$new() +ic <- IBClient$new(wrap) -# Connect +# Connect to the server with clientId = 1 ic$connect(port=4002, clientId=1) # Check connection messages (optional) @@ -64,6 +80,8 @@ contract <- IBContract("GOOG") order <- IBOrder("BUY", 10, "LMT", 1000) orderId <- 1 # Should match whatever is returned by the server + +# Send order ic$placeOrder(orderId, contract, order) # Check messages @@ -73,23 +91,27 @@ ic$checkMsg() ic$disconnect() ``` -As `R` is single threaded, in general it is the user's responsability to code an event loop that handles the request-response pattern: _i.e._: there is no `Reader` in the background waiting for and processing the server responses. +As R is single threaded, in general it is the user's responsability to code +an event loop that handles the request-response pattern: +_i.e._ there is no `Reader` in the background monitoring the connection +and processing the server responses. Two possible approaches, with or without a loop, are described: ##### Straight Request-Response pattern. No loop. -This is the simplest case. Not suitable for data subscriptions or whenever a stream of messages are expected. It follows the pattern: - - connect - - send requests - - process responses - - disconnect +This is the simplest case. Not suitable for data subscriptions or whenever a +stream of messages are expected. It follows the pattern: +- connect +- send requests +- process responses +- disconnect ```R library(rib) # Instantiate wrapper, client and connect -ew <- IBWrapSimple$new() -ic <- IBClient$new(ew) +wrap <- IBWrapSimple$new() +ic <- IBClient$new(wrap) ic$connect(port=4002, clientId=1) # Send requests, e.g.: @@ -103,28 +125,27 @@ ic$reqContractDetails(11, contract) ic$checkMsg(2) # Find results in -ew$context +wrap$context # Disconnect ic$disconnect() ``` ##### Request-Response loop - - A more realistic application requires a loop around the previous example: - - connect - - repeat - - send requests - - process responses - - if done exit - - disconnect +A more realistic application requires a loop around the previous example: +- connect +- repeat + - send requests + - process responses + - if done exit +- disconnect ```R library(rib) # Instantiate wrapper, client and connect -ew <- IBWrapSimple$new() -ic <- IBClient$new(ew) +wrap <- IBWrapSimple$new() +ic <- IBClient$new(wrap) ic$connect(port=4002, clientId=1) # Main loop @@ -153,34 +174,61 @@ ic$disconnect() ##### [`IBClient`](R/IBClient.R) This implements the IB `EClient` class functionality. Among its methods: - `new(wrap)`: constructor. Require an object derived from `IBWrap` as argument. -- `replaceWrap(wrap)`: replace the `wrap`. As the client runs synchronously, it is possible to replace the set of callbacks in a connected client. +- `replaceWrap(wrap)`: replace the `wrap`. As the client runs in a single thread, + it is possible to replace the set of callbacks in a connected client. - `connect(host, port, clientId, connectOptions)`: establish a connection. - `disconnect()`: close the connection. -- `checkMsg(timeout)`: wait for responses and dispatch callbacks. If no response is available, it **blocks** up to `timeout` seconds. Return the number of responses processed. **Needs to be called regularly**. -- `flush()`: flush unprocessed responses, without dispatching callbacks. Mostly for debugging or testing. -- all other methods send specific requests to the server. Refer to the official IB `EClient` documentation for details and method signatures. +- `checkMsg(timeout)`: wait for responses and dispatch callbacks. + If no response is available, it **blocks** up to `timeout` seconds. + Return the number of responses processed. **Needs to be called regularly**. +- `flush()`: flush unprocessed responses, without dispatching callbacks. + Mostly for debugging or testing. +- all other methods send specific requests to the server. + Refer to the official IB `EClient` documentation for details and method signatures. ##### [`IBWrap`](R/IBWrap/R) -Like the official IB `EWrapper`, this holds the callbacks that are dispatched when processing the responses. `IBWrap` itself is a base class containing only dummy methods. Users need to derive from it and customize the desired methods. +Like the official IB `EWrapper`, this holds the callbacks that are dispatched +when processing the responses. `IBWrap` itself is a base class containing +only dummy methods. +Users need to derive from it and customize the desired methods. -Refer to the code [above](#usage) or, for a more extensive example, to the definition of [`IBWrapSimple`](R/IBWrapSimple.R), which simply prints out the reponses or store their contents in `IBWrapSimple$context` for later inspection. +Refer to the code [above](#usage) or, for a more extensive example, +to the definition of [`IBWrapSimple`](R/IBWrapSimple.R), which is provided for +illustrative purposes and which prints out the content of the responses or store it +within `IBWrapSimple$context` for later inspection. -For more details regarding callback definitions and signatures, refer again to the official IB `EWrapper` documentation. +For more details regarding callback definitions and signatures, +refer again to the official IB `EWrapper` documentation. ##### Notes -Callbacks are generally invoked with arguments and types matching the signatures found in the official documentation. However, there are few notable exceptions: -- `tickPrice()` has an extra `size` argument, which is meaningful only when `TickType = {BID, ASK, LAST}`. In these cases, the official IB API fires an extra `tickSize()` event instead. -- `historicalData()` is invoked only once per request, presenting all the historical data as a single `data.frame`, whereas the official IB API invokes it row-by-row. -- `scannerData()` is also invoked once per request and its arguments are in fact vectors rather than single values. - -These modifications make it possible to establish the rule: _one callback per server response_. - -As a corollary, `historicalDataEnd()` and `scannerDataEnd()` become redundant and, therefore, are **not** used in this package. - -`data.frame` structures are used liberally in several other callbacks, where they fit naturally, such as: `softDollarTiers()`, `familyCodes()`, `mktDepthExchanges()`, `smartComponents()`, `newsProviders()`, `histogramData()`, `marketRule()` and the `historicalTicks*()` family. +Callbacks are generally invoked with arguments and types matching the signatures +found in the official documentation. However, there are few notable exceptions: +- `tickPrice()` has an extra `size` argument, + which is meaningful only when `TickType = {BID, ASK, LAST}`. + In these cases, the official IB API fires an extra `tickSize()` event instead. +- `historicalData()` is invoked only once per request, + presenting all the historical data as a single `data.frame`, + whereas the official IB API invokes it row-by-row. +- `scannerData()` is also invoked once per request and its arguments + are in fact vectors rather than single values. + +These modifications make it possible to establish the rule: +_one callback per server response_. + +As a corollary, `historicalDataEnd()` and `scannerDataEnd()` become redundant and +thus are **not** used in this package. + +`data.frame` structures are used liberally as arguments in several other callbacks, +such as: `softDollarTiers()`, `familyCodes()`, +`mktDepthExchanges()`, `smartComponents()`, `newsProviders()`, `histogramData()`, +`marketRule()` and the `historicalTicks*()` family. ##### Data Structures -Other classes that mainly hold data are also [defined](R/structs.R) in the package. They are implemented as simple `R` (nested) lists, with names, types and default values matching the IB counterparts. Examples are: `Contract`, `Order`, `ComboLeg`, `ExecutionFilter`. `ScannerSubscription` and `Condition`. +Other classes that mainly hold data are also [defined](R/structs.R) in the package. +They are implemented as simple R (nested) lists with names, types and default values +matching the IB API counterparts. +Examples are: `Contract`, `Order`, `ComboLeg`, `ExecutionFilter`, `ScannerSubscription` +and `Condition`. To use them, simply make a copy and override their elements: ```R @@ -188,7 +236,8 @@ contract <- Contract contract$conId <- 12345 contract$currency <- "USD" ``` -In the case of `Contract` and `Order`, convenience [functions](R/factory.R) are also provided to prefill some common fields: +In the case of `Contract` and `Order`, convenience [functions](R/factory.R) +are also provided to prefill some common fields: ```R contract <- IBContract("GOOG") @@ -214,7 +263,7 @@ To instantiate a `Condition` type, invoke `fCondition(type)` like this: ```R condition <- fCondition("Price") ``` -`TagValue` types are implemented as `R` named character vectors: +`TagValue` types are implemented as R named character vectors: ```R # Wherever a TagValue is needed, something like this can be used: c(tag1="value1", tag2="value2")