Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Live updating dataframe #9

Open
KKel414 opened this issue Aug 25, 2020 · 5 comments
Open

Live updating dataframe #9

KKel414 opened this issue Aug 25, 2020 · 5 comments

Comments

@KKel414
Copy link

KKel414 commented Aug 25, 2020

Hello, I have the following code that I am using to stream data, and hopefully create a live updating plot in R.

Can you please guide me on how I can export the wrap$context$historical field into a R dataframe that is steadily updated as the streamed data comes through?

library(rib)

tickers <- c("AAPL", "GOOG")

wrap <- IBWrapSimple$new()
ic   <- IBClient$new(wrap)

ic$connect(port=7497, clientId=5)

for(i in 1:length(tickers))
  ic$reqHistoricalData(i, IBContract(tickers[i]), endDateTime = "", durationStr = "1 M", barSizeSetting = "1 day", useRTH = "1", 
                       whatToShow = "TRADES", keepUpToDate = TRUE, formatDate = "1")

repeat
  ic$checkMsg()

@lbilli
Copy link
Owner

lbilli commented Aug 25, 2020

Here's a very quick idea on how to keep historical dataframes up to date.
For semplicity, I'll store them in a list indexed the same way as tickers to make it trivial to map
ticker -> reqId -> data.frame.

library(rib)

# derive a new wrapper with customized historicalData() and historicalDataUpdate()
IBWrapTest <- R6::R6Class("IBWrapTest",

  inherit= IBWrapSimple,

  public= list(
  
    initialize= function() 
                  # list holding the data.frames
                  self$context$dflist <- list(), 
    
    historicalData= function(reqId, bar) 
                      # store initial history
                      self$context$dflist[[reqId]] <- bar,
                      
    historicalDataUpdate= function(reqId, bar) {
    
                            df <- self$context$dflist[[reqId]]
                            n <- nrow(df)

                            if(bar$time == df$time[n])
                              # update the last bar
                              self$context$dflist[[reqId]][n, ] <- bar
                              
                            else   
                              # bar has changed, append a new one
                              self$context$dflist[[reqId]] <- rbind(df, bar)
                          }    
  )
)

wrap <- IBWrapTest$new()
ic   <- IBClient$new(wrap)

ic$connect(port=7497, clientId=5)

tickers <- c("AAPL", "GOOG")

for(i in 1:length(tickers))
  ic$reqHistoricalData(i, IBContract(tickers[i]), "", "1 D", "5 mins", "TRADES", TRUE, 1, TRUE)

repeat {
  # keep history up-to-date
  ic$checkMsg()

  # do something with it
  wrap$context$dflist[[1]]  # AAPL
  wrap$context$dflist[[2]]  # GOOG
}

@KKel414
Copy link
Author

KKel414 commented Aug 26, 2020

@lbilli many thanks - I see the logic, and makes sense to me.

I ran into the following error - any further guidance you can provide me?

Error in wrap$context$dflist[[1]] : subscript out of bounds

@lbilli
Copy link
Owner

lbilli commented Aug 26, 2020

It's difficult to say from here.
But as dflist is initialized as an empty list, you'd get that error if you try to access its elements, e.g. dflist[[1]] before any data is received and historicalData() invoked.

@KKel414
Copy link
Author

KKel414 commented Sep 25, 2020

Many thanks again @lbilli - data download and updating works like a charm.

One further question I may ask is how do you place orders in the rib framework assuming we use the above constantly updating dataframe code?

I did the following, namely inserted the calls to orderId1 and orderId2 and then the # Send order section in the loop, but it comes out with a Error: 1 103 Duplicate order id issue.

What I ultimately want to do is pull in the wrap$context$dflist[[1]] and wrap$context$dflist[[2]] into a separate function I have written, and to place trades if the ratio of the prices exceeds a certain level. There would be two trades - one long and one short. So I am confused how orderId would work.

wrap <- IBWrapTest$new()
ic   <- IBClient$new(wrap)

ic$connect(port=7497, clientId=5)

tickers <- c("AAPL", "GOOG")

# Define contract
contract1 <- IBContract("GOOG")
contract2 <- IBContract("AAPL")

# Define order
order1 <- IBOrder("BUY", 10, "LMT", 1000)

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

order2 <- IBOrder("SELL", 10, "LMT", 1000)

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

for(i in 1:length(tickers))
  ic$reqHistoricalData(i, IBContract(tickers[i]), "", "1 D", "5 mins", "TRADES", TRUE, 1, TRUE)

repeat {
  # keep history up-to-date
  ic$checkMsg()
  
  # do something with it
  wrap$context$dflist[[1]]  # AAPL
  wrap$context$dflist[[2]]  # GOOG
  
  # Send order
  ic$placeOrder(orderId1, contract1, order1)
  ic$placeOrder(orderId2, contract2, order2)
  
  # Check messages
  ic$checkMsg()
  
}

@lbilli
Copy link
Owner

lbilli commented Sep 25, 2020

As per IB API documentation, each new Order needs a unique orderId that is greater than any previous Order. The orderId can be reused to modify existing orders.

Upon connection, the server always responds with nextValidId() which contains the first orderId that can be used.
If using a variation of IBWrapSimple/IBWrapTest, that number is stored in wrap$context$nextId.
So, the logic to send orders should be something like:

wrap <- IBWrapTest$new()
ic   <- IBClient$new(wrap)

ic$connect(port=7497, clientId=5)

# wait to make sure you receive all initial messages
Sys.sleep(1)
ic$checkMsg()

orderId <- wrap$context$nextId

[...]

# send first order
ic$placeOrder(orderId, contract1, order1)
orderId <- orderId + 1

[...]

# send another order
ic$placeOrder(orderId, contract2, order2)
orderId <- orderId + 1

[...]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants