1

I'm using a combination of Python and R to do stock market analysis, using Interactive Brokers for data retrieval. Interactive Brokers supports a Python API, but not an R API, so I'm using Python calls to interact with Interactive Brokers and then convert the data to R. However, I've been plagued trying to convert the Python data structures to R data frames. In this example, I'm subscribing to a real-time tick data feed and trying to convert the data to a data frame. I've tried using pandas on the Python side, which kind of works, but gives me environment variables, rather than the data I want to see. When I try to convert the data on the R side, I get: "Error in as.data.frame.default(x[[i]], optional = TRUE) : cannot coerce class ‘c("ib_insync.objects.TickByTickAllLast", "python.builtin.tuple", ’ to a data.frame"

Here's my R code:

library(reticulate)
use_python("/usr/local/bin/python3.7")
source_python("testPythonCalls.py")

# Connect to IB
connection <- ibConnect(as.integer(7497),as.integer(600))
# Set up the NQ Futures contract

contract <- ibFuturesContract('NQ',as.integer(20210319),'GLOBEX')
# Subscribe to Real Time Bars
# Request Tick by Tick Data
#Subscribe to tick-by-tick data and return the Ticker that holds the ticks in ticker.tickByTicks.
#Parameters:    contract (Contract) – Contract of interest.
#tickType (str) – One of ‘Last’, ‘AllLast’, ‘BidAsk’ or ‘MidPoint’.
#numberOfTicks (int) – Number of ticks or 0 for unlimited.
#ignoreSize (bool) – Ignore bid/ask ticks that only update the size.
#Return type:   Ticker
ticks <- ibReqTickByTickData(contract, 'Last', as.integer(0), TRUE)

# Show the ticks
print (ticks)

# Here's my attempt to convert the list to a data frame on the R side
df <- as.data.frame(as.list(ticks))

# Here's my attempt to convert the data to a data frame on the Python side
df <- ibTickByTickDataDF(ticks)
print (df)

# Turn off real time feed
ibCancelTickByTickData(contract,'Last')
# Disconnect
ibDisconnect()

Here's my Python code:

from ib_insync import *
import pandas as pd

# Connect to IB; args are (IP address, device number, client ID)
def ibConnect(port,clientID):
  ib.sleep(0)
  connectAttempts=0
  while not ibIsConnected():
    connectAttempts += 1
    connection = ib.connect('127.0.0.1', port, clientID)
    ib.sleep(0)
    if connectAttempts > 10:
      print ("Unable to connect to Interactive Brokers")
  return ()

# Disconnect from IB  
def ibDisconnect():
  ib.disconnect()
  ib.sleep(0)
  return

# Check to see if IB is connected  
def ibIsConnected():
  isConnected = ib.isConnected()
  return isConnected

# Set up a futures contract
def ibFuturesContract(symbol, expirationDate, exchange):
  futuresContract = Future(symbol, expirationDate, exchange)
  return futuresContract

#Subscribe to tick-by-tick data and return the Ticker that holds the ticks in ticker.tickByTicks.
#Parameters:    contract (Contract) – Contract of interest.
  #tickType (str) – One of ‘Last’, ‘AllLast’, ‘BidAsk’ or ‘MidPoint’.
  #numberOfTicks (int) – Number of ticks or 0 for unlimited.
  #ignoreSize (bool) – Ignore bid/ask ticks that only update the size.
#Return type:   Ticker
def ibReqTickByTickData(contract, tickType, numberOfTicks, ignoreSize):
  ibTicks = ib.reqTickByTickData (contract, tickType, numberOfTicks, ignoreSize)
  ib.sleep(2)
  return (ibTicks.tickByTicks)

# Convert the Tick By Tick Data to a data frame
def ibTickByTickDataDF(ticks):
  df = pd.DataFrame (ticks)
    #index=[time],
    #columns=[bid,bidsize,ask,askSize,last, lastSize,prevBid, prevBidSize, prevAsk, prevAskSize, prevLast, prevLastSize, volume, open, high, low, close,halted])
#    index=[ticks.time], columns=['time', 'bid', 'bidSize'])
#  df.loc[0]=(ticks.time, ticks.price, ticks.size)
  return (df)

# Unsubscribe from tick by tick data
def ibCancelTickByTickData(contract, tickType):
  ib.cancelTickByTickData(contract, tickType)
  return

ib = IB()
global ibTicks
S Novogoratz
  • 388
  • 2
  • 14
  • 1
    The IBrokers R package on CRAN provides an interface to the IB API. – G. Grothendieck Mar 11 '21 at 19:43
  • 1
    @G. Grothendieck Yes, I had been using the IB API from CRAN and found it to be simple and straightforward with some known drawbacks. First, it does not have the full functionality I need for my application, such as multi-threading for data subscriptions. Also, it's not officially supported by IB, which had been problematic when I ran into some issues. – S Novogoratz Mar 11 '21 at 20:46
  • try `tibble::enframe()` instead of `as.data.frame()` and then proceed with rectangling and type casting. – Balthasar Apr 11 '21 at 21:52
  • @Balthasar Here's what I get using the data that came back from my call. > tib <- tibble::enframe(as.list(ticks)) Error in as.vector(x, "list") : cannot coerce type 'environment' to vector of type 'list' – S Novogoratz Apr 13 '21 at 15:01

0 Answers0