I want to use IBAPI to get historical stock data. My code does not work and returns nothings. Can anybody help me edit the code? Thanks
from ibapi import client
from ibapi import wrapper
import datetime
from ibapi.contract import Contract
from ibapi.common import BarData
# ! [socket_init]
class App(wrapper.EWrapper,client.EClient):
def __init__(self):
wrapper.EWrapper.__init__(self)
client.EClient.__init__(self, wrapper=self)
#Build a sample contract
contract = Contract();
contract.symbol = "9005.T";
contract.secType = "STK";
contract.currency = "JPY";
contract.exchange = "SMART";
app = App()
app.connect(host='localhost',port=7497, clientId=3)
print(app.isConnected())
queryTime = (datetime.datetime.today() - datetime.timedelta(days=180)).strftime("%Y%m%d %H:%M:%S")
print(app.reqHistoricalData(4102, contract, queryTime,"1 M", "1 day", "MIDPOINT", 1, 1, False, []))
queryTime = (datetime.datetime.today() - datetime.timedelta(days=180)).strftime("%Y%m%d %H:%M:%S")
print(app.historicalData(4102,BarData))
OUTPUT:
True
None
None
I tried to read the source code. But I found it is quite difficult to understand for me. Other posts showed the answer that appears not relevant to the newest api version.
Here's what I would do.
class App(wrapper.EWrapper,client.EClient): I would only subclass EClient if I wanted to override any of it's methods. I don't use python very much but it's like that in other languages.
Inside the class App you need to override the methods you are interested in like historicalData
After app.connect you must call app.run() to start it's message reader thread. Once that thread takes control it will block in your program so you must do program flow asynchronously.
I will put numbers in comments so you see the flow.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.common import BarData
import datetime
class MyWrapper(EWrapper):
def nextValidId(self, orderId:int):
#4 first message received is this one
print("setting nextValidOrderId: %d", orderId)
self.nextValidOrderId = orderId
#5 start requests here
self.start()
def historicalData(self, reqId:int, bar: BarData):
#7 data is received for every bar
print("HistoricalData. ReqId:", reqId, "BarData.", bar)
def historicalDataEnd(self, reqId: int, start: str, end: str):
#8 data is finished
print("HistoricalDataEnd. ReqId:", reqId, "from", start, "to", end)
#9 this is the logical end of your program
app.disconnect()
print("finished")
def error(self, reqId, errorCode, errorString):
# these messages can come anytime.
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def start(self):
queryTime = (datetime.datetime.today() - datetime.timedelta(days=180)).strftime("%Y%m%d %H:%M:%S")
fx = Contract()
fx.secType = "CASH"
fx.symbol = "USD"
fx.currency = "JPY"
fx.exchange = "IDEALPRO"
#6 request data, using fx since I don't have Japanese data
app.reqHistoricalData(4102, fx, queryTime,"1 M", "1 day", "MIDPOINT", 1, 1, False, [])
app = EClient(MyWrapper()) #1 create wrapper subclass and pass it to EClient
app.connect("127.0.0.1", 7497, clientId=123) #2 connect to TWS/IBG
app.run() #3 start message thread
Related
I'm trying to access Historical data of API Interactive brokers but I can't get the data.
My code looks like this:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import datetime
class TestApp(EClient, EWrapper):
def __init__(self):
EClient.__init__(self, self)
def nextValidId(self, orderId: int):
# Get the current year and month
now = datetime.datetime.now()
year = now.year
month = now.month
contract = Contract()
contract.symbol = "ES"
contract.secType = "FUT"
contract.exchange = "GLOBEX"
contract.currency = "USD"
contract.localSymbol = "ESZ7" # Set the local symbol
self.reqHistoricalData(orderId, contract, "", "1 D", "1 hour", "TRADES", 0, 1, True, [])
def historicalData(self, reqId, bar):
print(f"Historical data: {bar}")
def historicalDataEnd(self, reqId, start, end):
print("End of HistoricalData")
print(f"Start: {start}, End: {end}")
app = TestApp()
app.connect('127.0.0.1', 7497, 1)
app.run()
And I get the following error:
ERROR 1 200 No security definition has been found for the request
I have real times running on the futures contracts, do I need to activate another authorization in addition?
I would be very grateful if someone here could help me solve the problem.
The solution is:
I had to change contract.exchange = "GLOBEX" to contract.exchange = "CME"
I had to add the following line:
contract.lastTradeDateOrContractMonth = "202303"
i am new to Interactive brokers API, wondering if there is any way to get quote of NIFTY50 index, as i can see examples of NIFTY FUTURES, etc but not on index price quote of NIFTY50 or BANKNIFTY,
need help with some example, thanks,
sample on on getting quote of NIFTY OPTIONS,
from locale import currency
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.ticktype import TickTypeEnum
from ibapi.common import *
import threading
import time
def get_close_quote(symbol, secType='OPT', exchange='NSE', currency='INR'):
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
def historicalData(self, reqId, bar):
print(f'Time: {bar.date} Close: {bar.close}')
def tickPrice(self, reqId, tickType, price, attrib):
if tickType == TickTypeEnum.LAST or tickType == TickTypeEnum.DELAYED_LAST:
self.last = price;
self.disconnect()
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
time.sleep(1) #Sleep interval to allow time for connection to server
#Create contract object
contract = Contract()
contract.localSymbol = symbol
contract.secType = secType
contract.exchange = exchange
contract.currency = currency
app.reqMktData(100, contract, "", False, False, None)
time.sleep(2) #sleep to allow enough time for data to be returned
app.disconnect()
return(app.last)
I am not familiar with Interactive brokers API but from digging on their website I did find those useful commands. You are welcome to check more than provided in this answer.
If you are trying to get a different type of security, as per the documentation, you would change the contract.secType to one of the following:
The security's type: STK - stock (or ETF) OPT - option FUT - future
IND - index FOP - futures option CASH - forex pair BAG - combo WAR -
warrant BOND- bond CMDTY- commodity NEWS- news FUND- mutual fund.
As I understood, you also want to get the actual price as part of the request for example last price is tick id = 4 as seen on the documentation of different types, and in general only have to request for specific ticks.
In reqMktData the genericTickList (3rd parameter) can be used to specify extra ticks to monitor, like demonstrated in documentation:
# Requesting RTVolume (Time & Sales) and shortable generic ticks
self.reqMktData(1004, ContractSamples.USStockAtSmart(), "233,236", False, False, [])
Where "233, 236" are the specified ticks to get from the website.
Also when checking the contract documentation, you can acquire the Strike price from the contract object.
I was able to piece together a script from IB's documentation/examples and forums on this site. I am getting the output I want for a single symbol, however, if I use a list of stocks, I cannot figure out a way to pass the ticker symbol through to the DF output file. My workaround was to create a dictionary that uses the list sequence (see below) however the output from IB's api changes slightly each time rendering the symbols mostly pointless. The list i am using below normally has 20+ names but may change, i cut it down to make it easier to view.
#Brian/and or other developers, if there is a way to create either a unique ID/sequence for each symbol call and stamp it to data that is brought back, i can then utilize a dictionary to apply the symbol. In the other forum, you passed in a line where n_id = n_id +1, if that can be applied and is linked to each specific call which is done in order of the list, then that could work?
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import threading
import time
from datetime import timedelta
import datetime
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = [] #Initialize variable to store candle
def historicalData(self, reqId, bar):
#print(f'Time: {bar.date} Close: {bar.close} Volume: {bar.volume}',reqId)
self.data.append([bar.date, bar.close, bar.volume, reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
time.sleep(1) #Sleep interval to allow time for connection to server
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND"
app.reqHistoricalData(1, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
time.sleep(5) #sleep to allow enough time for data to be returned
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','reqId'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s') #,unit='s')
df['Count'] = df.groupby('DateTime').cumcount()+1
sym_dict = {1:'SPY',2:'MSFT',3:'GOOG',4:'AAPL',5:'QQQ',6:'IWM',7:'TSLA'}
df['Ticker'] = df['Count'].map(sym_dict)
print(df)
#edit, adding in #Brian's detail:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import time
from datetime import timedelta
import datetime
start = datetime.datetime.utcnow()
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = []
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def historicalData(self, reqId, bar):
self.data.append([bar.date, bar.close, bar.volume, sym_dict[reqId]])
print("HistoricalData. ReqId:", sym_dict[reqId], "BarData.", bar)
# include this callback to track progress and maybe disconnectwhen all are finished
def historicalDataEnd(self, reqId: int, start: str, end: str):
print("finished", sym_dict[reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
# you should wait for nextValidId instead of sleeping, what if it takes more than 1 second? #john: how do i do this?
time.sleep(5) #john: how do i do this? wait for nextValidId?
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
reqId = 1
sym_dict = {}
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
sym_dict[reqId] = sym
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND" # you may need this for msft
app.reqHistoricalData(reqId, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
reqId += 1
time.sleep(5)
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','sym'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s') #,unit='s')
df = df.set_index(['sym','DateTime']).sort_index()
print(df)
app.disconnect()
You just need to maintain a dict of reqId and symbol.
I'm not sure that one DataFrame is the best way to store your data but if you do then set a multi index. Decide how much data you want and how you're going to store it on disk and then decide on a data structure. I suggest csv for speed or sqlite for simplicity. Pandas can handle either.
I deleted your comments and added some of my own.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import threading
import time
from datetime import timedelta
import datetime
# I added this code to get fake data, works wtihout tws running
from ibapi.common import BarData
from random import random
start = datetime.datetime.utcnow()
def fake_data(reqId, ib):
last = reqId*10
for i in range(60, 0, -10):
bar = BarData();
bar.date = start - timedelta(minutes=i)
last += random() - 0.5
bar.close = last
bar.volume = reqId * 1000
ib.historicalData(reqId, bar)
ib.historicalDataEnd(reqId,"","")
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = []
#always include this for important messages, also turn on api logging in TWS/IBG
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def historicalData(self, reqId, bar):
self.data.append([bar.date, bar.close, bar.volume, sym_dict[reqId]])
# include this callback to track progress and maybe disconnectwhen all are finished
def historicalDataEnd(self, reqId: int, start: str, end: str):
print("finished", sym_dict[reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
# threading is needed only if you plan to interact after run is called
# this is a good way if you use a ui like jupyter
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
# you should wait for nextValidId instead of sleeping, what if it takes more than 1 second?
time.sleep(1)
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
reqId = 1
sym_dict = {}
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
sym_dict[reqId] = sym
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND" # you may need this for msft
#app.reqHistoricalData(reqId, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
fake_data(reqId, app)
reqId += 1
#now you need to sleep(10) to make sure you don't get a pacing error for too many requests
# don't sleep, use historicalDataEnd to know when finished
time.sleep(5)
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','sym'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s')
#make an index and sort
df = df.set_index(['sym','DateTime']).sort_index()
# now you can use the indexes
print(df.loc[("SPY","2021")])
#don't forget to disconnect somewhere or the clientId will still be in use
I am downloading 15Y of data (daily close) for 5 stocks ('A','AAP','AAPL','ABBV','ABC'). The issue is that I got some repetitions. No issue for the first one ,'A', I got the right amount of data. For the second one,'AAP', I have twice the right number of rows, it seems the data were downloaded twice. Same issue for the last 3 stocks for which I have three times the right number of rows. I have attached a screenshot showing the size of the csv files, these files should have the same size if everything was fine.
I suspect that the issue comes from the 10 seconds pause after calling reqHistoricalData; it may be too long. How could I avoid having duplicated rows and how to pause the right amount of time (not too long and not too short)?
import pandas as pd
import datetime as dt
import time
import collections
import threading
import os
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.common import BarData
path = r"D:\trading\data\debug\\"
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data=collections.defaultdict(list)
def nextValidId(self, orderId: int):
super().nextValidId(orderId)
self.nextorderId = orderId
print('The next valid order id is: ', self.nextorderId)
def error(self, reqId, errorCode, errorString):
super().error(reqId, errorCode, errorString)
print("Error. Id:", reqId, "Code:", errorCode, "Msg:", errorString)
def historicalData(self, reqId:int, bar:BarData):
self.data["date"].append(bar.date)
self.data["close"].append(bar.close)
self.df = pd.DataFrame.from_dict(self.data)
tickers = ["A","AAP","AAPL","ABBV","ABC"]
def run_loop():
app.run()
app = IBapi()
app.connect("127.0.0.1", 7496, 5)
app.nextorderId = None
# Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
# Check if the API is connected via orderid
while True:
if isinstance(app.nextorderId, int):
print('connected')
break
else:
print('waiting for connection')
time.sleep(1)
n_id = app.nextorderId
for ticker in tickers:
contract = Contract()
contract.symbol = ticker
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
app.reqHistoricalData(n_id, contract, "","15 Y", "1 day", "TRADES", 1, 1, False, [])
time.sleep(10)
app.df.to_csv(path + ticker + ".csv")
n_id = n_id + 1
app.disconnect()
You don't clear the list in between requests.
def historicalData(self, reqId:int, bar:BarData):
# just keeps adding data to list
self.data["date"].append(bar.date)
self.data["close"].append(bar.close)
# makes a new dataframe on every single bar
self.df = pd.DataFrame.from_dict(self.data)
In the historicalDataEnd method you can make a dataframe and save it to a file. Make a dict of tickers and reqId's so you know which ticker is finished.
You should still have a 10 second delay in between calls for pacing but do not count on data being returned within 10 seconds. If it doesn't arrive, you will get an empty file (or in your case, all the previous tickers data, which seems to have happened with ABC).
Your duplicates come every Friday. You make a request for, say Friday (1st iteration) and in the next 2 iterations (which are Saturday and Sunday) the API returns data from the first possible trading day (last Friday). Otherwise 5 seconds is enough time to wait.
This is the code attempting to retrieve AAPL delayed stock price via Interactive Broker (IB) TWS.
However, none of data is retrieved.
As you can see, app.reqMarketDataType(3) has been called to set delayed data. (3 is delay)
I've logged into demo account in IB TWS and ensured "Enable ActiveX and Socket client" is selected.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import threading
import time
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
def tickPrice(self, reqId, tickType, price, attrib):
if tickType == 2 and reqId == 1:
print('The current ask price is: ', price)
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7497, 123)
#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
time.sleep(1) #Sleep interval to allow time for connection to server
#Create contract object
apple_contract = Contract()
apple_contract.symbol = 'AAPL'
apple_contract.secType = 'STK'
apple_contract.exchange = 'SMART'
apple_contract.currency = 'USD'
#Request Market Data
app.reqMarketDataType(3)
app.reqMktData(1, apple_contract, '', False, False, [])
time.sleep(10) #Sleep interval to allow time for incoming price data
app.disconnect()
The code works ok. The problem is you don't print unless you get tickType 2(real time ask), delayed ask is tickType 67.
https://interactivebrokers.github.io/tws-api/tick_types.html