def reqMktData(tickerList, client, waitTime): ib = insync.IB() contractList = [] ib.connect('127.0.0.1', 7497, clientId=client) for ticker in tickerList: ticker = ticker.rstrip().upper() contract = insync.Stock(ticker, "SMART", "USD") ib.qualifyContracts(contract) ib.reqMktData(contract, "", False, False) contractList.append({"ticker": ticker, "contract": contract}) ib.sleep(5) while True: t = copy.copy(dt.datetime.now()) tWait = copy.copy(t + dt.timedelta(seconds=waitTime)) for contract in contractList: fileName = "{}_mkt.npy".format(contract["ticker"]) print("{} - STREAMING {}".format(dt.datetime.now(), contract["ticker"])) np.save(fileName, ib.ticker(contract["contract"])) t = copy.copy(dt.datetime.now()) sleepTime = (tWait - t).total_seconds() ib.sleep(sleepTime)
async def initialize_ib_connection(self): self.ib = ibs.IB() try: await self.ib.connectAsync('127.0.0.1', Config['ib_port']) except asyncio.TimeoutError: raise JobError('IB Gateway is not online') self.logger.info(f'IB connected')
def get_cached_ib_client( username: str, password: str, host: str = "127.0.0.1", port: int = 4001, connect=True, timeout=90, ) -> ib_insync.IB: """ Cache and return a InteractiveBrokers HTTP client with the given key and secret. If a cached client with matching key and secret already exists, then that cached client will be returned. Parameters ---------- username : str Interactive Brokers account username password : str Interactive Brokers account password host : str, optional The IB host to connect to port : int, optional The IB port to connect to connect: bool, optional Whether to connect to IB. timeout: int, optional The timeout for trying to establish a connection Returns ------- ib_insync.IB """ global IB_INSYNC_CLIENTS, GATEWAY # Start gateway if GATEWAY is None: GATEWAY = InteractiveBrokersGateway(username=username, password=password) GATEWAY.safe_start() client_key: tuple = (host, port) if client_key not in IB_INSYNC_CLIENTS: client = ib_insync.IB() if connect: try: client.connect(host=host, port=port, timeout=timeout) except TimeoutError: raise TimeoutError( f"Failed to connect to gateway in {timeout}s") IB_INSYNC_CLIENTS[client_key] = client return IB_INSYNC_CLIENTS[client_key]
def can_test_ib() -> bool: can_test = True try: import ib_insync ib_insync.IB().connect() except (ImportError, ConnectionRefusedError): can_test = False return can_test
async def main(): tickers = ['EURUSD'] contracts = [] ib = ibs.IB() await ib.connectAsync(port=4002, clientId=2) print('----------- Starting Positions -----------') print(ib.positions()) # [ib.cancelOrder(order) for order in ib.openOrders()] # print(ib.openOrders()) # print(ib.openTrades()) for ticker in tickers: con = ibs.Forex(ticker) await ib.qualifyContractsAsync(con) contracts.append(con) bars = ib.reqRealTimeBars(contracts[0], 5, 'MIDPOINT', True) bars.updateEvent += show def print_yes(): print('yes!') ib.updateEvent += print_yes # for i in range(2): # trades = [] # # print('\n----------- New Trades -----------') # for contract in contracts: # order = ibs.MarketOrder('BUY', 10000) if i % 2 == 0 else ibs.MarketOrder('SELL', 10000) # trade = ib.placeOrder(contract, order) # trades.append(trade) # # status = await asyncio.gather(*[wait_for_fill(ib, trade) for trade in trades]) # for trade in trades: # print(trade) # print(f'{trade.contract.symbol}: {trade.orderStatus.avgFillPrice}') # if trade.fills[0].commissionReport == ibs.CommissionReport(): # await trade.commissionReportEvent # # for fill in trade.fills: # print(fill.commissionReport) # # print('Positions After Fill ...') # print(ib.positions()) # # # for fill in ib.fills(): # # await asyncio.sleep(5) await asyncio.sleep(700) # ib.cancelRealTimeBars(bars) ib.disconnect()
def main(): global ib, wb #controller = ibi.IBController('TWS', '969', 'paper', # TWSUSERID='enter username here', TWSPASSWORD='******') ib = ibi.IB() #Create an object for the caller Excel workbook and note the calling worksheet wb = xw.Book.caller() while True: # Create an dictionary initialized with account numbers and empty lists # These lists will be populated with positions for the account acccountPositionsDict = {} for accountNumber in getAccountNumberDict(): acccountPositionsDict[accountNumber] = [] # Start IB connection ib.connect('127.0.0.1', getIbConnectionPort(wb.sheets.active.name), clientId=1) # Get positions for all accounts and organize them into the dictionary of lists created above for acccountPosition in ib.positions(): acccountPositionsDict[acccountPosition.account].append([ acccountPosition.contract.localSymbol, float(acccountPosition.avgCost), float(acccountPosition.avgCost) * float(acccountPosition.position) ]) # Update the worksheets with positions for accountNumber in acccountPositionsDict: sheetName = getAccountNumberDict().get(accountNumber) #Set NVL and Cash values in Excel cells wb.sheets(sheetName).range("B1").value = accountValue( accountNumber, 'NetLiquidationByCurrency') wb.sheets(sheetName).range("D1").value = accountValue( accountNumber, 'CashBalance') acccountPositionsDict.get(accountNumber).sort() # Get the Excel cell address where "Portfolio" table begins cellAddress = wb.sheets(sheetName).tables[ sheetName + 'PortfolioTable'].data_body_range(1, 1).address wb.sheets(sheetName).range( cellAddress).value = acccountPositionsDict.get(accountNumber) # Close IB connection ib.disconnect() ib.sleep(60)
def __init__(self, port=7000, _id=100, allow_error=False, **params): ''' Initiate class and connect to TWS if possible Set port to None or False to prevent the class from automatically connecting You can call Connect to connect later ''' print('ibx loaded from ' + params.get('mess', "nowhere")) self.ib = ibi.IB() self.connected = False self.currency = params.get('currency', 'USD') self.trades = [] if port: self.Connect(port, _id, allow_error, **params)
def connect_to_ib(): # Connect to market gateway ibinstance = ib_insync.IB() ibinstance.connect(host=os.getenv('IB_GATEWAY_URLNAME', 'tws'), port=int(os.getenv('IB_GATEWAY_URLPORT', '4004')), clientId=int( os.getenv('EFP_CLIENT_ID', (5 + random.randint(0, 4)))), timeout=15, readonly=True) logging.info("Connected to IB") ibinstance.reqMarketDataType(int(os.getenv('MKT_DATA_TYPE', '4'))) return ibinstance
def get_ib_connection(host='127.0.0.1', port=4002): """ Returns a connection to Interactive Brokers. :param host: str. IP to stablish the connection with. :param port: int. Port number to stablish the connection with. :return: ib_insync.IB instance with a connection already stablished. """ client_id = np.random.randint(1, 9999) ib_connection = ib.IB() ib_connection.connect(host, port, clientId=client_id) return ib_connection
def connect_to_gateway(self): """ Create and connect IB client """ host = self.config['IB_GATEWAY_HOST'] port = self.config['IB_GATEWAY_PORT'] self.ib = ib_insync.IB() self.ib.connect(host=host, port=port, clientId=self.config['CLIENT_ID'], timeout=15, readonly=True) logger.debug("Connected to IB on {}:{}.".format(host, port)) self.ib.reqMarketDataType(self.config['MKT_DATA_TYPE'])
def client(self) -> Optional[IB.IB]: if not self._twsPort: return None if not self._client: self._client = IB.IB() self._client.connect( "127.0.0.1", port=self._twsPort, # Random client ID to minimize chances of conflict clientId=randint(1, 1000000), readonly=True, ) return self._client
def main() -> None: args = parser.parse_args() error_handler = ErrorHandlerConfiguration( report_to_gcloud=args.report_errors) configure_root_logger(args.verbose) configure_package_logger(logger, args.verbose) ib = ib_insync.IB() logger.info(f"Connecting to IB on {args.tws_host}:{args.tws_port}") ib.connect( host=args.tws_host, port=args.tws_port, clientId=random.randint(1, 2**31 - 1), readonly=True, ) # Install SIGINT handler. This is apparently necessary for the process to be interruptible with Ctrl-C on Windows: # https://bugs.python.org/issue23057 signal.signal(signal.SIGINT, signal.SIG_DFL) def handle_ib_thread_error(error: Exception) -> None: with error_handler(f"Reporting error from IB:"): try: raise error except IBWarning: logger.warning(f"Warning from IB: {error}") except ConnectionError: logger.exception(f"Connection error from IB:") thread = IBThread(ib, error_handler=handle_ib_thread_error) port = args.port or random.randint(49152, 65535) streaming_manager = StreamingManager( error_handler=error_handler, batch_size=args.streaming_batch_size, batch_timeout=args.streaming_batch_timeout, ) (servicer, server) = Servicer.start(port, thread, streaming_manager, error_handler) if args.resume: servicer.resume_streaming() logger.info(f"Server listening on port {port}") thread.run_forever()
def contract_details_cl(): # Write pickled CL contract details to a file client = ib_insync.IB() client.connect() contract = Future( instrument_id="CL", lastTradeDateOrContractMonth="20211119", exchange="NYMEX", currency="USD", ) details = client.reqContractDetails(contract) with open("contract_details_cl.pickle", "wb") as file: pickle.dump(details[0], file)
def main() -> None: args = parser.parse_args() if args.verbose: logging.basicConfig( level=logging.DEBUG if args.verbose >= 2 else logging.INFO) ib = ib_insync.IB() print(f"Connecting to IB on {args.tws_host}:{args.tws_port}") ib.connect(host=args.tws_host, port=args.tws_port, readonly=True) port = args.port or random.randint(49152, 65535) s = server.start(port, IBInSyncClient(ib), asyncio.get_event_loop()) print(f"Server listening on port {port}") # Install SIGINT handler. This is apparently necessary for the process to be interruptible with Ctrl-C on Windows: # https://bugs.python.org/issue23057 signal.signal(signal.SIGINT, signal.SIG_DFL) ib.run()
def __init__(self, port=7000, _id=100, allow_error=False, **params): print('ibx loaded from ' + params.get('mess', "nowhere")) self.ib = ibi.IB() self.connected = False try: self.ib.connect('127.0.0.1', port, _id) self.ib.reqMarketDataType(3) self.connected = True print('connected to ib at {}'.format(self.ib.reqCurrentTime())) except: message = '\n'.join(( 'Failed connecting to Interactive Brokers', 'Make sure Trader Workstation or the IB Gateway is logged in and running', 'Make sure that the API is enabled and set to port {} and id {}' .format(port, _id))) if not allow_error: print(message) import sys sys.exit() self.currency = params.get('currency', 'USD') self.trades = []
def reqHistoricalData(tickerList, client, waitTime, duration, barSize, whatToShow): ib = insync.IB() contractList = [] ib.connect('127.0.0.1', 7497, clientId=client) for ticker in tickerList: ticker = ticker.rstrip().upper() contract = insync.Stock(ticker, "SMART", "USD") ib.qualifyContracts(contract) contractList.append({"ticker": ticker, "contract": contract}) ib.sleep(5) while True: t = copy.copy(dt.datetime.now()) tWait = copy.copy(t + dt.timedelta(seconds=waitTime)) for contract in contractList: fileName = "{}_bar.npy".format(contract["ticker"]) print("{} - STREAMING {}".format(dt.datetime.now(), contract["ticker"])) bars = ib.reqHistoricalData(contract["contract"], endDateTime="", durationStr=duration, barSizeSetting=barSize, whatToShow=whatToShow, useRTH=True, formatDate=1) np.save(fileName, bars) t = copy.copy(dt.datetime.now()) sleepTime = (tWait - t).total_seconds() ib.sleep(sleepTime)
async def ib(): ib = ibi.IB() await ib.connectAsync() yield ib ib.disconnect()
def _setup(self): print('Initializing IBKR Connection...\n') # admin config = configparser.ConfigParser() # config.ini contains sensitive credentials with open('credentials.ini') as f: config.read_file(f) self.IBKR_FLEXREPORT_TOKEN = str( config['IB API']['IBKR_FLEXREPORT_TOKEN']) # initialize instance of client self.client = ib_insync.IB() if PROJECT_DB_PATH: self.conn = sqlite3.connect(PROJECT_DB_PATH) else: self.conn = sqlite3.connect(':memory:') # run creation script if DB is empty if not self.conn.cursor().execute( "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';" ).fetchall(): schema.db_creation_script(self.conn) print('Loading tradelog...') self.query_flexreport('420983', savepath=TRADELOG_PATH) self.parse_tradelog(loadpath=TRADELOG_PATH) print('Loading dividend history...') self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) self.parse_dividend_history(loadpath=DIVIDEND_HISTORY_PATH) # update tradelog if last update was more than 1 day ago try: doc = ET.parse(TRADELOG_PATH) tradelog_datetime_str = list( doc.iter('FlexStatement'))[0].attrib['whenGenerated'] tradelog_datetime = datetime.strptime(tradelog_datetime_str, '%Y%m%d;%H%M%S') except OSError: # create tradelog if it doesn't exist print('Generating Tradelog...\n') self.query_flexreport('420983', savepath=TRADELOG_PATH) tradelog_datetime = datetime.now() # update dividend history if last update was more than 1 day ago try: doc = ET.parse(DIVIDEND_HISTORY_PATH) dividend_history_datetime_str = list( doc.iter('FlexStatement'))[0].attrib['whenGenerated'] dividend_history_datetime = datetime.strptime( dividend_history_datetime_str, '%Y%m%d;%H%M%S') except OSError: # create dividend history if it doesn't exist print('Generating Dividend History...\n') self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) dividend_history_datetime = datetime.now() # if there are new entries, parse the updated tradelog into db print('Checking Tradelog...') if (datetime.now() - tradelog_datetime).days > 0: self.query_flexreport('420983', savepath=TRADELOG_PATH) print('Updating Tradelog...') self._update_tradelog_db(last_updated=tradelog_datetime) print('Tradelog is up-to-date\n') # if there are new entries, parse the updated dividend history in db print('Checking Dividend History..') if (datetime.now() - dividend_history_datetime).days > 0: self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) print('Updating Dividend History...') self._update_dividend_history_db( last_updated=dividend_history_datetime) print('Dividend History is up-to-date\n') print('IBKR Connection Successfully Established\n')
import ib_insync as ibs ib = ibs.IB() ib.connect('127.0.0.1', 4001, clientId=1) print(ib.positions()) ib.disconnect()
def _setup(self): print('Initializing IBKR Connection...\n') # admin config = configparser.ConfigParser() # config.ini contains sensitive credentials with open('credentials.ini') as f: config.read_file(f) self.IBKR_FLEXREPORT_TOKEN = str( config['IB API']['IBKR_FLEXREPORT_TOKEN']) # initialize instance of client self.client = ib_insync.IB() if PROJECT_DB_PATH: self.conn = sqlite3.connect(PROJECT_DB_PATH) else: self.conn = sqlite3.connect(':memory:') last_trade_datetime = None last_dividend_date = None # run creation script if DB is empty if not self.conn.cursor().execute( "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%';" ).fetchall(): schema.db_creation_script(self.conn) print('Loading tradelog...') self.query_flexreport('420983', savepath=TRADELOG_PATH) self.parse_tradelog(loadpath=TRADELOG_PATH) last_trade_datetime = datetime.now() print('Loading dividend history...') self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) self.parse_dividend_history(loadpath=DIVIDEND_HISTORY_PATH) last_dividend_date = datetime.now() # update tradelog if last update was more than 1 day ago if not last_trade_datetime: last_trade_datetime = datetime.strptime( queries.execute_sql(self.conn, queries.sql_get_last_trade_datetime)[0][0], '%Y-%m-%d %H:%M:%S') try: doc = ET.parse(TRADELOG_PATH) except OSError: # create tradelog if it doesn't exist print('Generating Tradelog...\n') self.query_flexreport('420983', savepath=TRADELOG_PATH) # update dividend history if last update was more than 1 day ago if not last_dividend_date: last_dividend_date = datetime.strptime( queries.execute_sql( self.conn, queries.sql_get_last_dividend_datetime)[0][0], '%Y-%m-%d') try: doc = ET.parse(DIVIDEND_HISTORY_PATH) except OSError: # create dividend history if it doesn't exist print('Generating Dividend History...\n') self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) # hypothesis -> new trades from today can be retrieved after 9pm after_trading_hours_today = datetime.now().replace(hour=21, minute=0, second=0, microsecond=0) # if there are new entries, parse the updated tradelog into db print('Checking Tradelog...') if (datetime.now().day - last_trade_datetime.day ) > 0 and datetime.now() > after_trading_hours_today: move(TRADELOG_PATH, TRADELOG_BACKUP_PATH) self.query_flexreport('420983', savepath=TRADELOG_PATH) print('Updating Tradelog...') self._update_tradelog_db(last_updated=last_trade_datetime) print('Tradelog is up-to-date\n') # if there are new entries, parse the updated dividend history in db print('Checking Dividend History..') if (datetime.now().day - last_dividend_date.day ) > 0 and datetime.now() > after_trading_hours_today: move(DIVIDEND_HISTORY_PATH, DIVIDEND_HISTORY_BACKUP_PATH) self.query_flexreport('421808', savepath=DIVIDEND_HISTORY_PATH) print('Updating Dividend History...') self._update_dividend_history_db(last_updated=last_dividend_date) print('Dividend History is up-to-date\n') print('IBKR Connection Successfully Established\n')
def placeOrders(): wb = xw.Book.caller() callingWorksheet = wb.sheets.active.name # Get the Excel cell address where "Positions to Close" table begins cellAddress = wb.sheets(callingWorksheet).tables[ callingWorksheet + 'OrderListTable'].data_body_range(1, 1).address # Pick up the "Positions to Close" ordersFromXL = wb.sheets(callingWorksheet).tables[ callingWorksheet + 'OrderListTable'].data_body_range.options(ndim=2).value # If the first cell of the "Positions to Close" is empty, raise error if ordersFromXL[0][0] == None or ordersFromXL[0][0].strip() == "": raise ValueError("No Orders to Submit") # Start a new IB connection ib = ibi.IB() ib.connect('127.0.0.1', getIbConnectionPort(callingWorksheet), clientId=4) # Place orders one at a time for order in ordersFromXL: # Create the entryOrder object if order[2].upper() == "LMT": entryOrder = ibi.LimitOrder( order[1], abs(int(order[6])), order[5], account=getSheetNameDict().get(callingWorksheet)) elif order[2].upper() == "MKT": entryOrder = ibi.MarketOrder( order[1], abs(int(order[6])), account=getSheetNameDict().get(callingWorksheet)) else: raise ValueError("Incorrect Order Type in " + order[0]) # Create the contract object if order[7].upper() == "STK": contract = ibi.Stock(order[8], 'SMART', 'USD', primaryExchange='NYSE') elif order[7].upper() == "OPT": contract = ibi.Option(order[8], "20" + order[9].strftime("%y%m%d"), order[10], order[11], 'SMART', multiplier=100, currency='USD') ib.qualifyContracts(contract) else: raise ValueError("Incorrect instrument type") ib.qualifyContracts(contract) trade = ib.placeOrder(contract, entryOrder) assert trade in ib.trades() # Disconnect from IB after placing the orders ib.disconnect()
# It will be a list of dicts. # {"symbol":symbol, "decision":decision, "buySize":buySize} # # call IB positions() and save it to a list of dicts, formatted as such # {symbol, posSize} # # If decision is a 1 AND posSize < 1, send a market buy of buySize. # Then, posSize = posSize + buySize # If decision is a -1 AND posSize > 0, send a market sell of posSize # Then, posSize = 0 import ib_insync as insync import numpy as np import glob, time, copy, datetime, random ib = insync.IB() def updatePositions(): global positionList positionList = [] # empty positions list global symbolList symbolList = [] for i in ib.positions(): posSize = i[2] symbol = i[1].symbol # i[1] returns a symbol object. positionList.append({"symbol": symbol, "posSize": posSize})
trade = tradelimitorder(ib, db, combo, 1, 1, "BRANCO_1") order = ibsync.LimitOrder(action='SELL', totalQuantity=1, lmtPrice=1, transmit=False, account=accid) trade = ib.placeOrder(combo, order) print(trade) except Exception as err: # error_handling(err) raise if __name__ == "__main__": try: myib = ibsync.IB() mydb = ibutil.dbconnect("localhost", "besuga", "xarnaus", "Besuga8888") acc = input( "triar entre 'besugapaper', 'xavpaper', 'mavpaper1', 'mavpaper2', 'XAVREAL' " ) if acc == "besugapaper": rslt = execute_query( mydb, "SELECT connHost, connPort, connAccId FROM connections WHERE connName = 'besugapaper7498'" ) elif acc == "xavpaper": rslt = execute_query( mydb, "SELECT connHost, connPort, connAccId FROM connections WHERE connName = 'xavpaper7497'" ) elif acc == "mavpaper1":
import ib_insync import datetime ib = ib_insync.IB() ib.connect() futures = [ ib_insync.Future("ES", "CFE", localSymbol=s) for s in ["ESU8","ESZ8"]] last_lengths = {} def onBarUpdate(bars, hasNewBar): if hasNewBar: print("New bar for", bars.contract.localSymbol) ib.qualifyContracts(*futures) for f in futures: print(f) if 0: bars = ib.reqHistoricalData( f, endDateTime='', durationStr='900 S', barSizeSetting='5 secs', whatToShow='bid', useRTH=True, formatDate=1, keepUpToDate=True) bars = ib.reqRealTimeBars(f, 5, "TRADES", False) last_lengths[f.localSymbol] = 0 ib.barUpdateEvent += onBarUpdate
def get_real_time_data(steamNum, durationStr, stock_symbol_list, host="127.0.0.1", port=7496, clientId=1, is_insert=True): """ https://interactivebrokers.github.io/tws-api/classIBApi_1_1EClient.html#aad87a15294377608e59aec1d87420594 :param steamNum: :param durationStr: the amount of time for which the data needs to be retrieved: " S (seconds) - " D (days) " W (weeks) - " M (months) " Y (years) :param host: :param port: :param clientId: :return: """ ib = ibsy.IB() with ib.connect(host, port, clientId=clientId): start_time = time.time() for counter in range(steamNum): for i in stock_symbol_list: print("Getting " + i + " real time data...") contract = ibsy.Stock(i, 'SMART', 'USD', primaryExchange='NASDAQ') # bars = ib.reqHistoricalData(contract, endDateTime='', durationStr=durationStr, # barSizeSetting='1 min', whatToShow='MIDPOINT', useRTH=True) bars = ib.reqHistoricalData(contract, endDateTime='', durationStr=durationStr, barSizeSetting='1 min', whatToShow='TRADES', useRTH=True) # convert to pandas dataframe: df = ibsy.util.df(bars) if is_insert: query = "INSERT IGNORE INTO IB_TODAY_" + i + " VALUES (%s, '" + i + "', %s, %s, %s, %s, %s, %s);" for index, row in df.iterrows(): insert_data = (str(row.date.strftime("%Y%m%d")), str(row.date.strftime("%H:%M:%S")), str(row.open), str(row.high), str(row.low), str(row.close), str(row.volume)) try: mydb = DBConnection().db_mysql_connector() mycursor = mydb.cursor() mycursor.execute(query, insert_data) mydb.commit() except Exception as e: print(e) return None finally: mycursor.close() mydb.close() else: print(df) print(bars) print("End of getting real time data...") end_time = time.time() sleep_time = time.sleep(max(0, 60 - (end_time - start_time))) print("Sleep time: ", sleep_time) ib.disconnect() ib.waitOnUpdate(timeout=0.1)
#%% main script if __name__=="__main__": log = logging.getLogger('main') parser = getParser() args = parser.parse_args() log.debug(args) if args.debug: log.setLevel(logging.DEBUG) settings = yaml.load(open(args.settings,'r')) tickLogger = TickLogger(settings['dataRoot']) ib = ibis.IB() log.info('Connecting to IB') ib.connect('127.0.0.1', 4002, clientId=10) ib.pendingTickersEvent += tickLogger.tickHandler # subscribe to data contracts = [ibis.Contract(**sub) for sub in settings['subscriptions']] for contract in contracts: log.info('Subscribing to '+str(contract)) ib.reqMktData(contract, '', False, False)
import ib_insync as ib client = ib.IB() client.connect('127.0.0.1', 4002, clientId=10) print(client.portfolio())