title: Multithreading with ib_insync
body: <p>I am requesting real time market data using the ib_insync API and then store it in a SQL Server. I want to do it using multi threading as my request list of stock symbols requested is too long. When I am trying to execute the below code, I get the error message onPendingTickers() missing 1 required positional argument: 'tickers'. But tickers is a method of the IB class.</p>
  
  <pre><code>import threading 
  from IPython.display import display, clear_output
  import pandas as pd
  from ib_insync import *
  util.startLoop()
  import datetime
  import urllib.request
  from sqlalchemy import create_engine
  import pyodbc
  import numpy
  import threading 
  import sys
  from queue import Queue
  #sys.stdout = open('log_fx.txt', 'w')
  ##Connections to Database
  params = urllib.parse.quote_plus("DRIVER={SQL Server};SERVER=52.168.175.133;Database=DARIUSH;UID=dariush;PWD=success@HPDI**17")
  engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params, echo=False,fast_executemany = True) #set echo = True to print all sql statements sent to server
  conn = engine.connect()
  ib = IB()
  ib.connect('127.0.0.1', 4002, clientId=7)
  contracts = [Forex(pair) for pair in ('EURUSD', 'GBPUSD', 'NZDUSD', 'AUDUSD')]
  #    ib.qualifyContracts(*contracts)
  
  ## Requesting Market Data  
  for contract in contracts:
      ib.reqMktData(contract, '', False, False)
  
  ## DataFrame Definitions   
  df = pd.DataFrame(
      index=[c.pair() for c in contracts],
      columns=[ 'Symbol','bid', 'ask'])    
  df1 = pd.DataFrame( index=[c.pair() for c in contracts],columns = ['SystemTime'])
  df2 = pd.DataFrame( index=[c.pair() for c in contracts],columns = ['Symbol','bid','ask','SystemTime'])
  df3 = pd.DataFrame()
  df4 = pd.DataFrame()
  df5 = pd.DataFrame()
  ## Function to store the incoming ticks in a DataFrame and write that DataFrame to SQL table
  def onPendingTickers(q,tickers):
      global df,df1,df2,df3,df4,df5 
      for t in tickers:
          df.loc[t.contract.pair()] = (t.contract.pair(),
               t.bid, t.ask)    
  #        clear_output(wait=True)
      df1['SystemTime'] = pd.Series([datetime.datetime.now()] * len(df),index = [c.pair() for c in contracts])                
  
      df2 = pd.concat([df,df1],axis = 1)
      df2['SystemTime'] = pd.to_datetime(df2['SystemTime'])
      df2.reset_index(drop=True, inplace=True)
      q.put(df2)
  #    if df.isnull().any().any() == False:  
  
  def write_toDB(q):
      global df,df1,df2,df3,df4,df5
      start = datetime.datetime.now()
      df2 = q.get()
      if len(df3) &gt; 0:
          df4 =  df2[(df2['bid'].values &lt;= df2['ask'].values) &amp; (0.9*df3['bid'].values &lt;= df2['bid'].values)  &amp; (df2['bid']&lt;= 1.1*df3['bid'].values) &amp; (0.9*df3['ask'].values &lt;= df2['ask'].values) &amp; (df2['ask'] &lt;= 1.1*df3['ask'].values)]    
          df4 = df4.dropna(how = 'any')
          print(df4,'df4')  
  #        df4.to_sql('FXtest_tick',conn,if_exists = 'append',index= False,method = 'multi',chunksize = 4)       
  #        df2.to_csv('tickData.csv',header=False,index = False,mode = 'a' )
      else:
          df5 = df2.dropna(how = 'any')
  #        df5.to_sql('FXtest_tick',conn,if_exists = 'append',index= False,method = 'multi',chunksize = 4) 
          print(df5,'df5')      
      df3 = df2
      print('time diff',datetime.datetime.now() - start) 
  
      q.task_done()
  
  
  
  if __name__ == "__main__":
      # creating thread
      q = Queue() # you were missing the ()
      onPendingTickers(q)
      # q is now full
      workers = 10
      thread_list = []
      for i in range(workers):
          t = threading.Thread(target=write_toDB, args=[q])
          t.start()
          thread_list.append(t)
  
      q.join()
  
      for thread in thread_list:
          thread.join()
      ## Timer to keep the connection open to IB for inflow of data
      ib.pendingTickersEvent += onPendingTickers
      ib.sleep(23400)
      ib.pendingTickersEvent -= onPendingTickers
      ib.disconnect()
  </code></pre>