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