Path: blob/master/finrl/meta/preprocessor/ibkrdownloader.py
732 views
"""Contains methods and classes to collect data from1interactive broker API2"""34from __future__ import annotations56import math7from datetime import datetime89import pandas as pd10from ib_insync import *111213class ibkrdownloader:14"""Provides methods for retrieving daily stock data from15IBKR API1617Attributes18----------19start_date : str20start date of the data (modified from neofinrl_config.py)21end_date : str22end date of the data (modified from neofinrl_config.py)23ticker_list : list24a list of stock tickers (modified from neofinrl_config.py)25interval: str26ime period of one bar. Must be one of:27'1 secs', '5 secs', '10 secs' 15 secs', '30 secs',28'1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',29'20 mins', '30 mins',30'1 hour', '2 hours', '3 hours', '4 hours', '8 hours',31'1 day', '1 week', '1 month'.3233Methods34-------35fetch_data()36Fetches data from IBKR API37"""3839def __init__(40self,41start_date: str,42end_date: str,43ticker_list: list,44interval="1 day",45host="127.0.0.1",46port=7497,47clientId=999,48) -> None:49self.start_date = start_date50self.end_date = end_date51self.ticker_list = ticker_list52self.interval = interval53self.host = host54self.port = port55self.clientId = clientId5657def createContract(self, ticker):58contract = Stock(ticker, "SMART", "USD")59return contract6061def connect2ibkr(self):62self.ib = IB()63self.ib.connect(self.host, self.port, clientId=self.clientId)6465def calculate_duration(self, start_date_str, end_date_str):66start_date = datetime.strptime(start_date_str, "%Y-%m-%d")67end_date = datetime.strptime(end_date_str, "%Y-%m-%d")6869duration_days = (end_date - start_date).days7071return duration_days7273def fetch_data(self) -> pd.DataFrame:74"""Fetches data from IBKR API75Parameters76----------7778Returns79-------80`pd.DataFrame`817 columns: A date, open, high, low, close, volume and tick symbol82for the specified stock ticker83"""84# Download and save the data in a pandas DataFrame:85self.connect2ibkr()86data_df = pd.DataFrame()87duration = self.calculate_duration(self.start_date, self.end_date)88if duration > 365:89duration = f"{math.ceil(duration / 365)} Y"90else:91duration = f"{duration} D"9293end_date_time = datetime.strptime(self.end_date, "%Y-%m-%d")94for tic in self.ticker_list:95contract = self.createContract(tic)96self.ib.qualifyContracts(contract)97bars = self.ib.reqHistoricalData(98contract,99endDateTime=end_date_time,100durationStr=duration,101barSizeSetting=self.interval,102whatToShow="TRADES",103useRTH=False,104formatDate=1,105)106temp_df = util.df(bars)107print(f"************* {tic} *************")108temp_df["tic"] = [tic] * len(temp_df)109data_df = pd.concat([data_df, temp_df], ignore_index=True)110data_df = data_df[["date", "open", "high", "low", "close", "volume", "tic"]]111filter_df = data_df[data_df["date"] > pd.Timestamp(self.start_date).date()]112filter_df = filter_df.sort_values(by=["date", "tic"])113filter_df.index = filter_df["date"].factorize()[0]114115self.disconnect()116return filter_df117118def disconnect(self):119self.ib.disconnect()120121def select_equal_rows_stock(self, df):122df_check = df.tic.value_counts()123df_check = pd.DataFrame(df_check).reset_index()124df_check.columns = ["tic", "counts"]125mean_df = df_check.counts.mean()126equal_list = list(df.tic.value_counts() >= mean_df)127names = df.tic.value_counts().index128select_stocks_list = list(names[equal_list])129df = df[df.tic.isin(select_stocks_list)]130return df131132133if __name__ == "__main__":134intr = ibkrdownloader(135"2023-01-01", "2023-04-12", ["AAPL", "MSFT", "CSCO", "WMT", "TSLA"]136)137try:138df = intr.fetch_data()139df.to_csv("data.csv", index=False)140except:141intr.disconnect()142143intr.disconnect()144145146