├── .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 |
--------------------------------------------------------------------------------