ibapi-stable 10.37.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ibapi/__init__.py +16 -0
- ibapi/account_summary_tags.py +70 -0
- ibapi/client.py +4891 -0
- ibapi/client_utils.py +412 -0
- ibapi/comm.py +100 -0
- ibapi/commission_and_fees_report.py +31 -0
- ibapi/common.py +315 -0
- ibapi/connection.py +126 -0
- ibapi/const.py +12 -0
- ibapi/contract.py +265 -0
- ibapi/decoder.py +1711 -0
- ibapi/decoder_utils.py +420 -0
- ibapi/enum_implem.py +20 -0
- ibapi/errors.py +43 -0
- ibapi/execution.py +95 -0
- ibapi/ineligibility_reason.py +18 -0
- ibapi/message.py +186 -0
- ibapi/news.py +13 -0
- ibapi/object_implem.py +12 -0
- ibapi/order.py +263 -0
- ibapi/order_cancel.py +21 -0
- ibapi/order_condition.py +289 -0
- ibapi/order_state.py +117 -0
- ibapi/orderdecoder.py +539 -0
- ibapi/protobuf/CancelOrderRequest_pb2.py +38 -0
- ibapi/protobuf/ComboLeg_pb2.py +37 -0
- ibapi/protobuf/Contract_pb2.py +39 -0
- ibapi/protobuf/DeltaNeutralContract_pb2.py +37 -0
- ibapi/protobuf/ErrorMessage_pb2.py +37 -0
- ibapi/protobuf/ExecutionDetailsEnd_pb2.py +37 -0
- ibapi/protobuf/ExecutionDetails_pb2.py +39 -0
- ibapi/protobuf/ExecutionFilter_pb2.py +37 -0
- ibapi/protobuf/ExecutionRequest_pb2.py +38 -0
- ibapi/protobuf/Execution_pb2.py +37 -0
- ibapi/protobuf/GlobalCancelRequest_pb2.py +38 -0
- ibapi/protobuf/OpenOrder_pb2.py +40 -0
- ibapi/protobuf/OpenOrdersEnd_pb2.py +37 -0
- ibapi/protobuf/OrderAllocation_pb2.py +37 -0
- ibapi/protobuf/OrderCancel_pb2.py +37 -0
- ibapi/protobuf/OrderCondition_pb2.py +37 -0
- ibapi/protobuf/OrderState_pb2.py +38 -0
- ibapi/protobuf/OrderStatus_pb2.py +37 -0
- ibapi/protobuf/Order_pb2.py +51 -0
- ibapi/protobuf/PlaceOrderRequest_pb2.py +39 -0
- ibapi/protobuf/SoftDollarTier_pb2.py +37 -0
- ibapi/reader.py +49 -0
- ibapi/scanner.py +77 -0
- ibapi/server_versions.py +159 -0
- ibapi/softdollartier.py +16 -0
- ibapi/tag_value.py +22 -0
- ibapi/ticktype.py +117 -0
- ibapi/utils.py +233 -0
- ibapi/wrapper.py +885 -0
- ibapi_stable-10.37.2.dist-info/METADATA +136 -0
- ibapi_stable-10.37.2.dist-info/RECORD +57 -0
- ibapi_stable-10.37.2.dist-info/WHEEL +5 -0
- ibapi_stable-10.37.2.dist-info/top_level.txt +1 -0
ibapi/common.py
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (C) 2025 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
|
+
from ibapi.const import UNSET_INTEGER, UNSET_DECIMAL
|
|
8
|
+
from ibapi.enum_implem import Enum
|
|
9
|
+
from ibapi.object_implem import Object
|
|
10
|
+
from ibapi.utils import floatMaxString, decimalMaxString, intMaxString
|
|
11
|
+
from ibapi.message import OUT
|
|
12
|
+
from ibapi.server_versions import (
|
|
13
|
+
MIN_SERVER_VER_PROTOBUF,
|
|
14
|
+
MIN_SERVER_VER_PROTOBUF_PLACE_ORDER
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
TickerId = int
|
|
18
|
+
OrderId = int
|
|
19
|
+
TagValueList = list
|
|
20
|
+
|
|
21
|
+
FaDataType = int
|
|
22
|
+
FaDataTypeEnum = Enum("N/A", "GROUPS", "N/A", "ALIASES")
|
|
23
|
+
|
|
24
|
+
MarketDataType = int
|
|
25
|
+
MarketDataTypeEnum = Enum("N/A", "REALTIME", "FROZEN", "DELAYED", "DELAYED_FROZEN")
|
|
26
|
+
|
|
27
|
+
Liquidities = int
|
|
28
|
+
LiquiditiesEnum = Enum("None", "Added", "Remove", "RoudedOut")
|
|
29
|
+
|
|
30
|
+
SetOfString = set
|
|
31
|
+
SetOfFloat = set
|
|
32
|
+
ListOfOrder = list
|
|
33
|
+
ListOfFamilyCode = list
|
|
34
|
+
ListOfContractDescription = list
|
|
35
|
+
ListOfDepthExchanges = list
|
|
36
|
+
ListOfNewsProviders = list
|
|
37
|
+
SmartComponentMap = dict
|
|
38
|
+
HistogramDataList = list
|
|
39
|
+
ListOfPriceIncrements = list
|
|
40
|
+
ListOfHistoricalTick = list
|
|
41
|
+
ListOfHistoricalTickBidAsk = list
|
|
42
|
+
ListOfHistoricalTickLast = list
|
|
43
|
+
ListOfHistoricalSessions = list
|
|
44
|
+
|
|
45
|
+
PROTOBUF_MSG_ID = 200
|
|
46
|
+
PROTOBUF_MSG_IDS = {
|
|
47
|
+
OUT.REQ_EXECUTIONS : MIN_SERVER_VER_PROTOBUF,
|
|
48
|
+
OUT.PLACE_ORDER : MIN_SERVER_VER_PROTOBUF_PLACE_ORDER,
|
|
49
|
+
OUT.CANCEL_ORDER : MIN_SERVER_VER_PROTOBUF_PLACE_ORDER,
|
|
50
|
+
OUT.REQ_GLOBAL_CANCEL : MIN_SERVER_VER_PROTOBUF_PLACE_ORDER
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class BarData(Object):
|
|
54
|
+
def __init__(self):
|
|
55
|
+
self.date = ""
|
|
56
|
+
self.open = 0.0
|
|
57
|
+
self.high = 0.0
|
|
58
|
+
self.low = 0.0
|
|
59
|
+
self.close = 0.0
|
|
60
|
+
self.volume = UNSET_DECIMAL
|
|
61
|
+
self.wap = UNSET_DECIMAL
|
|
62
|
+
self.barCount = 0
|
|
63
|
+
|
|
64
|
+
def __str__(self):
|
|
65
|
+
return (
|
|
66
|
+
f"Date: {self.date}, "
|
|
67
|
+
f"Open: {floatMaxString(self.open)}, "
|
|
68
|
+
f"High: {floatMaxString(self.high)}, "
|
|
69
|
+
f"Low: {floatMaxString(self.low)}, "
|
|
70
|
+
f"Close: {floatMaxString(self.close)}, "
|
|
71
|
+
f"Volume: {decimalMaxString(self.volume)}, "
|
|
72
|
+
f"WAP: {decimalMaxString(self.wap)}, "
|
|
73
|
+
f"BarCount: {intMaxString(self.barCount)}"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class RealTimeBar(Object):
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
time=0,
|
|
81
|
+
endTime=-1,
|
|
82
|
+
open_=0.0,
|
|
83
|
+
high=0.0,
|
|
84
|
+
low=0.0,
|
|
85
|
+
close=0.0,
|
|
86
|
+
volume=UNSET_DECIMAL,
|
|
87
|
+
wap=UNSET_DECIMAL,
|
|
88
|
+
count=0,
|
|
89
|
+
):
|
|
90
|
+
self.time = time
|
|
91
|
+
self.endTime = endTime
|
|
92
|
+
self.open_ = open_
|
|
93
|
+
self.high = high
|
|
94
|
+
self.low = low
|
|
95
|
+
self.close = close
|
|
96
|
+
self.volume = volume
|
|
97
|
+
self.wap = wap
|
|
98
|
+
self.count = count
|
|
99
|
+
|
|
100
|
+
def __str__(self):
|
|
101
|
+
return (
|
|
102
|
+
"Time: %s, Open: %s, High: %s, Low: %s, Close: %s, Volume: %s, WAP: %s, Count: %s"
|
|
103
|
+
% (
|
|
104
|
+
intMaxString(self.time),
|
|
105
|
+
floatMaxString(self.open_),
|
|
106
|
+
floatMaxString(self.high),
|
|
107
|
+
floatMaxString(self.low),
|
|
108
|
+
floatMaxString(self.close),
|
|
109
|
+
decimalMaxString(self.volume),
|
|
110
|
+
decimalMaxString(self.wap),
|
|
111
|
+
intMaxString(self.count),
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class HistogramData(Object):
|
|
117
|
+
def __init__(self):
|
|
118
|
+
self.price = 0.0
|
|
119
|
+
self.size = UNSET_DECIMAL
|
|
120
|
+
|
|
121
|
+
def __str__(self):
|
|
122
|
+
return "Price: %s, Size: %s" % (
|
|
123
|
+
floatMaxString(self.price),
|
|
124
|
+
decimalMaxString(self.size),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class NewsProvider(Object):
|
|
129
|
+
def __init__(self):
|
|
130
|
+
self.code = ""
|
|
131
|
+
self.name = ""
|
|
132
|
+
|
|
133
|
+
def __str__(self):
|
|
134
|
+
return f"Code: {self.code}, Name: {self.name}"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class DepthMktDataDescription(Object):
|
|
138
|
+
def __init__(self):
|
|
139
|
+
self.exchange = ""
|
|
140
|
+
self.secType = ""
|
|
141
|
+
self.listingExch = ""
|
|
142
|
+
self.serviceDataType = ""
|
|
143
|
+
self.aggGroup = UNSET_INTEGER
|
|
144
|
+
|
|
145
|
+
def __str__(self):
|
|
146
|
+
if self.aggGroup != UNSET_INTEGER:
|
|
147
|
+
aggGroup = self.aggGroup
|
|
148
|
+
else:
|
|
149
|
+
aggGroup = ""
|
|
150
|
+
return (
|
|
151
|
+
"Exchange: %s, SecType: %s, ListingExchange: %s, ServiceDataType: %s, AggGroup: %s, "
|
|
152
|
+
% (
|
|
153
|
+
self.exchange,
|
|
154
|
+
self.secType,
|
|
155
|
+
self.listingExch,
|
|
156
|
+
self.serviceDataType,
|
|
157
|
+
intMaxString(aggGroup),
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class SmartComponent(Object):
|
|
163
|
+
def __init__(self):
|
|
164
|
+
self.bitNumber = 0
|
|
165
|
+
self.exchange = ""
|
|
166
|
+
self.exchangeLetter = ""
|
|
167
|
+
|
|
168
|
+
def __str__(self):
|
|
169
|
+
return "BitNumber: %d, Exchange: %s, ExchangeLetter: %s" % (
|
|
170
|
+
self.bitNumber,
|
|
171
|
+
self.exchange,
|
|
172
|
+
self.exchangeLetter,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class TickAttrib(Object):
|
|
177
|
+
def __init__(self):
|
|
178
|
+
self.canAutoExecute = False
|
|
179
|
+
self.pastLimit = False
|
|
180
|
+
self.preOpen = False
|
|
181
|
+
|
|
182
|
+
def __str__(self):
|
|
183
|
+
return "CanAutoExecute: %d, PastLimit: %d, PreOpen: %d" % (
|
|
184
|
+
self.canAutoExecute,
|
|
185
|
+
self.pastLimit,
|
|
186
|
+
self.preOpen,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class TickAttribBidAsk(Object):
|
|
191
|
+
def __init__(self):
|
|
192
|
+
self.bidPastLow = False
|
|
193
|
+
self.askPastHigh = False
|
|
194
|
+
|
|
195
|
+
def __str__(self):
|
|
196
|
+
return "BidPastLow: %d, AskPastHigh: %d" % (self.bidPastLow, self.askPastHigh)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class TickAttribLast(Object):
|
|
200
|
+
def __init__(self):
|
|
201
|
+
self.pastLimit = False
|
|
202
|
+
self.unreported = False
|
|
203
|
+
|
|
204
|
+
def __str__(self):
|
|
205
|
+
return "PastLimit: %d, Unreported: %d" % (self.pastLimit, self.unreported)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class FamilyCode(Object):
|
|
209
|
+
def __init__(self):
|
|
210
|
+
self.accountID = ""
|
|
211
|
+
self.familyCodeStr = ""
|
|
212
|
+
|
|
213
|
+
def __str__(self):
|
|
214
|
+
return f"AccountId: {self.accountID}, FamilyCodeStr: {self.familyCodeStr}"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class PriceIncrement(Object):
|
|
218
|
+
def __init__(self):
|
|
219
|
+
self.lowEdge = 0.0
|
|
220
|
+
self.increment = 0.0
|
|
221
|
+
|
|
222
|
+
def __str__(self):
|
|
223
|
+
return "LowEdge: %s, Increment: %s" % (
|
|
224
|
+
floatMaxString(self.lowEdge),
|
|
225
|
+
floatMaxString(self.increment),
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class HistoricalTick(Object):
|
|
230
|
+
def __init__(self):
|
|
231
|
+
self.time = 0
|
|
232
|
+
self.price = 0.0
|
|
233
|
+
self.size = UNSET_DECIMAL
|
|
234
|
+
|
|
235
|
+
def __str__(self):
|
|
236
|
+
return "Time: %s, Price: %s, Size: %s" % (
|
|
237
|
+
intMaxString(self.time),
|
|
238
|
+
floatMaxString(self.price),
|
|
239
|
+
decimalMaxString(self.size),
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class HistoricalTickBidAsk(Object):
|
|
244
|
+
def __init__(self):
|
|
245
|
+
self.time = 0
|
|
246
|
+
self.tickAttribBidAsk = TickAttribBidAsk()
|
|
247
|
+
self.priceBid = 0.0
|
|
248
|
+
self.priceAsk = 0.0
|
|
249
|
+
self.sizeBid = UNSET_DECIMAL
|
|
250
|
+
self.sizeAsk = UNSET_DECIMAL
|
|
251
|
+
|
|
252
|
+
def __str__(self):
|
|
253
|
+
return (
|
|
254
|
+
f"Time: {intMaxString(self.time)}, "
|
|
255
|
+
f"TickAttriBidAsk: {self.tickAttribBidAsk}, "
|
|
256
|
+
f"PriceBid: {floatMaxString(self.priceBid)}, "
|
|
257
|
+
f"PriceAsk: {floatMaxString(self.priceAsk)}, "
|
|
258
|
+
f"SizeBid: {decimalMaxString(self.sizeBid)}, "
|
|
259
|
+
f"SizeAsk: {decimalMaxString(self.sizeAsk)}"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class HistoricalTickLast(Object):
|
|
264
|
+
def __init__(self):
|
|
265
|
+
self.time = 0
|
|
266
|
+
self.tickAttribLast = TickAttribLast()
|
|
267
|
+
self.price = 0.0
|
|
268
|
+
self.size = UNSET_DECIMAL
|
|
269
|
+
self.exchange = ""
|
|
270
|
+
self.specialConditions = ""
|
|
271
|
+
|
|
272
|
+
def __str__(self):
|
|
273
|
+
return (
|
|
274
|
+
f"Time: {intMaxString(self.time)}, "
|
|
275
|
+
f"TickAttribLast: {self.tickAttribLast}, "
|
|
276
|
+
f"Price: {floatMaxString(self.price)}, "
|
|
277
|
+
f"Size: {decimalMaxString(self.size)}, "
|
|
278
|
+
f"Exchange: {self.exchange}, "
|
|
279
|
+
f"SpecialConditions: {self.specialConditions}"
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class HistoricalSession(Object):
|
|
284
|
+
def __init__(self):
|
|
285
|
+
self.startDateTime = ""
|
|
286
|
+
self.endDateTime = ""
|
|
287
|
+
self.refDate = ""
|
|
288
|
+
|
|
289
|
+
def __str__(self):
|
|
290
|
+
return "Start: %s, End: %s, Ref Date: %s" % (
|
|
291
|
+
self.startDateTime,
|
|
292
|
+
self.endDateTime,
|
|
293
|
+
self.refDate,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class WshEventData(Object):
|
|
298
|
+
def __init__(self):
|
|
299
|
+
self.conId = UNSET_INTEGER
|
|
300
|
+
self.filter = ""
|
|
301
|
+
self.fillWatchlist = False
|
|
302
|
+
self.fillPortfolio = False
|
|
303
|
+
self.fillCompetitors = False
|
|
304
|
+
self.startDate = ""
|
|
305
|
+
self.endDate = ""
|
|
306
|
+
self.totalLimit = UNSET_INTEGER
|
|
307
|
+
|
|
308
|
+
def __str__(self):
|
|
309
|
+
return (
|
|
310
|
+
f"WshEventData. ConId: {intMaxString(self.conId)}, "
|
|
311
|
+
f"Filter: {self.filter}, "
|
|
312
|
+
f"Fill Watchlist: {self.fillWatchlist:d}, "
|
|
313
|
+
f"Fill Portfolio: {self.fillPortfolio:d}, "
|
|
314
|
+
f"Fill Competitors: {self.fillCompetitors:d}"
|
|
315
|
+
)
|
ibapi/connection.py
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (C) 2024 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
|
+
Just a thin wrapper around a socket.
|
|
8
|
+
It allows us to keep some other info along with it.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import socket
|
|
12
|
+
import threading
|
|
13
|
+
import logging
|
|
14
|
+
import sys
|
|
15
|
+
from ibapi.errors import FAIL_CREATE_SOCK
|
|
16
|
+
from ibapi.errors import CONNECT_FAIL
|
|
17
|
+
from ibapi.const import NO_VALID_ID
|
|
18
|
+
from ibapi.utils import currentTimeMillis
|
|
19
|
+
|
|
20
|
+
# TODO: support SSL !!
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Connection:
|
|
26
|
+
def __init__(self, host, port):
|
|
27
|
+
self.host = host
|
|
28
|
+
self.port = port
|
|
29
|
+
self.socket = None
|
|
30
|
+
self.wrapper = None
|
|
31
|
+
self.lock = threading.Lock()
|
|
32
|
+
|
|
33
|
+
def connect(self):
|
|
34
|
+
try:
|
|
35
|
+
self.socket = socket.socket()
|
|
36
|
+
# TODO: list the exceptions you want to catch
|
|
37
|
+
except socket.error:
|
|
38
|
+
if self.wrapper:
|
|
39
|
+
self.wrapper.error(
|
|
40
|
+
NO_VALID_ID, currentTimeMillis(), FAIL_CREATE_SOCK.code(), FAIL_CREATE_SOCK.msg()
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
self.socket.connect((self.host, self.port))
|
|
45
|
+
except socket.error:
|
|
46
|
+
if self.wrapper:
|
|
47
|
+
self.wrapper.error(NO_VALID_ID, currentTimeMillis(), CONNECT_FAIL.code(), CONNECT_FAIL.msg())
|
|
48
|
+
|
|
49
|
+
self.socket.settimeout(1) # non-blocking
|
|
50
|
+
|
|
51
|
+
def disconnect(self):
|
|
52
|
+
self.lock.acquire()
|
|
53
|
+
try:
|
|
54
|
+
if self.socket is not None:
|
|
55
|
+
logger.debug("disconnecting")
|
|
56
|
+
self.socket.close()
|
|
57
|
+
self.socket = None
|
|
58
|
+
logger.debug("disconnected")
|
|
59
|
+
if self.wrapper:
|
|
60
|
+
self.wrapper.connectionClosed()
|
|
61
|
+
finally:
|
|
62
|
+
self.lock.release()
|
|
63
|
+
|
|
64
|
+
def isConnected(self):
|
|
65
|
+
return self.socket is not None
|
|
66
|
+
|
|
67
|
+
def sendMsg(self, msg):
|
|
68
|
+
logger.debug("acquiring lock")
|
|
69
|
+
self.lock.acquire()
|
|
70
|
+
logger.debug("acquired lock")
|
|
71
|
+
if not self.isConnected():
|
|
72
|
+
logger.debug("sendMsg attempted while not connected, releasing lock")
|
|
73
|
+
self.lock.release()
|
|
74
|
+
return 0
|
|
75
|
+
try:
|
|
76
|
+
nSent = self.socket.send(msg)
|
|
77
|
+
except socket.error:
|
|
78
|
+
logger.debug("exception from sendMsg %s", sys.exc_info())
|
|
79
|
+
raise
|
|
80
|
+
finally:
|
|
81
|
+
logger.debug("releasing lock")
|
|
82
|
+
self.lock.release()
|
|
83
|
+
logger.debug("release lock")
|
|
84
|
+
|
|
85
|
+
logger.debug("sendMsg: sent: %d", nSent)
|
|
86
|
+
|
|
87
|
+
return nSent
|
|
88
|
+
|
|
89
|
+
def recvMsg(self):
|
|
90
|
+
if not self.isConnected():
|
|
91
|
+
logger.debug("recvMsg attempted while not connected, releasing lock")
|
|
92
|
+
return b""
|
|
93
|
+
try:
|
|
94
|
+
buf = self._recvAllMsg()
|
|
95
|
+
# receiving 0 bytes outside a timeout means the connection is either
|
|
96
|
+
# closed or broken
|
|
97
|
+
if len(buf) == 0:
|
|
98
|
+
logger.debug("socket either closed or broken, disconnecting")
|
|
99
|
+
self.disconnect()
|
|
100
|
+
except socket.timeout:
|
|
101
|
+
logger.debug("socket timeout from recvMsg %s", sys.exc_info())
|
|
102
|
+
buf = b""
|
|
103
|
+
except socket.error:
|
|
104
|
+
logger.debug("socket broken, disconnecting")
|
|
105
|
+
self.disconnect()
|
|
106
|
+
buf = b""
|
|
107
|
+
except OSError:
|
|
108
|
+
# Thrown if the socket was closed (ex: disconnected at end of script)
|
|
109
|
+
# while waiting for self.socket.recv() to timeout.
|
|
110
|
+
logger.debug("Socket is broken or closed.")
|
|
111
|
+
|
|
112
|
+
return buf
|
|
113
|
+
|
|
114
|
+
def _recvAllMsg(self):
|
|
115
|
+
cont = True
|
|
116
|
+
allbuf = b""
|
|
117
|
+
|
|
118
|
+
while cont and self.isConnected():
|
|
119
|
+
buf = self.socket.recv(4096)
|
|
120
|
+
allbuf += buf
|
|
121
|
+
logger.debug("len %d raw:%s|", len(buf), buf)
|
|
122
|
+
|
|
123
|
+
if len(buf) < 4096:
|
|
124
|
+
cont = False
|
|
125
|
+
|
|
126
|
+
return allbuf
|
ibapi/const.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import sys
|
|
3
|
+
from _decimal import Decimal
|
|
4
|
+
|
|
5
|
+
NO_VALID_ID = -1
|
|
6
|
+
MAX_MSG_LEN = 0xFFFFFF # 16Mb - 1byte
|
|
7
|
+
UNSET_INTEGER = 2**31 - 1
|
|
8
|
+
UNSET_DOUBLE = float(sys.float_info.max)
|
|
9
|
+
UNSET_LONG = 2**63 - 1
|
|
10
|
+
UNSET_DECIMAL = Decimal(2**127 - 1)
|
|
11
|
+
DOUBLE_INFINITY = math.inf
|
|
12
|
+
INFINITY_STR = "Infinity"
|