Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9562a62

Browse files
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+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /