Skip to content

Commit

Permalink
Add man/*
Browse files Browse the repository at this point in the history
Move IBWrapSimple to examples/
  • Loading branch information
lbilli committed Nov 24, 2022
1 parent 71d7e1b commit 455a514
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 64 deletions.
26 changes: 12 additions & 14 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
Package: rib
Title: An R implementation of Interactive Brokers API
Version: 0.17.2
Title: An Implementation of 'Interactive Brokers' API
Version: 0.18.2
Authors@R: person("Luca", "Billi", email = "[email protected]", role = c("aut", "cre"))
Description: A native R implementation of Interactive Brokers API.
It establishes a TCP connection to a server and handles
request-response message exchanges.
Data is encoded and decoded between user and wire formats. Data strucures
mirror what is found in the official API, which is available for other
languages.
Description: Allows interaction with 'Interactive Brokers' 'Trader Workstation'
<https://interactivebrokers.github.io/tws-api/>.
Handles the connection over the network and the exchange of messages.
Data is encoded and decoded between user and wire formats.
Data structures and functionality closely mirror the official implementations.
Depends:
R (>= 3.4.0)
Import:
R6 (>= 2.4.0)
R (>= 3.4)
Imports:
R6 (>= 2.4)
License: GPL-3
Encoding: UTF-8
LazyData: true
URL: https://github.com/lbilli/rib/
BugReports: https://github.com/lbilli/rib/issues/
URL: https://github.com/lbilli/rib
BugReports: https://github.com/lbilli/rib/issues
3 changes: 2 additions & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ importFrom(R6, R6Class)
# Main classes
export(IBClient)
export(IBWrap)
export(IBWrapSimple)

# Helpers
export(IBContract)
export(IBOrder)
export(fCondition)
export(map_enum2int)
export(map_int2enum)

# Structures
export(ComboLeg)
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# rib 0.18.2

* Submission to CRAN
2 changes: 1 addition & 1 deletion R/IBClient.R
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ IBClient <- R6Class("IBClient",

stopifnot(length(res)==2L)

cat("server version and timestamp:", res, "\n")
message("server version: ", res[1L], " timestamp: ", res[2L])
private$serverVersion <- as.integer(res[1L])
private$serverTimestamp <- res[2L]

Expand Down
2 changes: 1 addition & 1 deletion R/zzz.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.onLoad <- function(libname, pkgname) {

load_data <- function(file)
utils::read.table(file= system.file("data-raw/", file, package=pkgname),
utils::read.table(file= system.file("data-raw", file, package=pkgname),
header= TRUE,
colClasses= "character")

Expand Down
89 changes: 43 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@

Originally inspired by [`IBrokers`](https://CRAN.R-project.org/package=IBrokers),
`rib` is a native [R](https://www.r-project.org/) client that
implements [Interactive Brokers](https://www.interactivebrokers.com/) API
to communicate with their TWS or IBGateway.
implements the [Interactive Brokers](https://www.interactivebrokers.com/) API
to communicate with TWS or IBGateway.

It aims to be feature complete, however it does not support legacy versions.
Currently, only API versions `v165+` are supported.

The package design mirrors the official C++/Java
[IB API](https://interactivebrokers.github.io/tws-api/),
which is based on an asynchronous request-response communication model
over TCP.
which is based on an asynchronous communication model over TCP.

### Installation
To install from GitHub,
Expand All @@ -26,9 +25,9 @@ remotes::install_github("lbilli/rib")
### Usage
The user interacts mainly with two classes, implemented 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.
- `IBClient`: responsible to establish the connection and send requests to the server
- `IBWrap`: base class holding the callbacks that are executed when responses
are processed. User customizations are derived from this class.

Other data structures, such as `Contract` and `Order`, are implemented as R lists,
or nested lists, and mirror the respective classes of the official IB API.
Expand Down Expand Up @@ -65,35 +64,35 @@ IBWrapCustom <- R6::R6Class("IBWrapCustom",

# Instantiate wrapper and client
wrap <- IBWrapCustom$new()
ic <- IBClient$new(wrap)
ic <- IBClient$new()

# Connect to the server with clientId = 1
ic$connect(port=4002, clientId=1)

# Check connection messages (optional)
ic$checkMsg()
ic$checkMsg(wrap)

# Define contract
contract <- IBContract("GOOG")
contract <- IBContract(symbol="GOOG", secType="STK", exchange="SMART", currency="USD")

# Define order
order <- IBOrder("BUY", 10, "LMT", 1000)
order <- IBOrder(action="BUY", totalQuantity=10, orderType="LMT", lmtPrice=1000)

orderId <- 1 # Should match whatever is returned by the server

# Send order
ic$placeOrder(orderId, contract, order)

# Check messages
ic$checkMsg()
# Check inbound messages
ic$checkMsg(wrap)

# Disconnect
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 monitoring the connection
As R is single threaded, in general it is the user's responsibility to code
some kind of event loop to periodically process incoming messages:
_i.e._ there is no background `Reader` monitoring the connection
and processing the server responses.

Two possible approaches, with or without a loop, are described:
Expand All @@ -111,18 +110,18 @@ library(rib)

# Instantiate wrapper, client and connect
wrap <- IBWrapSimple$new()
ic <- IBClient$new(wrap)
ic <- IBClient$new()
ic$connect(port=4002, clientId=1)

# Send requests, e.g.:
contract <- IBContract("GOOG")
contract <- IBContract(symbol="GOOG", secType="STK", exchange="SMART", currency="USD")
ic$reqContractDetails(11, contract)

# more requests can go here...

# Parse responses
# Might need to be called several times to exhaust all messages
ic$checkMsg()
ic$checkMsg(wrap)

# Find results in
wrap$context
Expand All @@ -145,7 +144,7 @@ library(rib)

# Instantiate wrapper, client and connect
wrap <- IBWrapSimple$new()
ic <- IBClient$new(wrap)
ic <- IBClient$new()
ic$connect(port=4002, clientId=1)

# Main loop
Expand All @@ -156,7 +155,7 @@ repeat {
ic$reqContractDetails(...)

# Wait and process responses
ic$checkMsg()
ic$checkMsg(wrap)

if(done)
break
Expand All @@ -173,33 +172,31 @@ 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 in a single thread,
it is possible to swap wrappers on the fly in a connected client.
- `new()`: create a new instance.
- `connect(host, port, clientId, connectOptions)`: establish a connection.
- `disconnect()`: terminate the connection.
- `checkMsg(timeout, flush)`: wait for responses and dispatch callbacks.
- `checkMsg(wrap, timeout)`: wait for responses and dispatch callbacks defined
in `wrap`, which must be an instance of a class derived from `IBWrap`.
If no response is available, it **blocks** up to `timeout` seconds.
If `flush=TRUE` callbacks are not dispatched.
Return the number of responses processed. **Needs to be called regularly**.
- methods that send specific requests to the server.
If `wrap` is missing, messages are taken off the wire and discarded.
Return the number of responses processed. **Needs to be called regularly!**
- methods that send requests to the server.
Refer to the official IB `EClient` class documentation for further details and
method signatures.

##### [`IBWrap`](R/IBWrap.R)
Like the official IB `EWrapper` class, this holds the callbacks that are dispatched
when responses are processed. `IBWrap` itself is a base class containing
only dummy methods.
when responses are processed. `IBWrap` itself contains only stubs.
Users need to derive from it and override the desired methods.
The code [above](#usage) provides a quick view of the procedure.
The code [above](#usage) provides a template of the procedure.

For a more extensive example refer 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.
[`IBWrapSimple`](examples/IBWrapSimple.R), mainly provided for
illustrative purposes, which simply prints out the content of the responses
or store it within `IBWrapSimple$context` for later inspection.

For more details about callback definitions and signatures,
refer again to the official IB `EWrapper` class documentation.
refer to the official IB `EWrapper` class documentation.

### Notes
Callbacks are generally invoked with arguments and types matching the signatures
Expand All @@ -226,21 +223,21 @@ are **not** used in this package.
`marketRule()` and the `historicalTicks*()` family.

##### Missing Values
Occasionally there is the need for numerical types to represent
Occasionally, for numerical types, there is the need to represent
the lack of a value.

The IB API does not adopt a uniform solution for all situations, but rather
various sentinel values are used.
IB API does not have a uniform solution across the board, but rather
it adopts a variety of sentinel values.
They can be either the plain `0` or the largest representable value
of a given type such as `2147483647` and `9223372036854775807`
for 32 and 64 bit integers respectively or `1.7976931348623157E308`
for 64 bit floating point.
for 32- and 64-bit integers respectively or `1.7976931348623157E308`
for 64-bit floating point.

Within this package an effort is made to replace all these values with
R built-in `NA`.
This package makes an effort to use R built-in `NA`
in all circumstances.

##### Data Structures
Other classes that mainly hold data are also [defined](R/structs.R).
Other classes that mainly hold data are also [replicated](R/structs.R).
They are implemented as R lists, possibly nested, with names, types and default values
matching the IB API counterparts: _e.g._
`Contract`, `Order`, `ComboLeg`, `ExecutionFilter`, `ScannerSubscription`
Expand All @@ -253,9 +250,9 @@ contract$conId <- 12345
contract$currency <- "USD"
```
In the case of `Contract` and `Order`, helper [functions](R/factory.R)
are also provided to prefill some common fields:
are also provided to simplify the assignment to a subset of the fields:
```R
contract <- IBContract("GOOG")
contract <- IBContract(symbol="GOOG", secType="STK", exchange="SMART", currency="USD")

# Equivalent to
contract <- Contract
Expand All @@ -266,7 +263,7 @@ contract$currency <- "USD"
```
and
```R
order <- IBOrder(totalQuantity=100, lmtPrice=50)
order <- IBOrder(action="BUY", totalQuantity=100, orderType="LMT", lmtPrice=50)

# Equivalent to
order <- Order
Expand Down
2 changes: 1 addition & 1 deletion R/IBWrapSimple.R → examples/IBWrapSimple.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
IBWrapSimple <- R6Class("IBWrapSimple",
IBWrapSimple <- R6::R6Class("IBWrapSimple",

class= FALSE,
cloneable= FALSE,
Expand Down
71 changes: 71 additions & 0 deletions man/IBClient.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
\name{IBClient}
\alias{IBClient}
\docType{class}

\title{Client Connection Class}

\description{
This is the main class that manages the connection with the
'Trader Workstation', sends requests and handles responses.
}

\section{Methods}{
\itemize{

\item \code{IBClient$new()}: creates a new instance.

\item \code{$connect(host="localhost", port, clientId, connectOptions="")}:
connects to \code{host:port} and performs the initial
handshake using client identifier \code{clientId} and additional
options \code{connectOptions}.

\item \code{$checkMsg(wrap, timeout=0.2)}: waits for and process server messages.
When available, messages are decoded and handed over to the appropriate
callback defined in \code{wrap}, which must be an instance of a child of
\code{IBWrap}.
If \code{wrap} is missing, messages are read and immediately discarded.
Returns the number of messages processed.

This methods \bold{blocks} up to \code{timeout} seconds.
\bold{Needs to be called regularly}.

\item \code{$disconnect()}: terminates the connection.
}

This class is modeled after the class \code{EClient} from the official IB API
implementations.
In addition to the methods shown above, several others exist that are used to send
requests to the server.

Refer to the official documentation for a comprehensive list of the possible
requests, including their signatures and descriptions.
}

\seealso{
\code{\link{IBWrap}}.

\href{https://interactivebrokers.github.io/tws-api/classIBApi_1_1EClient.html}{\code{EClient}}
definition from the official documentation.
}


\examples{
\dontrun{
# Instantiate a wrapper
wrap <- IBWrapSimple$new()

# Create a client and connect to a server
ic <- IBClient$new()
ic$connect(port=4002, clientId=1)

# Make a request
stock <- IBContract(symbol="GOOG", secType="STK", exchange="SMART", currency="USD")
ic$reqContractDetails(11, stock)

# Process responses
ic$checkMsg(wrap)

# Disconnect
ic$disconnect()
}
}
Loading

0 comments on commit 455a514

Please sign in to comment.