├── .gitignore ├── Common Errors ├── connection.py └── reader.py ├── GOOG_five_percent.py ├── alert_telegram.py ├── available_ticktypes.py ├── calculate_20SMA_Pandas.py ├── calculate_20SMA_manually.py ├── create_order.py ├── implement_stoploss_bracketorder.py ├── options_order.py ├── price_condition.py ├── readme.rst ├── requirements.txt ├── retrieve_ask_price_AAPL.py ├── retrieve_ask_price_BTC_Futures.py ├── retrieve_ask_price_EURUSD.py ├── retrieve_ask_price_Gold_commodities.py ├── store_hourly_candles_EURUSD.py └── test_for_connectivity.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /Common Errors/connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms 3 | and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. 4 | """ 5 | 6 | 7 | """ 8 | Just a thin wrapper around a socket. 9 | It allows us to keep some other info along with it. 10 | """ 11 | 12 | 13 | import socket 14 | import threading 15 | import logging 16 | 17 | from ibapi.common import * # @UnusedWildImport 18 | from ibapi.errors import * # @UnusedWildImport 19 | 20 | 21 | #TODO: support SSL !! 22 | 23 | logger = logging.getLogger(__name__) 24 | 25 | 26 | class Connection: 27 | def __init__(self, host, port): 28 | self.host = host 29 | self.port = port 30 | self.socket = None 31 | self.wrapper = None 32 | self.lock = threading.Lock() 33 | 34 | def connect(self): 35 | try: 36 | self.socket = socket.socket() 37 | #TODO: list the exceptions you want to catch 38 | except socket.error: 39 | if self.wrapper: 40 | self.wrapper.error(NO_VALID_ID, FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()) 41 | 42 | try: 43 | self.socket.connect((self.host, self.port)) 44 | except socket.error: 45 | if self.wrapper: 46 | self.wrapper.error(NO_VALID_ID, CONNECT_FAIL.code(), CONNECT_FAIL.msg()) 47 | 48 | self.socket.settimeout(1) #non-blocking 49 | 50 | def disconnect(self): 51 | self.lock.acquire() 52 | try: 53 | if self.socket is not None: 54 | logger.debug("disconnecting") 55 | self.socket.close() 56 | self.socket = None 57 | logger.debug("disconnected") 58 | if self.wrapper: 59 | self.wrapper.connectionClosed() 60 | finally: 61 | self.lock.release() 62 | 63 | def isConnected(self): 64 | return self.socket is not None 65 | 66 | def sendMsg(self, msg): 67 | logger.debug("acquiring lock") 68 | self.lock.acquire() 69 | logger.debug("acquired lock") 70 | if not self.isConnected(): 71 | logger.debug("sendMsg attempted while not connected, releasing lock") 72 | self.lock.release() 73 | return 0 74 | try: 75 | nSent = self.socket.send(msg) 76 | except socket.error: 77 | logger.debug("exception from sendMsg %s", sys.exc_info()) 78 | raise 79 | finally: 80 | logger.debug("releasing lock") 81 | self.lock.release() 82 | logger.debug("release lock") 83 | 84 | logger.debug("sendMsg: sent: %d", nSent) 85 | 86 | return nSent 87 | 88 | def recvMsg(self): 89 | if not self.isConnected(): 90 | logger.debug("recvMsg attempted while not connected, releasing lock") 91 | return b"" 92 | try: 93 | buf = self._recvAllMsg() 94 | # receiving 0 bytes outside a timeout means the connection is either 95 | # closed or broken 96 | if len(buf) == 0: 97 | logger.debug("socket either closed or broken, disconnecting") 98 | self.disconnect() 99 | except socket.timeout: 100 | logger.debug("socket timeout from recvMsg %s", sys.exc_info()) 101 | buf = b"" 102 | except socket.error: 103 | logger.debug("socket broken, disconnecting") 104 | self.disconnect() 105 | buf = b"" 106 | 107 | return buf 108 | 109 | def _recvAllMsg(self): 110 | cont = True 111 | allbuf = b"" 112 | 113 | while cont and self.isConnected(): 114 | buf = self.socket.recv(4096) 115 | allbuf += buf 116 | logger.debug("len %d raw:%s|", len(buf), buf) 117 | 118 | if len(buf) < 4096: 119 | cont = False 120 | 121 | return allbuf 122 | 123 | -------------------------------------------------------------------------------- /Common Errors/reader.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (C) 2019 Interactive Brokers LLC. All rights reserved. This code is subject to the terms 3 | and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. 4 | """ 5 | 6 | 7 | """ 8 | This code fix is by Thane Brooker. Link: https://idalpha-devops.blogspot.com/2019/11/interactive-brokers-tws-api-python.html 9 | 10 | The EReader runs in a separate threads and is responsible for receiving the 11 | incoming messages. 12 | It will read the packets from the wire, use the low level IB messaging to 13 | remove the size prefix and put the rest in a Queue. 14 | """ 15 | import time 16 | import logging 17 | from threading import Thread 18 | 19 | from ibapi import comm 20 | 21 | 22 | logger = logging.getLogger(__name__) 23 | 24 | 25 | class EReader(Thread): 26 | def __init__(self, conn, msg_queue): 27 | super().__init__() 28 | self.conn = conn 29 | self.msg_queue = msg_queue 30 | 31 | def run(self): 32 | try: 33 | buf = b"" 34 | while self.conn.isConnected(): 35 | 36 | try: 37 | data = self.conn.recvMsg() 38 | logger.debug("reader loop, recvd size %d", len(data)) 39 | buf += data 40 | 41 | except OSError as err: 42 | #If connection is disconnected, Windows will generate error 10038 43 | if err.errno == 10038: 44 | 45 | #Wait up to 1 second for disconnect confirmation 46 | waitUntil = time.time() + 1 47 | while time.time() < waitUntil: 48 | if not self.conn.isConnected(): 49 | break 50 | time.sleep(.1) 51 | 52 | if not self.conn.isConnected(): 53 | logger.debug("Ignoring OSError: {0}".format(err)) 54 | break 55 | 56 | #Disconnect wasn't received or error != 10038 57 | raise 58 | 59 | while len(buf) > 0: 60 | (size, msg, buf) = comm.read_msg(buf) 61 | #logger.debug("resp %s", buf.decode('ascii')) 62 | logger.debug("size:%d msg.size:%d msg:|%s| buf:%s|", size, 63 | len(msg), buf, "|") 64 | 65 | if msg: 66 | self.msg_queue.put(msg) 67 | else: 68 | logger.debug("more incoming packet(s) are needed ") 69 | break 70 | 71 | logger.debug("EReader thread finished") 72 | except: 73 | logger.exception('unhandled exception in EReader thread') 74 | 75 | -------------------------------------------------------------------------------- /GOOG_five_percent.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | from ibapi.order import * 5 | 6 | import pandas as pd 7 | import threading 8 | import time 9 | 10 | 11 | class IBapi(EWrapper, EClient): 12 | def __init__(self): 13 | EClient.__init__(self, self) 14 | self.bardata = {} #Initialize dictionary to store bar data 15 | 16 | def nextValidId(self, orderId: int): 17 | super().nextValidId(orderId) 18 | self.nextorderId = orderId 19 | print('The next valid order id is: ', self.nextorderId) 20 | 21 | def tick_df(self, reqId, contract): 22 | ''' custom function to init DataFrame and request Tick Data ''' 23 | self.bardata[reqId] = pd.DataFrame(columns=['time', 'price']) 24 | self.bardata[reqId].set_index('time', inplace=True) 25 | self.reqTickByTickData(reqId, contract, "Last", 0, True) 26 | return self.bardata[reqId] 27 | 28 | def tickByTickAllLast(self, reqId, tickType, time, price, size, tickAtrribLast, exchange, specialConditions): 29 | if tickType == 1: 30 | self.bardata[reqId].loc[pd.to_datetime(time, unit='s')] = price 31 | 32 | def Stock_contract(self, symbol, secType='STK', exchange='SMART', currency='USD'): 33 | ''' custom function to create contract ''' 34 | contract = Contract() 35 | contract.symbol = symbol 36 | contract.secType = secType 37 | contract.exchange = exchange 38 | contract.currency = currency 39 | return contract 40 | 41 | 42 | 43 | def run_loop(): 44 | app.run() 45 | 46 | def submit_order(contract, direction, qty=100, ordertype='MKT', transmit=True): 47 | #Create order object 48 | order = Order() 49 | order.action = direction 50 | order.totalQuantity = qty 51 | order.orderType = ordertype 52 | order.transmit = transmit 53 | #submit order 54 | app.placeOrder(app.nextorderId, contract, order) 55 | app.nextorderId += 1 56 | 57 | def check_for_trade(df, contract): 58 | start_time = df.index[-1] - pd.Timedelta(minutes=5) 59 | min_value = df[start_time:].price.min() 60 | max_value = df[start_time:].price.max() 61 | 62 | if df.price.iloc[-1] < max_value * 0.95: 63 | submit_order(contract, 'SELL') 64 | return True 65 | 66 | elif df.price.iloc[-1] > min_value * 1.05: 67 | submit_order(contract, 'BUY') 68 | return True 69 | 70 | #Main 71 | app = IBapi() 72 | app.nextorderId = None 73 | app.connect('127.0.0.1', 7496, 123) 74 | 75 | #Start the socket in a thread 76 | api_thread = threading.Thread(target=run_loop) 77 | api_thread.start() 78 | 79 | #Check if the API is connected via orderid 80 | while True: 81 | if isinstance(app.nextorderId, int): 82 | print('connected') 83 | break 84 | else: 85 | print('waiting for connection') 86 | time.sleep(1) 87 | 88 | #Create contract object 89 | google_contract = app.Stock_contract('GOOG') 90 | apple_contract = app.Stock_contract('AAPL') 91 | #-----------------------------------------------------------# 92 | 93 | #Reqest tick data for google using custom function 94 | df = app.tick_df(401, google_contract) 95 | 96 | #Verify data stream 97 | time.sleep(10) 98 | for i in range(100): 99 | if len(df) > 0: 100 | break 101 | time.sleep(0.3) 102 | 103 | if i == 99: 104 | app.disconnect() 105 | raise Exception ('Error with Tick data stream') 106 | 107 | #Check if there is enough data 108 | data_length = df.index[-1] - df.index[0] 109 | if data_length.seconds < 300: 110 | time.sleep(300 - data_length.seconds) 111 | 112 | #Main loop 113 | while True: 114 | if check_for_trade(df, apple_contract): break 115 | time.sleep(0.1) 116 | 117 | app.disconnect() -------------------------------------------------------------------------------- /alert_telegram.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | #This code can be used alongside the IB API to send the order & stop order values as an alert to Telegram 4 | 5 | def send(pair, order, stop_order): 6 | #Replace token, chat_id & text variables 7 | text = f'A new trade has been placed in {pair} at {order.lmitPrice} with a stop at {stop_order.auxPrice}' 8 | 9 | token = 'xxx' 10 | params = {'chat_id': xxx, 'text': text, 'parse_mode': 'HTML'} 11 | resp = requests.post('https://api.telegram.org/bot{}/sendMessage'.format(token), params) 12 | resp.raise_for_status() 13 | 14 | send('EURUSD', order, stop_order) -------------------------------------------------------------------------------- /available_ticktypes.py: -------------------------------------------------------------------------------- 1 | from ibapi.ticktype import TickTypeEnum 2 | 3 | for i in range(91): 4 | print(TickTypeEnum.to_str(i), i) -------------------------------------------------------------------------------- /calculate_20SMA_Pandas.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | class IBapi(EWrapper, EClient): 9 | def __init__(self): 10 | EClient.__init__(self, self) 11 | self.data = [] #Initialize variable to store candle 12 | 13 | def historicalData(self, reqId, bar): 14 | print(f'Time: {bar.date} Close: {bar.close}') 15 | self.data.append([bar.date, bar.close]) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 123) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | eurusd_contract = Contract() 31 | eurusd_contract.symbol = 'EUR' 32 | eurusd_contract.secType = 'CASH' 33 | eurusd_contract.exchange = 'IDEALPRO' 34 | eurusd_contract.currency = 'USD' 35 | 36 | 37 | #Request historical candles 38 | app.reqHistoricalData(1, eurusd_contract, '', '2 D', '1 hour', 'MIDPOINT', 0, 2, False, []) 39 | 40 | time.sleep(5) #sleep to allow enough time for data to be returned 41 | 42 | #Working with Pandas DataFrames 43 | import pandas 44 | 45 | df = pandas.DataFrame(app.data, columns=['DateTime', 'Close']) 46 | df['DateTime'] = pandas.to_datetime(df['DateTime'],unit='s') 47 | 48 | 49 | ### Calculate 20 SMA Using Pandas 50 | df['20SMA'] = df['Close'].rolling(20).mean() 51 | print(df.tail(10)) 52 | 53 | 54 | app.disconnect() -------------------------------------------------------------------------------- /calculate_20SMA_manually.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | class IBapi(EWrapper, EClient): 9 | def __init__(self): 10 | EClient.__init__(self, self) 11 | self.data = [] #Initialize variable to store candle 12 | 13 | def historicalData(self, reqId, bar): 14 | print(f'Time: {bar.date} Close: {bar.close}') 15 | self.data.append([bar.date, bar.close]) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 126) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | eurusd_contract = Contract() 31 | eurusd_contract.symbol = 'EUR' 32 | eurusd_contract.secType = 'CASH' 33 | eurusd_contract.exchange = 'IDEALPRO' 34 | eurusd_contract.currency = 'USD' 35 | 36 | 37 | #Request historical candles 38 | app.reqHistoricalData(1, eurusd_contract, '', '2 D', '1 hour', 'MIDPOINT', 0, 1, False, []) 39 | 40 | time.sleep(5) #sleep to allow enough time for data to be returned 41 | 42 | 43 | ### Calculate 20 SMA without a library 44 | total = 0 45 | for i in app.data[-20:]: 46 | total += float(i[1]) 47 | 48 | print('20SMA =', round(total/20, 5)) 49 | 50 | 51 | app.disconnect() -------------------------------------------------------------------------------- /create_order.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | from ibapi.order import * 5 | 6 | import threading 7 | import time 8 | 9 | class IBapi(EWrapper, EClient): 10 | def __init__(self): 11 | EClient.__init__(self, self) 12 | 13 | def nextValidId(self, orderId: int): 14 | super().nextValidId(orderId) 15 | self.nextorderId = orderId 16 | print('The next valid order id is: ', self.nextorderId) 17 | 18 | def orderStatus(self, orderId, status, filled, remaining, avgFullPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice): 19 | print('orderStatus - orderid:', orderId, 'status:', status, 'filled', filled, 'remaining', remaining, 'lastFillPrice', lastFillPrice) 20 | 21 | def openOrder(self, orderId, contract, order, orderState): 22 | print('openOrder id:', orderId, contract.symbol, contract.secType, '@', contract.exchange, ':', order.action, order.orderType, order.totalQuantity, orderState.status) 23 | 24 | def execDetails(self, reqId, contract, execution): 25 | print('Order Executed: ', reqId, contract.symbol, contract.secType, contract.currency, execution.execId, execution.orderId, execution.shares, execution.lastLiquidity) 26 | 27 | 28 | def run_loop(): 29 | app.run() 30 | 31 | #Function to create FX Order contract 32 | def FX_order(symbol): 33 | contract = Contract() 34 | contract.symbol = symbol[:3] 35 | contract.secType = 'CASH' 36 | contract.exchange = 'IDEALPRO' 37 | contract.currency = symbol[3:] 38 | return contract 39 | 40 | app = IBapi() 41 | app.connect('127.0.0.1', 7497, 123) 42 | 43 | app.nextorderId = None 44 | 45 | #Start the socket in a thread 46 | api_thread = threading.Thread(target=run_loop, daemon=True) 47 | api_thread.start() 48 | 49 | #Check if the API is connected via orderid 50 | while True: 51 | if isinstance(app.nextorderId, int): 52 | print('connected') 53 | print() 54 | break 55 | else: 56 | print('waiting for connection') 57 | time.sleep(1) 58 | 59 | #Create order object 60 | order = Order() 61 | order.action = 'BUY' 62 | order.totalQuantity = 1000 63 | order.orderType = 'LMT' 64 | order.lmtPrice = '1.10' 65 | 66 | #Place order 67 | app.placeOrder(app.nextorderId, FX_order('EURUSD'), order) 68 | #app.nextorderId += 1 69 | 70 | time.sleep(3) 71 | 72 | #Cancel order 73 | print('cancelling order') 74 | app.cancelOrder(app.nextorderId) 75 | 76 | time.sleep(3) 77 | app.disconnect() -------------------------------------------------------------------------------- /implement_stoploss_bracketorder.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | from ibapi.order import * 5 | 6 | import threading 7 | import time 8 | 9 | class IBapi(EWrapper, EClient): 10 | 11 | def __init__(self): 12 | EClient.__init__(self, self) 13 | 14 | def nextValidId(self, orderId: int): 15 | super().nextValidId(orderId) 16 | self.nextorderId = orderId 17 | print('The next valid order id is: ', self.nextorderId) 18 | 19 | def orderStatus(self, orderId, status, filled, remaining, avgFullPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice): 20 | print('orderStatus - orderid:', orderId, 'status:', status, 'filled', filled, 'remaining', remaining, 'lastFillPrice', lastFillPrice) 21 | 22 | def openOrder(self, orderId, contract, order, orderState): 23 | print('openOrder id:', orderId, contract.symbol, contract.secType, '@', contract.exchange, ':', order.action, order.orderType, order.totalQuantity, orderState.status) 24 | 25 | def execDetails(self, reqId, contract, execution): 26 | print('Order Executed: ', reqId, contract.symbol, contract.secType, contract.currency, execution.execId, execution.orderId, execution.shares, execution.lastLiquidity) 27 | 28 | 29 | def run_loop(): 30 | app.run() 31 | 32 | def FX_order(symbol): 33 | contract = Contract() 34 | contract.symbol = symbol[:3] 35 | contract.secType = 'CASH' 36 | contract.exchange = 'IDEALPRO' 37 | contract.currency = symbol[3:] 38 | return contract 39 | 40 | app = IBapi() 41 | app.connect('127.0.0.1', 7497, 123) 42 | 43 | app.nextorderId = None 44 | 45 | #Start the socket in a thread 46 | api_thread = threading.Thread(target=run_loop, daemon=True) 47 | api_thread.start() 48 | 49 | #Check if the API is connected via orderid 50 | while True: 51 | if isinstance(app.nextorderId, int): 52 | print('connected') 53 | print() 54 | break 55 | else: 56 | print('waiting for connection') 57 | time.sleep(1) 58 | 59 | #Create order object 60 | order = Order() 61 | order.action = 'BUY' 62 | order.totalQuantity = 100000 63 | order.orderType = 'LMT' 64 | order.lmtPrice = '1.10' 65 | order.orderId = app.nextorderId 66 | app.nextorderId += 1 67 | order.transmit = False 68 | 69 | #Create stop loss order object 70 | stop_order = Order() 71 | stop_order.action = 'SELL' 72 | stop_order.totalQuantity = 100000 73 | stop_order.orderType = 'STP' 74 | stop_order.auxPrice = '1.09' 75 | stop_order.orderId = app.nextorderId 76 | app.nextorderId += 1 77 | stop_order.parentId = order.orderId 78 | stop_order.transmit = True 79 | 80 | #Place orders 81 | app.placeOrder(order.orderId, FX_order('EURUSD'), order) 82 | app.placeOrder(stop_order.orderId, FX_order('EURUSD'), stop_order) 83 | time.sleep(10) 84 | 85 | #Cancel order 86 | print() 87 | print('cancelling order') 88 | app.cancelOrder(order.orderId) 89 | 90 | time.sleep(3) 91 | app.disconnect() -------------------------------------------------------------------------------- /options_order.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | from ibapi.order import * 5 | 6 | import threading 7 | import time 8 | 9 | 10 | class IBapi(EWrapper, EClient): 11 | def __init__(self): 12 | EClient.__init__(self, self) 13 | 14 | def nextValidId(self, orderId: int): 15 | super().nextValidId(orderId) 16 | self.nextorderId = orderId 17 | print('The next valid order id is: ', self.nextorderId) 18 | 19 | def orderStatus(self, orderId, status, filled, remaining, avgFullPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice): 20 | print('orderStatus - orderid:', orderId, 'status:', status, 'filled', filled, 'remaining', remaining, 'lastFillPrice', lastFillPrice) 21 | 22 | def openOrder(self, orderId, contract, order, orderState): 23 | print('openOrder id:', orderId, contract.symbol, contract.secType, '@', contract.exchange, ':', order.action, order.orderType, order.totalQuantity, orderState.status) 24 | 25 | def execDetails(self, reqId, contract, execution): 26 | print('Order Executed: ', reqId, contract.symbol, contract.secType, contract.currency, execution.execId, execution.orderId, execution.shares, execution.lastLiquidity) 27 | 28 | 29 | def run_loop(): 30 | app.run() 31 | 32 | 33 | 34 | app = IBapi() 35 | app.connect('127.0.0.1', 7496, 123) 36 | 37 | app.nextorderId = None 38 | 39 | #Start the socket in a thread 40 | api_thread = threading.Thread(target=run_loop, daemon=True) 41 | api_thread.start() 42 | 43 | #Check if the API is connected via orderid 44 | while True: 45 | if isinstance(app.nextorderId, int): 46 | print('connected') 47 | print() 48 | break 49 | else: 50 | print('waiting for connection') 51 | time.sleep(1) 52 | 53 | #Create contract 54 | contract = Contract() 55 | contract.symbol = 'TSLA' 56 | contract.secType = 'OPT' 57 | contract.exchange = 'SMART' 58 | contract.lastTradeDateOrContractMonth = '20201002' 59 | contract.strike = 424 60 | contract.right = 'C' 61 | contract.multiplier = '100' 62 | 63 | #Create order object 64 | order = Order() 65 | order.action = 'BUY' 66 | order.totalQuantity = 1 67 | order.orderType = 'MKT' 68 | 69 | #Place order 70 | app.placeOrder(app.nextorderId, contract, order) 71 | 72 | 73 | time.sleep(3) 74 | app.disconnect() 75 | -------------------------------------------------------------------------------- /price_condition.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | from ibapi.order_condition import Create, OrderCondition 5 | from ibapi.order import * 6 | 7 | import threading 8 | import time 9 | 10 | class IBapi(EWrapper, EClient): 11 | def __init__(self): 12 | EClient.__init__(self, self) 13 | self.contract_details = {} #Contract details will be stored here using reqId as a dictionary key 14 | 15 | def nextValidId(self, orderId: int): 16 | super().nextValidId(orderId) 17 | self.nextorderId = orderId 18 | print('The next valid order id is: ', self.nextorderId) 19 | 20 | def orderStatus(self, orderId, status, filled, remaining, avgFullPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice): 21 | print('orderStatus - orderid:', orderId, 'status:', status, 'filled', filled, 'remaining', remaining, 'lastFillPrice', lastFillPrice) 22 | 23 | def openOrder(self, orderId, contract, order, orderState): 24 | print('openOrder id:', orderId, contract.symbol, contract.secType, '@', contract.exchange, ':', order.action, order.orderType, order.totalQuantity, orderState.status) 25 | 26 | def execDetails(self, reqId, contract, execution): 27 | print('Order Executed: ', reqId, contract.symbol, contract.secType, contract.currency, execution.execId, execution.orderId, execution.shares, execution.lastLiquidity) 28 | 29 | def contractDetails(self, reqId: int, contractDetails): 30 | self.contract_details[reqId] = contractDetails 31 | 32 | def get_contract_details(self, reqId, contract): 33 | self.contract_details[reqId] = None 34 | self.reqContractDetails(reqId, contract) 35 | #Error checking loop - breaks from loop once contract details are obtained 36 | for i in range(50): 37 | if not self.contract_details[reqId]: 38 | time.sleep(0.1) 39 | else: 40 | break 41 | #Raise if error checking loop count maxed out (contract details not obtained) 42 | if i == 49: 43 | raise Exception('error getting contract details') 44 | #Return contract details otherwise 45 | return app.contract_details[reqId].contract 46 | 47 | 48 | 49 | def run_loop(): 50 | app.run() 51 | 52 | def Stock_contract(symbol, secType='STK', exchange='SMART', currency='USD'): 53 | ''' custom function to create stock contract ''' 54 | contract = Contract() 55 | contract.symbol = symbol 56 | contract.secType = secType 57 | contract.exchange = exchange 58 | contract.currency = currency 59 | return contract 60 | 61 | app = IBapi() 62 | app.connect('127.0.0.1', 7496, 123) 63 | 64 | app.nextorderId = None 65 | 66 | #Start the socket in a thread 67 | api_thread = threading.Thread(target=run_loop, daemon=True) 68 | api_thread.start() 69 | 70 | #Check if the API is connected via orderid 71 | while True: 72 | if isinstance(app.nextorderId, int): 73 | print('connected') 74 | break 75 | else: 76 | print('waiting for connection') 77 | time.sleep(1) 78 | 79 | #Create contracts 80 | apple_contract = Stock_contract('AAPL') 81 | google_contract = Stock_contract('GOOG') 82 | 83 | #Update contract ID 84 | google_contract = app.get_contract_details(101, google_contract) 85 | 86 | ##Create price conditions 87 | #init 88 | priceCondition = Create(OrderCondition.Price) 89 | priceCondition.conId = google_contract.conId 90 | priceCondition.exchange = google_contract.exchange 91 | 92 | #create conditions 93 | priceCondition.isMore = True 94 | priceCondition.triggerMethod = priceCondition.TriggerMethodEnum.Last 95 | priceCondition.price = 1400.00 96 | 97 | #Create order object 98 | order = Order() 99 | order.action = 'BUY' 100 | order.totalQuantity = 100 101 | order.orderType = 'MKT' 102 | #order.lmtPrice = '300' - optional - you can add a buy stop limit here 103 | order.conditions.append(priceCondition) 104 | order.transmit = True 105 | 106 | app.placeOrder(app.nextorderId, apple_contract, order) 107 | 108 | time.sleep(3) 109 | app.disconnect() -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | ==================================================================================== 2 | Interactive Brokers Python API (Native) - A Step-by-step Guide - AlgoTrading101 Blog 3 | ==================================================================================== 4 | 5 | This is the code used in `Interactive Brokers Python API (Native) `_ published on the AlgoTrading101 Blog 6 | 7 | ----------------- 8 | Table of Contents 9 | ----------------- 10 | 11 | * `What is the Interactive Brokers Python native API? `_ 12 | * `Why should I learn the IB Python Native API? `_ 13 | * `Why shouldn’t I learn the IB Python Native API? `_ 14 | * `IB Python native API vs Third Party Libraries (IBridgePy, IbPy etc) `_ 15 | * `How to set up the IB native Python API? `_ 16 | * `How to retrieve the current ask price of Apple’s Stock (AAPL) `_ 17 | * `Retrieving market data for other assets – EUR/USD, Bitcoin & Gold `_ 18 | * `How to retrieve the last 10 hourly candlebars using the native Python API? `_ 19 | * `What’s the best way to store historical data for later use? `_ 20 | * `3 ways to calculate the 20 SMA `_ 21 | * `How to fire an order using the native Python API? `_ 22 | * `How to implement a stop loss or take profit? `_ 23 | * `How to fire an order for Apple when Google hits a certain price? `_ 24 | * `How to fire an order for Apple when Google moves more than 5% within the last 5 minutes? `_ 25 | * `How to send notifications via telegram? `_ 26 | * `Common Errors with the IB Python Native API v9.76 `_ 27 | 28 | ------------ 29 | Requirements 30 | ------------ 31 | 32 | * `python `_ >= 2.7, 3.4+ 33 | * `pandas `_ (tested to work with >= 1.0.3 ) 34 | * `requests `_ (tested to work with >= 2.22.0 ) 35 | * `ibapi `_ (tested to work with >= 9.76.1 ) 36 | 37 | ----------- 38 | Author Info 39 | ----------- 40 | 41 | :author: Jignesh Davda 42 | :author page: https://algotrading101.com/learn/author/jdavda/ 43 | :published: 2020-02-07 44 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas==1.0.3 2 | requests==2.22.0 3 | ibapi==9.76.1 4 | -------------------------------------------------------------------------------- /retrieve_ask_price_AAPL.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | 9 | class IBapi(EWrapper, EClient): 10 | def __init__(self): 11 | EClient.__init__(self, self) 12 | 13 | def tickPrice(self, reqId, tickType, price, attrib): 14 | if tickType == 2 and reqId == 1: 15 | print('The current ask price is: ', price) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 58) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | apple_contract = Contract() 31 | apple_contract.symbol = 'AAPL' 32 | apple_contract.secType = 'STK' 33 | apple_contract.exchange = 'SMART' 34 | apple_contract.currency = 'USD' 35 | 36 | #Request Market Data 37 | app.reqMktData(1, apple_contract, '', False, False, []) 38 | 39 | time.sleep(10) #Sleep interval to allow time for incoming price data 40 | app.disconnect() -------------------------------------------------------------------------------- /retrieve_ask_price_BTC_Futures.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | 9 | class IBapi(EWrapper, EClient): 10 | def __init__(self): 11 | EClient.__init__(self, self) 12 | 13 | def tickPrice(self, reqId, tickType, price, attrib): 14 | if tickType == 2 and reqId == 1: 15 | print('The current ask price is: ', price) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 123) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | BTC_futures__contract = Contract() 31 | BTC_futures__contract.symbol = 'BRR' 32 | BTC_futures__contract.secType = 'FUT' 33 | BTC_futures__contract.exchange = 'CMECRYPTO' 34 | BTC_futures__contract.lastTradeDateOrContractMonth = '202003' 35 | 36 | #Request Market Data 37 | app.reqMktData(1, BTC_futures__contract, '', False, False, []) 38 | 39 | time.sleep(10) #Sleep interval to allow time for incoming price data 40 | app.disconnect() -------------------------------------------------------------------------------- /retrieve_ask_price_EURUSD.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | 9 | class IBapi(EWrapper, EClient): 10 | def __init__(self): 11 | EClient.__init__(self, self) 12 | 13 | def tickPrice(self, reqId, tickType, price, attrib): 14 | if tickType == 2 and reqId == 1: 15 | print('The current ask price is: ', price) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 58) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | eurusd_contract = Contract() 31 | eurusd_contract.symbol = 'EUR' 32 | eurusd_contract.secType = 'CASH' 33 | eurusd_contract.exchange = 'IDEALPRO' 34 | eurusd_contract.currency = 'USD' 35 | 36 | #Request Market Data 37 | app.reqMktData(1, eurusd_contract, '', False, False, []) 38 | 39 | time.sleep(10) #Sleep interval to allow time for incoming price data 40 | app.disconnect() -------------------------------------------------------------------------------- /retrieve_ask_price_Gold_commodities.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | 9 | class IBapi(EWrapper, EClient): 10 | def __init__(self): 11 | EClient.__init__(self, self) 12 | 13 | def tickPrice(self, reqId, tickType, price, attrib): 14 | if tickType == 2 and reqId == 1: 15 | print('The current ask price is: ', price) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 123) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | XAUUSD_contract = Contract() 31 | XAUUSD_contract.symbol = 'XAUUSD' 32 | XAUUSD_contract.secType = 'CMDTY' 33 | XAUUSD_contract.exchange = 'SMART' 34 | XAUUSD_contract.currency = 'USD' 35 | 36 | #Request Market Data 37 | app.reqMktData(1, XAUUSD_contract, '', False, False, []) 38 | 39 | time.sleep(10) #Sleep interval to allow time for incoming price data 40 | app.disconnect() -------------------------------------------------------------------------------- /store_hourly_candles_EURUSD.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | from ibapi.contract import Contract 4 | 5 | import threading 6 | import time 7 | 8 | class IBapi(EWrapper, EClient): 9 | def __init__(self): 10 | EClient.__init__(self, self) 11 | self.data = [] #Initialize variable to store candle 12 | 13 | def historicalData(self, reqId, bar): 14 | print(f'Time: {bar.date} Close: {bar.close}') 15 | self.data.append([bar.date, bar.close]) 16 | 17 | def run_loop(): 18 | app.run() 19 | 20 | app = IBapi() 21 | app.connect('127.0.0.1', 7497, 123) 22 | 23 | #Start the socket in a thread 24 | api_thread = threading.Thread(target=run_loop, daemon=True) 25 | api_thread.start() 26 | 27 | time.sleep(1) #Sleep interval to allow time for connection to server 28 | 29 | #Create contract object 30 | eurusd_contract = Contract() 31 | eurusd_contract.symbol = 'EUR' 32 | eurusd_contract.secType = 'CASH' 33 | eurusd_contract.exchange = 'IDEALPRO' 34 | eurusd_contract.currency = 'USD' 35 | 36 | app.data = [] #Initialize variable to store candle 37 | 38 | #Request historical candles 39 | app.reqHistoricalData(1, eurusd_contract, '', '2 D', '1 hour', 'MIDPOINT', 0, 2, False, []) 40 | 41 | time.sleep(5) #sleep to allow enough time for data to be returned 42 | 43 | #Working with Pandas DataFrames 44 | import pandas 45 | 46 | df = pandas.DataFrame(app.data, columns=['DateTime', 'Close']) 47 | df['DateTime'] = pandas.to_datetime(df['DateTime'],unit='s') 48 | df.to_csv('EURUSD_Hourly.csv') 49 | 50 | print(df) 51 | 52 | 53 | app.disconnect() -------------------------------------------------------------------------------- /test_for_connectivity.py: -------------------------------------------------------------------------------- 1 | from ibapi.client import EClient 2 | from ibapi.wrapper import EWrapper 3 | 4 | class IBapi(EWrapper, EClient): 5 | def __init__(self): 6 | EClient.__init__(self, self) 7 | 8 | app = IBapi() 9 | app.connect('127.0.0.1', 7497, 123) 10 | app.run() 11 | 12 | ''' 13 | #Uncomment this section if unable to connect 14 | #and to prevent errors on a reconnect 15 | 16 | import time 17 | time.sleep(2) 18 | app.disconnect() 19 | ''' 20 | --------------------------------------------------------------------------------