Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9562a62

Browse files
committedJun 2, 2020
first commit
0 parents  commit 9562a62

19 files changed

+1105
-0
lines changed
 

‎.gitignore

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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/

‎Common Errors/connection.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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+

‎Common Errors/reader.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+

‎GOOG_five_percent.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from ibapi.ticktype import TickTypeEnum
2+
3+
for i in range(91):
4+
print(TickTypeEnum.to_str(i), i)

‎calculate_20SMA_Pandas.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 = 1000
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 = 1000
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+
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()

‎price_condition.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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) <https://algotrading101.com/learn/interactive-brokers-python-api-native-guide/>`_ published on the AlgoTrading101 Blog
6+
7+
-----------------
8+
Table of Contents
9+
-----------------
10+
11+
12+
------------
13+
Requirements
14+
------------
15+
16+
* `python <https://www.python.org>`_ >= 2.7, 3.4+
17+
* `ibapi.egg <url_goes_here>`_ (tested to work with >= info )
18+
* `pandas <url_goes_here>`_ (tested to work with >= 1.0.3 )
19+
* `requests <url_goes_here>`_ (tested to work with >= 2.22.0 )
20+
* `ibapi <url_goes_here>`_ (tested to work with >= 9.76.1 )
21+
22+
-----------
23+
Author Info
24+
-----------
25+
26+
:author: Jignesh Davda
27+
:author page: https://algotrading101.com/learn/author/jdavda/
28+
:published: 2020-02-07

‎requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pandas==1.0.3
2+
requests==2.22.0
3+
ibapi==9.76.1

‎retrieve_ask_price_AAPL.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
'''

0 commit comments

Comments
 (0)
Please sign in to comment.