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.
Files changed (57) hide show
  1. ibapi/__init__.py +16 -0
  2. ibapi/account_summary_tags.py +70 -0
  3. ibapi/client.py +4891 -0
  4. ibapi/client_utils.py +412 -0
  5. ibapi/comm.py +100 -0
  6. ibapi/commission_and_fees_report.py +31 -0
  7. ibapi/common.py +315 -0
  8. ibapi/connection.py +126 -0
  9. ibapi/const.py +12 -0
  10. ibapi/contract.py +265 -0
  11. ibapi/decoder.py +1711 -0
  12. ibapi/decoder_utils.py +420 -0
  13. ibapi/enum_implem.py +20 -0
  14. ibapi/errors.py +43 -0
  15. ibapi/execution.py +95 -0
  16. ibapi/ineligibility_reason.py +18 -0
  17. ibapi/message.py +186 -0
  18. ibapi/news.py +13 -0
  19. ibapi/object_implem.py +12 -0
  20. ibapi/order.py +263 -0
  21. ibapi/order_cancel.py +21 -0
  22. ibapi/order_condition.py +289 -0
  23. ibapi/order_state.py +117 -0
  24. ibapi/orderdecoder.py +539 -0
  25. ibapi/protobuf/CancelOrderRequest_pb2.py +38 -0
  26. ibapi/protobuf/ComboLeg_pb2.py +37 -0
  27. ibapi/protobuf/Contract_pb2.py +39 -0
  28. ibapi/protobuf/DeltaNeutralContract_pb2.py +37 -0
  29. ibapi/protobuf/ErrorMessage_pb2.py +37 -0
  30. ibapi/protobuf/ExecutionDetailsEnd_pb2.py +37 -0
  31. ibapi/protobuf/ExecutionDetails_pb2.py +39 -0
  32. ibapi/protobuf/ExecutionFilter_pb2.py +37 -0
  33. ibapi/protobuf/ExecutionRequest_pb2.py +38 -0
  34. ibapi/protobuf/Execution_pb2.py +37 -0
  35. ibapi/protobuf/GlobalCancelRequest_pb2.py +38 -0
  36. ibapi/protobuf/OpenOrder_pb2.py +40 -0
  37. ibapi/protobuf/OpenOrdersEnd_pb2.py +37 -0
  38. ibapi/protobuf/OrderAllocation_pb2.py +37 -0
  39. ibapi/protobuf/OrderCancel_pb2.py +37 -0
  40. ibapi/protobuf/OrderCondition_pb2.py +37 -0
  41. ibapi/protobuf/OrderState_pb2.py +38 -0
  42. ibapi/protobuf/OrderStatus_pb2.py +37 -0
  43. ibapi/protobuf/Order_pb2.py +51 -0
  44. ibapi/protobuf/PlaceOrderRequest_pb2.py +39 -0
  45. ibapi/protobuf/SoftDollarTier_pb2.py +37 -0
  46. ibapi/reader.py +49 -0
  47. ibapi/scanner.py +77 -0
  48. ibapi/server_versions.py +159 -0
  49. ibapi/softdollartier.py +16 -0
  50. ibapi/tag_value.py +22 -0
  51. ibapi/ticktype.py +117 -0
  52. ibapi/utils.py +233 -0
  53. ibapi/wrapper.py +885 -0
  54. ibapi_stable-10.37.2.dist-info/METADATA +136 -0
  55. ibapi_stable-10.37.2.dist-info/RECORD +57 -0
  56. ibapi_stable-10.37.2.dist-info/WHEEL +5 -0
  57. ibapi_stable-10.37.2.dist-info/top_level.txt +1 -0
ibapi/decoder.py ADDED
@@ -0,0 +1,1711 @@
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
+ from ibapi.const import NO_VALID_ID
6
+ from ibapi.utils import getEnumTypeFromString
7
+ from ibapi.common import PROTOBUF_MSG_ID
8
+
9
+ """
10
+ The Decoder knows how to transform a message's payload into higher level
11
+ IB message (eg: order info, mkt data, etc).
12
+ It will call the corresponding method from the EWrapper so that customer's code
13
+ (eg: class derived from EWrapper) can make further use of the data.
14
+ """
15
+
16
+ from ibapi.message import IN
17
+ from ibapi.wrapper import * # @UnusedWildImport
18
+ from ibapi.contract import ContractDescription
19
+ from ibapi.server_versions import * # @UnusedWildImport
20
+ from ibapi.utils import * # @UnusedWildImport
21
+ from ibapi.softdollartier import SoftDollarTier
22
+ from ibapi.ticktype import * # @UnusedWildImport
23
+ from ibapi.tag_value import TagValue
24
+ from ibapi.scanner import ScanData
25
+ from ibapi.errors import BAD_MESSAGE
26
+ from ibapi.common import * # @UnusedWildImport
27
+ from ibapi.orderdecoder import OrderDecoder
28
+ from ibapi.contract import FundDistributionPolicyIndicator
29
+ from ibapi.contract import FundAssetType
30
+ from ibapi.ineligibility_reason import IneligibilityReason
31
+ from ibapi.decoder_utils import decodeContract, decodeOrder, decodeExecution, decodeOrderState
32
+
33
+ from ibapi.protobuf.OrderStatus_pb2 import OrderStatus as OrderStatusProto
34
+ from ibapi.protobuf.OpenOrder_pb2 import OpenOrder as OpenOrderProto
35
+ from ibapi.protobuf.OpenOrdersEnd_pb2 import OpenOrdersEnd as OpenOrdersEndProto
36
+ from ibapi.protobuf.ErrorMessage_pb2 import ErrorMessage as ErrorMessageProto
37
+ from ibapi.protobuf.ExecutionDetails_pb2 import ExecutionDetails as ExecutionDetailsProto
38
+ from ibapi.protobuf.ExecutionDetailsEnd_pb2 import ExecutionDetailsEnd as ExecutionDetailsEndProto
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+
43
+ class HandleInfo(Object):
44
+ def __init__(self, wrap=None, proc=None):
45
+ self.wrapperMeth = wrap
46
+ self.wrapperParams = None
47
+ self.processMeth = proc
48
+ if wrap is None and proc is None:
49
+ raise ValueError("both wrap and proc can't be None")
50
+
51
+ def __str__(self):
52
+ s = f"wrap:{self.wrapperMeth} meth:{self.processMeth} prms:{self.wrapperParams}"
53
+ return s
54
+
55
+
56
+ class Decoder(Object):
57
+ def __init__(self, wrapper, serverVersion):
58
+ self.wrapper = wrapper
59
+ self.serverVersion = serverVersion
60
+ self.discoverParams()
61
+
62
+ def processTickPriceMsg(self, fields):
63
+ decode(int, fields)
64
+
65
+ reqId = decode(int, fields)
66
+ tickType = decode(int, fields)
67
+ price = decode(float, fields)
68
+ size = decode(Decimal, fields) # ver 2 field
69
+ attrMask = decode(int, fields) # ver 3 field
70
+
71
+ attrib = TickAttrib()
72
+
73
+ attrib.canAutoExecute = attrMask == 1
74
+
75
+ if self.serverVersion >= MIN_SERVER_VER_PAST_LIMIT:
76
+ attrib.canAutoExecute = attrMask & 1 != 0
77
+ attrib.pastLimit = attrMask & 2 != 0
78
+ if self.serverVersion >= MIN_SERVER_VER_PRE_OPEN_BID_ASK:
79
+ attrib.preOpen = attrMask & 4 != 0
80
+
81
+ self.wrapper.tickPrice(reqId, tickType, price, attrib)
82
+
83
+ # process ver 2 fields
84
+ sizeTickType = TickTypeEnum.NOT_SET
85
+ if TickTypeEnum.BID == tickType:
86
+ sizeTickType = TickTypeEnum.BID_SIZE
87
+ elif TickTypeEnum.ASK == tickType:
88
+ sizeTickType = TickTypeEnum.ASK_SIZE
89
+ elif TickTypeEnum.LAST == tickType:
90
+ sizeTickType = TickTypeEnum.LAST_SIZE
91
+ elif TickTypeEnum.DELAYED_BID == tickType:
92
+ sizeTickType = TickTypeEnum.DELAYED_BID_SIZE
93
+ elif TickTypeEnum.DELAYED_ASK == tickType:
94
+ sizeTickType = TickTypeEnum.DELAYED_ASK_SIZE
95
+ elif TickTypeEnum.DELAYED_LAST == tickType:
96
+ sizeTickType = TickTypeEnum.DELAYED_LAST_SIZE
97
+
98
+ if sizeTickType != TickTypeEnum.NOT_SET:
99
+ self.wrapper.tickSize(reqId, sizeTickType, size)
100
+
101
+ def processTickSizeMsg(self, fields):
102
+ decode(int, fields)
103
+
104
+ reqId = decode(int, fields)
105
+ sizeTickType = decode(int, fields)
106
+ size = decode(Decimal, fields)
107
+
108
+ if sizeTickType != TickTypeEnum.NOT_SET:
109
+ self.wrapper.tickSize(reqId, sizeTickType, size)
110
+
111
+ def processOrderStatusMsg(self, fields):
112
+ if self.serverVersion < MIN_SERVER_VER_MARKET_CAP_PRICE:
113
+ decode(int, fields)
114
+ orderId = decode(int, fields)
115
+ status = decode(str, fields)
116
+ filled = decode(Decimal, fields)
117
+ remaining = decode(Decimal, fields)
118
+ avgFillPrice = decode(float, fields)
119
+
120
+ permId = decode(int, fields) # ver 2 field
121
+ parentId = decode(int, fields) # ver 3 field
122
+ lastFillPrice = decode(float, fields) # ver 4 field
123
+ clientId = decode(int, fields) # ver 5 field
124
+ whyHeld = decode(str, fields) # ver 6 field
125
+
126
+ if self.serverVersion >= MIN_SERVER_VER_MARKET_CAP_PRICE:
127
+ mktCapPrice = decode(float, fields)
128
+ else:
129
+ mktCapPrice = None
130
+
131
+ self.wrapper.orderStatus(
132
+ orderId,
133
+ status,
134
+ filled,
135
+ remaining,
136
+ avgFillPrice,
137
+ permId,
138
+ parentId,
139
+ lastFillPrice,
140
+ clientId,
141
+ whyHeld,
142
+ mktCapPrice,
143
+ )
144
+
145
+ def processOrderStatusMsgProtoBuf(self, protobuf):
146
+ orderStatusProto = OrderStatusProto()
147
+ orderStatusProto.ParseFromString(protobuf)
148
+
149
+ self.wrapper.orderStatusProtoBuf(orderStatusProto)
150
+
151
+ orderId = orderStatusProto.orderId if orderStatusProto.HasField('orderId') else UNSET_INTEGER
152
+ status = orderStatusProto.status if orderStatusProto.HasField('status') else ""
153
+ filled = orderStatusProto.filled if orderStatusProto.HasField('filled') else UNSET_DECIMAL
154
+ remaining = orderStatusProto.remaining if orderStatusProto.HasField('remaining') else UNSET_DECIMAL
155
+ avgFillPrice = orderStatusProto.avgFillPrice if orderStatusProto.HasField('avgFillPrice') else UNSET_DOUBLE
156
+ permId = orderStatusProto.permId if orderStatusProto.HasField('permId') else UNSET_LONG
157
+ parentId = orderStatusProto.parentId if orderStatusProto.HasField('parentId') else UNSET_INTEGER
158
+ lastFillPrice = orderStatusProto.lastFillPrice if orderStatusProto.HasField('lastFillPrice') else UNSET_DOUBLE
159
+ clientId = orderStatusProto.clientId if orderStatusProto.HasField('clientId') else UNSET_INTEGER
160
+ whyHeld = orderStatusProto.whyHeld if orderStatusProto.HasField('whyHeld') else ""
161
+ mktCapPrice = orderStatusProto.mktCapPrice if orderStatusProto.HasField('mktCapPrice') else UNSET_DOUBLE
162
+
163
+ self.wrapper.orderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice)
164
+
165
+ def processOpenOrder(self, fields):
166
+ order = Order()
167
+ contract = Contract()
168
+ orderState = OrderState()
169
+
170
+ if self.serverVersion < MIN_SERVER_VER_ORDER_CONTAINER:
171
+ version = decode(int, fields)
172
+ else:
173
+ version = self.serverVersion
174
+
175
+ OrderDecoder.__init__(
176
+ self, contract, order, orderState, version, self.serverVersion
177
+ )
178
+
179
+ # read orderId
180
+ OrderDecoder.decodeOrderId(self, fields)
181
+
182
+ # read contract fields
183
+ OrderDecoder.decodeContractFields(self, fields)
184
+
185
+ # read order fields
186
+ OrderDecoder.decodeAction(self, fields)
187
+ OrderDecoder.decodeTotalQuantity(self, fields)
188
+ OrderDecoder.decodeOrderType(self, fields)
189
+ OrderDecoder.decodeLmtPrice(self, fields)
190
+ OrderDecoder.decodeAuxPrice(self, fields)
191
+ OrderDecoder.decodeTIF(self, fields)
192
+ OrderDecoder.decodeOcaGroup(self, fields)
193
+ OrderDecoder.decodeAccount(self, fields)
194
+ OrderDecoder.decodeOpenClose(self, fields)
195
+ OrderDecoder.decodeOrigin(self, fields)
196
+ OrderDecoder.decodeOrderRef(self, fields)
197
+ OrderDecoder.decodeClientId(self, fields)
198
+ OrderDecoder.decodePermId(self, fields)
199
+ OrderDecoder.decodeOutsideRth(self, fields)
200
+ OrderDecoder.decodeHidden(self, fields)
201
+ OrderDecoder.decodeDiscretionaryAmt(self, fields)
202
+ OrderDecoder.decodeGoodAfterTime(self, fields)
203
+ OrderDecoder.skipSharesAllocation(self, fields)
204
+ OrderDecoder.decodeFAParams(self, fields)
205
+ OrderDecoder.decodeModelCode(self, fields)
206
+ OrderDecoder.decodeGoodTillDate(self, fields)
207
+ OrderDecoder.decodeRule80A(self, fields)
208
+ OrderDecoder.decodePercentOffset(self, fields)
209
+ OrderDecoder.decodeSettlingFirm(self, fields)
210
+ OrderDecoder.decodeShortSaleParams(self, fields)
211
+ OrderDecoder.decodeAuctionStrategy(self, fields)
212
+ OrderDecoder.decodeBoxOrderParams(self, fields)
213
+ OrderDecoder.decodePegToStkOrVolOrderParams(self, fields)
214
+ OrderDecoder.decodeDisplaySize(self, fields)
215
+ OrderDecoder.decodeBlockOrder(self, fields)
216
+ OrderDecoder.decodeSweepToFill(self, fields)
217
+ OrderDecoder.decodeAllOrNone(self, fields)
218
+ OrderDecoder.decodeMinQty(self, fields)
219
+ OrderDecoder.decodeOcaType(self, fields)
220
+ OrderDecoder.skipETradeOnly(self, fields)
221
+ OrderDecoder.skipFirmQuoteOnly(self, fields)
222
+ OrderDecoder.skipNbboPriceCap(self, fields)
223
+ OrderDecoder.decodeParentId(self, fields)
224
+ OrderDecoder.decodeTriggerMethod(self, fields)
225
+ OrderDecoder.decodeVolOrderParams(self, fields, True)
226
+ OrderDecoder.decodeTrailParams(self, fields)
227
+ OrderDecoder.decodeBasisPoints(self, fields)
228
+ OrderDecoder.decodeComboLegs(self, fields)
229
+ OrderDecoder.decodeSmartComboRoutingParams(self, fields)
230
+ OrderDecoder.decodeScaleOrderParams(self, fields)
231
+ OrderDecoder.decodeHedgeParams(self, fields)
232
+ OrderDecoder.decodeOptOutSmartRouting(self, fields)
233
+ OrderDecoder.decodeClearingParams(self, fields)
234
+ OrderDecoder.decodeNotHeld(self, fields)
235
+ OrderDecoder.decodeDeltaNeutral(self, fields)
236
+ OrderDecoder.decodeAlgoParams(self, fields)
237
+ OrderDecoder.decodeSolicited(self, fields)
238
+ OrderDecoder.decodeWhatIfInfoAndCommissionAndFees(self, fields)
239
+ OrderDecoder.decodeVolRandomizeFlags(self, fields)
240
+ OrderDecoder.decodePegToBenchParams(self, fields)
241
+ OrderDecoder.decodeConditions(self, fields)
242
+ OrderDecoder.decodeAdjustedOrderParams(self, fields)
243
+ OrderDecoder.decodeSoftDollarTier(self, fields)
244
+ OrderDecoder.decodeCashQty(self, fields)
245
+ OrderDecoder.decodeDontUseAutoPriceForHedge(self, fields)
246
+ OrderDecoder.decodeIsOmsContainers(self, fields)
247
+ OrderDecoder.decodeDiscretionaryUpToLimitPrice(self, fields)
248
+ OrderDecoder.decodeUsePriceMgmtAlgo(self, fields)
249
+ OrderDecoder.decodeDuration(self, fields)
250
+ OrderDecoder.decodePostToAts(self, fields)
251
+ OrderDecoder.decodeAutoCancelParent(
252
+ self, fields, MIN_SERVER_VER_AUTO_CANCEL_PARENT
253
+ )
254
+ OrderDecoder.decodePegBestPegMidOrderAttributes(self, fields)
255
+ OrderDecoder.decodeCustomerAccount(self, fields)
256
+ OrderDecoder.decodeProfessionalCustomer(self, fields)
257
+ OrderDecoder.decodeBondAccruedInterest(self, fields)
258
+ OrderDecoder.decodeIncludeOvernight(self, fields)
259
+ OrderDecoder.decodeCMETaggingFields(self, fields)
260
+ OrderDecoder.decodeSubmitter(self, fields)
261
+ OrderDecoder.decodeImbalanceOnly(
262
+ self, fields, MIN_SERVER_VER_IMBALANCE_ONLY
263
+ )
264
+
265
+ self.wrapper.openOrder(order.orderId, contract, order, orderState)
266
+
267
+ def processOpenOrderMsgProtoBuf(self, protobuf):
268
+ openOrderProto = OpenOrderProto()
269
+ openOrderProto.ParseFromString(protobuf)
270
+
271
+ self.wrapper.openOrderProtoBuf(openOrderProto)
272
+
273
+ orderId = openOrderProto.orderId if openOrderProto.HasField('orderId') else 0
274
+
275
+ # decode contract fields
276
+ if not openOrderProto.HasField('contract'):
277
+ return
278
+ contract = decodeContract(openOrderProto.contract)
279
+
280
+ # decode order fields
281
+ if not openOrderProto.HasField('order'):
282
+ return
283
+ order = decodeOrder(openOrderProto.contract, openOrderProto.order)
284
+
285
+ # decode order state fields
286
+ if not openOrderProto.HasField('orderState'):
287
+ return
288
+ orderState = decodeOrderState(openOrderProto.orderState)
289
+
290
+ self.wrapper.openOrder(orderId, contract, order, orderState);
291
+
292
+ def processOpenOrdersEndMsgProtoBuf(self, protobuf):
293
+ openOrdersEndProto = OpenOrdersEndProto()
294
+ openOrdersEndProto.ParseFromString(protobuf)
295
+
296
+ self.wrapper.openOrdersEndProtoBuf(openOrdersEndProto)
297
+
298
+ self.wrapper.openOrderEnd()
299
+
300
+ def processPortfolioValueMsg(self, fields):
301
+ version = decode(int, fields)
302
+
303
+ # read contract fields
304
+ contract = Contract()
305
+ contract.conId = decode(int, fields) # ver 6 field
306
+ contract.symbol = decode(str, fields)
307
+ contract.secType = decode(str, fields)
308
+ contract.lastTradeDateOrContractMonth = decode(str, fields)
309
+ contract.strike = decode(float, fields)
310
+ contract.right = decode(str, fields)
311
+
312
+ if version >= 7:
313
+ contract.multiplier = decode(str, fields)
314
+ contract.primaryExchange = decode(str, fields)
315
+
316
+ contract.currency = decode(str, fields)
317
+ contract.localSymbol = decode(str, fields) # ver 2 field
318
+ if version >= 8:
319
+ contract.tradingClass = decode(str, fields)
320
+
321
+ position = decode(Decimal, fields)
322
+
323
+ marketPrice = decode(float, fields)
324
+ marketValue = decode(float, fields)
325
+ averageCost = decode(float, fields) # ver 3 field
326
+ unrealizedPNL = decode(float, fields) # ver 3 field
327
+ realizedPNL = decode(float, fields) # ver 3 field
328
+
329
+ accountName = decode(str, fields) # ver 4 field
330
+
331
+ if version == 6 and self.serverVersion == 39:
332
+ contract.primaryExchange = decode(str, fields)
333
+
334
+ self.wrapper.updatePortfolio(
335
+ contract,
336
+ position,
337
+ marketPrice,
338
+ marketValue,
339
+ averageCost,
340
+ unrealizedPNL,
341
+ realizedPNL,
342
+ accountName,
343
+ )
344
+
345
+ def processContractDataMsg(self, fields):
346
+ version = 8
347
+ if self.serverVersion < MIN_SERVER_VER_SIZE_RULES:
348
+ version = decode(int, fields)
349
+
350
+ reqId = -1
351
+ if version >= 3:
352
+ reqId = decode(int, fields)
353
+
354
+ contract = ContractDetails()
355
+ contract.contract.symbol = decode(str, fields)
356
+ contract.contract.secType = decode(str, fields)
357
+ self.readLastTradeDate(fields, contract, False)
358
+ if self.serverVersion >= MIN_SERVER_VER_LAST_TRADE_DATE:
359
+ contract.contract.lastTradeDate = decode(str, fields)
360
+ contract.contract.strike = decode(float, fields)
361
+ contract.contract.right = decode(str, fields)
362
+ contract.contract.exchange = decode(str, fields)
363
+ contract.contract.currency = decode(str, fields)
364
+ contract.contract.localSymbol = decode(str, fields)
365
+ contract.marketName = decode(str, fields)
366
+ contract.contract.tradingClass = decode(str, fields)
367
+ contract.contract.conId = decode(int, fields)
368
+ contract.minTick = decode(float, fields)
369
+ if (
370
+ self.serverVersion >= MIN_SERVER_VER_MD_SIZE_MULTIPLIER
371
+ and self.serverVersion < MIN_SERVER_VER_SIZE_RULES
372
+ ):
373
+ decode(int, fields) # mdSizeMultiplier - not used anymore
374
+ contract.contract.multiplier = decode(str, fields)
375
+ contract.orderTypes = decode(str, fields)
376
+ contract.validExchanges = decode(str, fields)
377
+ contract.priceMagnifier = decode(int, fields) # ver 2 field
378
+ if version >= 4:
379
+ contract.underConId = decode(int, fields)
380
+ if version >= 5:
381
+ contract.longName = (
382
+ decode(str, fields).encode().decode("unicode-escape")
383
+ if self.serverVersion >= MIN_SERVER_VER_ENCODE_MSG_ASCII7
384
+ else decode(str, fields)
385
+ )
386
+ contract.contract.primaryExchange = decode(str, fields)
387
+ if version >= 6:
388
+ contract.contractMonth = decode(str, fields)
389
+ contract.industry = decode(str, fields)
390
+ contract.category = decode(str, fields)
391
+ contract.subcategory = decode(str, fields)
392
+ contract.timeZoneId = decode(str, fields)
393
+ contract.tradingHours = decode(str, fields)
394
+ contract.liquidHours = decode(str, fields)
395
+ if version >= 8:
396
+ contract.evRule = decode(str, fields)
397
+ contract.evMultiplier = decode(int, fields)
398
+ if version >= 7:
399
+ secIdListCount = decode(int, fields)
400
+ if secIdListCount > 0:
401
+ contract.secIdList = []
402
+ for _ in range(secIdListCount):
403
+ tagValue = TagValue()
404
+ tagValue.tag = decode(str, fields)
405
+ tagValue.value = decode(str, fields)
406
+ contract.secIdList.append(tagValue)
407
+
408
+ if self.serverVersion >= MIN_SERVER_VER_AGG_GROUP:
409
+ contract.aggGroup = decode(int, fields)
410
+
411
+ if self.serverVersion >= MIN_SERVER_VER_UNDERLYING_INFO:
412
+ contract.underSymbol = decode(str, fields)
413
+ contract.underSecType = decode(str, fields)
414
+
415
+ if self.serverVersion >= MIN_SERVER_VER_MARKET_RULES:
416
+ contract.marketRuleIds = decode(str, fields)
417
+
418
+ if self.serverVersion >= MIN_SERVER_VER_REAL_EXPIRATION_DATE:
419
+ contract.realExpirationDate = decode(str, fields)
420
+
421
+ if self.serverVersion >= MIN_SERVER_VER_STOCK_TYPE:
422
+ contract.stockType = decode(str, fields)
423
+
424
+ if (
425
+ self.serverVersion >= MIN_SERVER_VER_FRACTIONAL_SIZE_SUPPORT
426
+ and self.serverVersion < MIN_SERVER_VER_SIZE_RULES
427
+ ):
428
+ decode(Decimal, fields) # sizeMinTick - not used anymore
429
+
430
+ if self.serverVersion >= MIN_SERVER_VER_SIZE_RULES:
431
+ contract.minSize = decode(Decimal, fields)
432
+ contract.sizeIncrement = decode(Decimal, fields)
433
+ contract.suggestedSizeIncrement = decode(Decimal, fields)
434
+
435
+ if (
436
+ self.serverVersion >= MIN_SERVER_VER_FUND_DATA_FIELDS
437
+ and contract.contract.secType == "FUND"
438
+ ):
439
+ contract.fundName = decode(str, fields)
440
+ contract.fundFamily = decode(str, fields)
441
+ contract.fundType = decode(str, fields)
442
+ contract.fundFrontLoad = decode(str, fields)
443
+ contract.fundBackLoad = decode(str, fields)
444
+ contract.fundBackLoadTimeInterval = decode(str, fields)
445
+ contract.fundManagementFee = decode(str, fields)
446
+ contract.fundClosed = decode(bool, fields)
447
+ contract.fundClosedForNewInvestors = decode(bool, fields)
448
+ contract.fundClosedForNewMoney = decode(bool, fields)
449
+ contract.fundNotifyAmount = decode(str, fields)
450
+ contract.fundMinimumInitialPurchase = decode(str, fields)
451
+ contract.fundSubsequentMinimumPurchase = decode(str, fields)
452
+ contract.fundBlueSkyStates = decode(str, fields)
453
+ contract.fundBlueSkyTerritories = decode(str, fields)
454
+ contract.fundDistributionPolicyIndicator = getEnumTypeFromString(FundDistributionPolicyIndicator, decode(str, fields))
455
+ contract.fundAssetType = getEnumTypeFromString(FundAssetType, decode(str, fields))
456
+
457
+ if self.serverVersion >= MIN_SERVER_VER_INELIGIBILITY_REASONS:
458
+ ineligibilityReasonListCount = decode(int, fields)
459
+ if ineligibilityReasonListCount > 0:
460
+ contract.ineligibilityReasonList = []
461
+ for _ in range(ineligibilityReasonListCount):
462
+ ineligibilityReason = IneligibilityReason()
463
+ ineligibilityReason.id_ = decode(str, fields)
464
+ ineligibilityReason.description = decode(str, fields)
465
+ contract.ineligibilityReasonList.append(ineligibilityReason)
466
+
467
+ self.wrapper.contractDetails(reqId, contract)
468
+
469
+ def processBondContractDataMsg(self, fields):
470
+ version = 6
471
+ if self.serverVersion < MIN_SERVER_VER_SIZE_RULES:
472
+ version = decode(int, fields)
473
+
474
+ reqId = -1
475
+ if version >= 3:
476
+ reqId = decode(int, fields)
477
+
478
+ contract = ContractDetails()
479
+ contract.contract.symbol = decode(str, fields)
480
+ contract.contract.secType = decode(str, fields)
481
+ contract.cusip = decode(str, fields)
482
+ contract.coupon = decode(float, fields)
483
+ self.readLastTradeDate(fields, contract, True)
484
+ contract.issueDate = decode(str, fields)
485
+ contract.ratings = decode(str, fields)
486
+ contract.bondType = decode(str, fields)
487
+ contract.couponType = decode(str, fields)
488
+ contract.convertible = decode(bool, fields)
489
+ contract.callable = decode(bool, fields)
490
+ contract.putable = decode(bool, fields)
491
+ contract.descAppend = decode(str, fields)
492
+ contract.contract.exchange = decode(str, fields)
493
+ contract.contract.currency = decode(str, fields)
494
+ contract.marketName = decode(str, fields)
495
+ contract.contract.tradingClass = decode(str, fields)
496
+ contract.contract.conId = decode(int, fields)
497
+ contract.minTick = decode(float, fields)
498
+ if (
499
+ self.serverVersion >= MIN_SERVER_VER_MD_SIZE_MULTIPLIER
500
+ and self.serverVersion < MIN_SERVER_VER_SIZE_RULES
501
+ ):
502
+ decode(int, fields) # mdSizeMultiplier - not used anymore
503
+ contract.orderTypes = decode(str, fields)
504
+ contract.validExchanges = decode(str, fields)
505
+ contract.nextOptionDate = decode(str, fields) # ver 2 field
506
+ contract.nextOptionType = decode(str, fields) # ver 2 field
507
+ contract.nextOptionPartial = decode(bool, fields) # ver 2 field
508
+ contract.notes = decode(str, fields) # ver 2 field
509
+ if version >= 4:
510
+ contract.longName = decode(str, fields)
511
+ if self.serverVersion >= MIN_SERVER_VER_BOND_TRADING_HOURS:
512
+ contract.timeZoneId = decode(str, fields)
513
+ contract.tradingHours = decode(str, fields)
514
+ contract.liquidHours = decode(str, fields)
515
+ if version >= 6:
516
+ contract.evRule = decode(str, fields)
517
+ contract.evMultiplier = decode(int, fields)
518
+ if version >= 5:
519
+ secIdListCount = decode(int, fields)
520
+ if secIdListCount > 0:
521
+ contract.secIdList = []
522
+ for _ in range(secIdListCount):
523
+ tagValue = TagValue()
524
+ tagValue.tag = decode(str, fields)
525
+ tagValue.value = decode(str, fields)
526
+ contract.secIdList.append(tagValue)
527
+
528
+ if self.serverVersion >= MIN_SERVER_VER_AGG_GROUP:
529
+ contract.aggGroup = decode(int, fields)
530
+
531
+ if self.serverVersion >= MIN_SERVER_VER_MARKET_RULES:
532
+ contract.marketRuleIds = decode(str, fields)
533
+
534
+ if self.serverVersion >= MIN_SERVER_VER_SIZE_RULES:
535
+ contract.minSize = decode(Decimal, fields)
536
+ contract.sizeIncrement = decode(Decimal, fields)
537
+ contract.suggestedSizeIncrement = decode(Decimal, fields)
538
+
539
+ self.wrapper.bondContractDetails(reqId, contract)
540
+
541
+ def processScannerDataMsg(self, fields):
542
+ decode(int, fields)
543
+ reqId = decode(int, fields)
544
+
545
+ numberOfElements = decode(int, fields)
546
+
547
+ for _ in range(numberOfElements):
548
+ data = ScanData()
549
+ data.contract = ContractDetails()
550
+
551
+ data.rank = decode(int, fields)
552
+ data.contract.contract.conId = decode(int, fields) # ver 3 field
553
+ data.contract.contract.symbol = decode(str, fields)
554
+ data.contract.contract.secType = decode(str, fields)
555
+ data.contract.contract.lastTradeDateOrContractMonth = decode(str, fields)
556
+ data.contract.contract.strike = decode(float, fields)
557
+ data.contract.contract.right = decode(str, fields)
558
+ data.contract.contract.exchange = decode(str, fields)
559
+ data.contract.contract.currency = decode(str, fields)
560
+ data.contract.contract.localSymbol = decode(str, fields)
561
+ data.contract.marketName = decode(str, fields)
562
+ data.contract.contract.tradingClass = decode(str, fields)
563
+ data.distance = decode(str, fields)
564
+ data.benchmark = decode(str, fields)
565
+ data.projection = decode(str, fields)
566
+ data.legsStr = decode(str, fields)
567
+ self.wrapper.scannerData(
568
+ reqId,
569
+ data.rank,
570
+ data.contract,
571
+ data.distance,
572
+ data.benchmark,
573
+ data.projection,
574
+ data.legsStr,
575
+ )
576
+
577
+ self.wrapper.scannerDataEnd(reqId)
578
+
579
+ def processExecutionDataMsg(self, fields):
580
+ version = self.serverVersion
581
+
582
+ if self.serverVersion < MIN_SERVER_VER_LAST_LIQUIDITY:
583
+ version = decode(int, fields)
584
+
585
+ reqId = -1
586
+ if version >= 7:
587
+ reqId = decode(int, fields)
588
+
589
+ orderId = decode(int, fields)
590
+
591
+ # decode contract fields
592
+ contract = Contract()
593
+ contract.conId = decode(int, fields) # ver 5 field
594
+ contract.symbol = decode(str, fields)
595
+ contract.secType = decode(str, fields)
596
+ contract.lastTradeDateOrContractMonth = decode(str, fields)
597
+ contract.strike = decode(float, fields)
598
+ contract.right = decode(str, fields)
599
+ if version >= 9:
600
+ contract.multiplier = decode(str, fields)
601
+ contract.exchange = decode(str, fields)
602
+ contract.currency = decode(str, fields)
603
+ contract.localSymbol = decode(str, fields)
604
+ if version >= 10:
605
+ contract.tradingClass = decode(str, fields)
606
+
607
+ # decode execution fields
608
+ execution = Execution()
609
+ execution.orderId = orderId
610
+ execution.execId = decode(str, fields)
611
+ execution.time = decode(str, fields)
612
+ execution.acctNumber = decode(str, fields)
613
+ execution.exchange = decode(str, fields)
614
+ execution.side = decode(str, fields)
615
+ execution.shares = decode(Decimal, fields)
616
+ execution.price = decode(float, fields)
617
+ execution.permId = decode(int, fields) # ver 2 field
618
+ execution.clientId = decode(int, fields) # ver 3 field
619
+ execution.liquidation = decode(int, fields) # ver 4 field
620
+
621
+ if version >= 6:
622
+ execution.cumQty = decode(Decimal, fields)
623
+ execution.avgPrice = decode(float, fields)
624
+
625
+ if version >= 8:
626
+ execution.orderRef = decode(str, fields)
627
+
628
+ if version >= 9:
629
+ execution.evRule = decode(str, fields)
630
+ execution.evMultiplier = decode(float, fields)
631
+ if self.serverVersion >= MIN_SERVER_VER_MODELS_SUPPORT:
632
+ execution.modelCode = decode(str, fields)
633
+ if self.serverVersion >= MIN_SERVER_VER_LAST_LIQUIDITY:
634
+ execution.lastLiquidity = decode(int, fields)
635
+ if self.serverVersion >= MIN_SERVER_VER_PENDING_PRICE_REVISION:
636
+ execution.pendingPriceRevision = decode(bool, fields)
637
+ if self.serverVersion >= MIN_SERVER_VER_SUBMITTER:
638
+ execution.submitter = decode(str, fields)
639
+
640
+ self.wrapper.execDetails(reqId, contract, execution)
641
+
642
+ def processExecutionDataEndMsgProtoBuf(self, protobuf):
643
+ executionDetailsEndProto = ExecutionDetailsEndProto()
644
+ executionDetailsEndProto.ParseFromString(protobuf)
645
+
646
+ self.wrapper.executionDetailsEndProtoBuf(executionDetailsEndProto)
647
+
648
+ reqId = executionDetailsEndProto.reqId if executionDetailsEndProto.HasField('reqId') else 0
649
+
650
+ self.wrapper.execDetailsEnd(reqId)
651
+
652
+ def processExecutionDataMsgProtoBuf(self, protobuf):
653
+ executionDetailsProto = ExecutionDetailsProto()
654
+ executionDetailsProto.ParseFromString(protobuf)
655
+
656
+ self.wrapper.executionDetailsProtoBuf(executionDetailsProto)
657
+
658
+ reqId = executionDetailsProto.reqId if executionDetailsProto.HasField('reqId') else 0
659
+
660
+ # decode contract fields
661
+ if not executionDetailsProto.HasField('contract'):
662
+ return
663
+ contract = decodeContract(executionDetailsProto.contract)
664
+
665
+ # decode execution fields
666
+ if not executionDetailsProto.HasField('execution'):
667
+ return
668
+ execution = decodeExecution(executionDetailsProto.execution)
669
+
670
+ self.wrapper.execDetails(reqId, contract, execution)
671
+
672
+ def processHistoricalDataMsg(self, fields):
673
+ if self.serverVersion < MIN_SERVER_VER_SYNT_REALTIME_BARS:
674
+ decode(int, fields)
675
+
676
+ reqId = decode(int, fields)
677
+
678
+ if self.serverVersion < MIN_SERVER_VER_HISTORICAL_DATA_END:
679
+ startDateStr = decode(str, fields) # ver 2 field
680
+ endDateStr = decode(str, fields) # ver 2 field
681
+
682
+ itemCount = decode(int, fields)
683
+
684
+ for _ in range(itemCount):
685
+ bar = BarData()
686
+ bar.date = decode(str, fields)
687
+ bar.open = decode(float, fields)
688
+ bar.high = decode(float, fields)
689
+ bar.low = decode(float, fields)
690
+ bar.close = decode(float, fields)
691
+ bar.volume = decode(Decimal, fields)
692
+ bar.wap = decode(Decimal, fields)
693
+
694
+ if self.serverVersion < MIN_SERVER_VER_SYNT_REALTIME_BARS:
695
+ decode(str, fields)
696
+
697
+ bar.barCount = decode(int, fields) # ver 3 field
698
+
699
+ self.wrapper.historicalData(reqId, bar)
700
+
701
+ if self.serverVersion < MIN_SERVER_VER_HISTORICAL_DATA_END:
702
+ # send end of dataset marker
703
+ self.wrapper.historicalDataEnd(reqId, startDateStr, endDateStr)
704
+
705
+
706
+ def processHistoricalDataEndMsg(self, fields):
707
+ reqId = decode(int, fields)
708
+ startDateStr = decode(str, fields)
709
+ endDateStr = decode(str, fields)
710
+
711
+ self.wrapper.historicalDataEnd(reqId, startDateStr, endDateStr)
712
+
713
+ def processHistoricalDataUpdateMsg(self, fields):
714
+ reqId = decode(int, fields)
715
+ bar = BarData()
716
+ bar.barCount = decode(int, fields)
717
+ bar.date = decode(str, fields)
718
+ bar.open = decode(float, fields)
719
+ bar.close = decode(float, fields)
720
+ bar.high = decode(float, fields)
721
+ bar.low = decode(float, fields)
722
+ bar.wap = decode(Decimal, fields)
723
+ bar.volume = decode(Decimal, fields)
724
+ self.wrapper.historicalDataUpdate(reqId, bar)
725
+
726
+ def processRealTimeBarMsg(self, fields):
727
+ decode(int, fields)
728
+ reqId = decode(int, fields)
729
+
730
+ bar = RealTimeBar()
731
+ bar.time = decode(int, fields)
732
+ bar.open = decode(float, fields)
733
+ bar.high = decode(float, fields)
734
+ bar.low = decode(float, fields)
735
+ bar.close = decode(float, fields)
736
+ bar.volume = decode(Decimal, fields)
737
+ bar.wap = decode(Decimal, fields)
738
+ bar.count = decode(int, fields)
739
+
740
+ self.wrapper.realtimeBar(
741
+ reqId,
742
+ bar.time,
743
+ bar.open,
744
+ bar.high,
745
+ bar.low,
746
+ bar.close,
747
+ bar.volume,
748
+ bar.wap,
749
+ bar.count,
750
+ )
751
+
752
+ def processTickOptionComputationMsg(self, fields):
753
+ version = self.serverVersion
754
+ tickAttrib = None
755
+ optPrice = None
756
+ pvDividend = None
757
+ gamma = None
758
+ vega = None
759
+ theta = None
760
+ undPrice = None
761
+
762
+ if self.serverVersion < MIN_SERVER_VER_PRICE_BASED_VOLATILITY:
763
+ version = decode(int, fields)
764
+
765
+ reqId = decode(int, fields)
766
+ tickTypeInt = decode(int, fields)
767
+
768
+ if self.serverVersion >= MIN_SERVER_VER_PRICE_BASED_VOLATILITY:
769
+ tickAttrib = decode(int, fields)
770
+
771
+ impliedVol = decode(float, fields)
772
+ delta = decode(float, fields)
773
+
774
+ if impliedVol < 0: # -1 is the "not computed" indicator
775
+ impliedVol = None
776
+ if delta == -2: # -2 is the "not computed" indicator
777
+ delta = None
778
+
779
+ if (
780
+ version >= 6
781
+ or tickTypeInt == TickTypeEnum.MODEL_OPTION
782
+ or tickTypeInt == TickTypeEnum.DELAYED_MODEL_OPTION
783
+ ):
784
+ optPrice = decode(float, fields)
785
+ pvDividend = decode(float, fields)
786
+
787
+ if optPrice == -1: # -1 is the "not computed" indicator
788
+ optPrice = None
789
+ if pvDividend == -1: # -1 is the "not computed" indicator
790
+ pvDividend = None
791
+
792
+ if version >= 6:
793
+ gamma = decode(float, fields)
794
+ vega = decode(float, fields)
795
+ theta = decode(float, fields)
796
+ undPrice = decode(float, fields)
797
+
798
+ if gamma == -2: # -2 is the "not yet computed" indicator
799
+ gamma = None
800
+ if vega == -2: # -2 is the "not yet computed" indicator
801
+ vega = None
802
+ if theta == -2: # -2 is the "not yet computed" indicator
803
+ theta = None
804
+ if undPrice == -1: # -1 is the "not computed" indicator
805
+ undPrice = None
806
+
807
+ self.wrapper.tickOptionComputation(
808
+ reqId,
809
+ tickTypeInt,
810
+ tickAttrib,
811
+ impliedVol,
812
+ delta,
813
+ optPrice,
814
+ pvDividend,
815
+ gamma,
816
+ vega,
817
+ theta,
818
+ undPrice,
819
+ )
820
+
821
+ def processDeltaNeutralValidationMsg(self, fields):
822
+ decode(int, fields)
823
+ reqId = decode(int, fields)
824
+
825
+ deltaNeutralContract = DeltaNeutralContract()
826
+
827
+ deltaNeutralContract.conId = decode(int, fields)
828
+ deltaNeutralContract.delta = decode(float, fields)
829
+ deltaNeutralContract.price = decode(float, fields)
830
+
831
+ self.wrapper.deltaNeutralValidation(reqId, deltaNeutralContract)
832
+
833
+ def processMarketDataTypeMsg(self, fields):
834
+ decode(int, fields)
835
+ reqId = decode(int, fields)
836
+ marketDataType = decode(int, fields)
837
+
838
+ self.wrapper.marketDataType(reqId, marketDataType)
839
+
840
+ def processCommissionAndFeesReportMsg(self, fields):
841
+ decode(int, fields)
842
+
843
+ commissionAndFeesReport = CommissionAndFeesReport()
844
+ commissionAndFeesReport.execId = decode(str, fields)
845
+ commissionAndFeesReport.commissionAndFees = decode(float, fields)
846
+ commissionAndFeesReport.currency = decode(str, fields)
847
+ commissionAndFeesReport.realizedPNL = decode(float, fields)
848
+ commissionAndFeesReport.yield_ = decode(float, fields)
849
+ commissionAndFeesReport.yieldRedemptionDate = decode(int, fields)
850
+
851
+ self.wrapper.commissionAndFeesReport(commissionAndFeesReport)
852
+
853
+ def processPositionDataMsg(self, fields):
854
+ version = decode(int, fields)
855
+
856
+ account = decode(str, fields)
857
+
858
+ # decode contract fields
859
+ contract = Contract()
860
+ contract.conId = decode(int, fields)
861
+ contract.symbol = decode(str, fields)
862
+ contract.secType = decode(str, fields)
863
+ contract.lastTradeDateOrContractMonth = decode(str, fields)
864
+ contract.strike = decode(float, fields)
865
+ contract.right = decode(str, fields)
866
+ contract.multiplier = decode(str, fields)
867
+ contract.exchange = decode(str, fields)
868
+ contract.currency = decode(str, fields)
869
+ contract.localSymbol = decode(str, fields)
870
+ if version >= 2:
871
+ contract.tradingClass = decode(str, fields)
872
+
873
+ position = decode(Decimal, fields)
874
+
875
+ avgCost = 0.0
876
+ if version >= 3:
877
+ avgCost = decode(float, fields)
878
+
879
+ self.wrapper.position(account, contract, position, avgCost)
880
+
881
+ def processPositionMultiMsg(self, fields):
882
+ decode(int, fields)
883
+ reqId = decode(int, fields)
884
+ account = decode(str, fields)
885
+
886
+ # decode contract fields
887
+ contract = Contract()
888
+ contract.conId = decode(int, fields)
889
+ contract.symbol = decode(str, fields)
890
+ contract.secType = decode(str, fields)
891
+ contract.lastTradeDateOrContractMonth = decode(str, fields)
892
+ contract.strike = decode(float, fields)
893
+ contract.right = decode(str, fields)
894
+ contract.multiplier = decode(str, fields)
895
+ contract.exchange = decode(str, fields)
896
+ contract.currency = decode(str, fields)
897
+ contract.localSymbol = decode(str, fields)
898
+ contract.tradingClass = decode(str, fields)
899
+ position = decode(Decimal, fields)
900
+ avgCost = decode(float, fields)
901
+ modelCode = decode(str, fields)
902
+
903
+ self.wrapper.positionMulti(
904
+ reqId, account, modelCode, contract, position, avgCost
905
+ )
906
+
907
+ def processSecurityDefinitionOptionParameterMsg(self, fields):
908
+ reqId = decode(int, fields)
909
+ exchange = decode(str, fields)
910
+ underlyingConId = decode(int, fields)
911
+ tradingClass = decode(str, fields)
912
+ multiplier = decode(str, fields)
913
+
914
+ expCount = decode(int, fields)
915
+ expirations = set()
916
+ for _ in range(expCount):
917
+ expiration = decode(str, fields)
918
+ expirations.add(expiration)
919
+
920
+ strikeCount = decode(int, fields)
921
+ strikes = set()
922
+ for _ in range(strikeCount):
923
+ strike = decode(float, fields)
924
+ strikes.add(strike)
925
+
926
+ self.wrapper.securityDefinitionOptionParameter(
927
+ reqId,
928
+ exchange,
929
+ underlyingConId,
930
+ tradingClass,
931
+ multiplier,
932
+ expirations,
933
+ strikes,
934
+ )
935
+
936
+ def processSecurityDefinitionOptionParameterEndMsg(self, fields):
937
+ reqId = decode(int, fields)
938
+ self.wrapper.securityDefinitionOptionParameterEnd(reqId)
939
+
940
+ def processSoftDollarTiersMsg(self, fields):
941
+ reqId = decode(int, fields)
942
+ nTiers = decode(int, fields)
943
+
944
+ tiers = []
945
+ for _ in range(nTiers):
946
+ tier = SoftDollarTier()
947
+ tier.name = decode(str, fields)
948
+ tier.val = decode(str, fields)
949
+ tier.displayName = decode(str, fields)
950
+ tiers.append(tier)
951
+
952
+ self.wrapper.softDollarTiers(reqId, tiers)
953
+
954
+ def processFamilyCodesMsg(self, fields):
955
+ nFamilyCodes = decode(int, fields)
956
+ familyCodes = []
957
+ for _ in range(nFamilyCodes):
958
+ famCode = FamilyCode()
959
+ famCode.accountID = decode(str, fields)
960
+ famCode.familyCodeStr = decode(str, fields)
961
+ familyCodes.append(famCode)
962
+
963
+ self.wrapper.familyCodes(familyCodes)
964
+
965
+ def processSymbolSamplesMsg(self, fields):
966
+ reqId = decode(int, fields)
967
+ nContractDescriptions = decode(int, fields)
968
+ contractDescriptions = []
969
+ for _ in range(nContractDescriptions):
970
+ conDesc = ContractDescription()
971
+ conDesc.contract.conId = decode(int, fields)
972
+ conDesc.contract.symbol = decode(str, fields)
973
+ conDesc.contract.secType = decode(str, fields)
974
+ conDesc.contract.primaryExchange = decode(str, fields)
975
+ conDesc.contract.currency = decode(str, fields)
976
+
977
+ nDerivativeSecTypes = decode(int, fields)
978
+ conDesc.derivativeSecTypes = []
979
+ for _ in range(nDerivativeSecTypes):
980
+ derivSecType = decode(str, fields)
981
+ conDesc.derivativeSecTypes.append(derivSecType)
982
+ contractDescriptions.append(conDesc)
983
+
984
+ if self.serverVersion >= MIN_SERVER_VER_BOND_ISSUERID:
985
+ conDesc.contract.description = decode(str, fields)
986
+ conDesc.contract.issuerId = decode(str, fields)
987
+
988
+ self.wrapper.symbolSamples(reqId, contractDescriptions)
989
+
990
+ def processSmartComponents(self, fields):
991
+ reqId = decode(int, fields)
992
+ n = decode(int, fields)
993
+
994
+ smartComponentMap = []
995
+ for _ in range(n):
996
+ smartComponent = SmartComponent()
997
+ smartComponent.bitNumber = decode(int, fields)
998
+ smartComponent.exchange = decode(str, fields)
999
+ smartComponent.exchangeLetter = decode(str, fields)
1000
+ smartComponentMap.append(smartComponent)
1001
+
1002
+ self.wrapper.smartComponents(reqId, smartComponentMap)
1003
+
1004
+ def processTickReqParams(self, fields):
1005
+ tickerId = decode(int, fields)
1006
+ minTick = decode(float, fields)
1007
+ bboExchange = decode(str, fields)
1008
+ snapshotPermissions = decode(int, fields)
1009
+ self.wrapper.tickReqParams(tickerId, minTick, bboExchange, snapshotPermissions)
1010
+
1011
+ def processMktDepthExchanges(self, fields):
1012
+ depthMktDataDescriptions = []
1013
+ nDepthMktDataDescriptions = decode(int, fields)
1014
+
1015
+ if nDepthMktDataDescriptions > 0:
1016
+ for _ in range(nDepthMktDataDescriptions):
1017
+ desc = DepthMktDataDescription()
1018
+ desc.exchange = decode(str, fields)
1019
+ desc.secType = decode(str, fields)
1020
+ if self.serverVersion >= MIN_SERVER_VER_SERVICE_DATA_TYPE:
1021
+ desc.listingExch = decode(str, fields)
1022
+ desc.serviceDataType = decode(str, fields)
1023
+ desc.aggGroup = decode(int, fields)
1024
+ else:
1025
+ decode(int, fields) # boolean notSuppIsL2
1026
+ depthMktDataDescriptions.append(desc)
1027
+
1028
+ self.wrapper.mktDepthExchanges(depthMktDataDescriptions)
1029
+
1030
+ def processHeadTimestamp(self, fields):
1031
+ reqId = decode(int, fields)
1032
+ headTimestamp = decode(str, fields)
1033
+ self.wrapper.headTimestamp(reqId, headTimestamp)
1034
+
1035
+ def processTickNews(self, fields):
1036
+ tickerId = decode(int, fields)
1037
+ timeStamp = decode(int, fields)
1038
+ providerCode = decode(str, fields)
1039
+ articleId = decode(str, fields)
1040
+ headline = decode(str, fields)
1041
+ extraData = decode(str, fields)
1042
+ self.wrapper.tickNews(
1043
+ tickerId, timeStamp, providerCode, articleId, headline, extraData
1044
+ )
1045
+
1046
+ def processNewsProviders(self, fields):
1047
+ newsProviders = []
1048
+ nNewsProviders = decode(int, fields)
1049
+ if nNewsProviders > 0:
1050
+ for _ in range(nNewsProviders):
1051
+ provider = NewsProvider()
1052
+ provider.code = decode(str, fields)
1053
+ provider.name = decode(str, fields)
1054
+ newsProviders.append(provider)
1055
+
1056
+ self.wrapper.newsProviders(newsProviders)
1057
+
1058
+ def processNewsArticle(self, fields):
1059
+ reqId = decode(int, fields)
1060
+ articleType = decode(int, fields)
1061
+ articleText = decode(str, fields)
1062
+ self.wrapper.newsArticle(reqId, articleType, articleText)
1063
+
1064
+ def processHistoricalNews(self, fields):
1065
+ requestId = decode(int, fields)
1066
+ time = decode(str, fields)
1067
+ providerCode = decode(str, fields)
1068
+ articleId = decode(str, fields)
1069
+ headline = decode(str, fields)
1070
+ self.wrapper.historicalNews(requestId, time, providerCode, articleId, headline)
1071
+
1072
+ def processHistoricalNewsEnd(self, fields):
1073
+ reqId = decode(int, fields)
1074
+ hasMore = decode(bool, fields)
1075
+ self.wrapper.historicalNewsEnd(reqId, hasMore)
1076
+
1077
+ def processHistogramData(self, fields):
1078
+ reqId = decode(int, fields)
1079
+ numPoints = decode(int, fields)
1080
+
1081
+ histogram = []
1082
+ for _ in range(numPoints):
1083
+ dataPoint = HistogramData()
1084
+ dataPoint.price = decode(float, fields)
1085
+ dataPoint.size = decode(Decimal, fields)
1086
+ histogram.append(dataPoint)
1087
+
1088
+ self.wrapper.histogramData(reqId, histogram)
1089
+
1090
+ def processRerouteMktDataReq(self, fields):
1091
+ reqId = decode(int, fields)
1092
+ conId = decode(int, fields)
1093
+ exchange = decode(str, fields)
1094
+
1095
+ self.wrapper.rerouteMktDataReq(reqId, conId, exchange)
1096
+
1097
+ def processRerouteMktDepthReq(self, fields):
1098
+ reqId = decode(int, fields)
1099
+ conId = decode(int, fields)
1100
+ exchange = decode(str, fields)
1101
+
1102
+ self.wrapper.rerouteMktDepthReq(reqId, conId, exchange)
1103
+
1104
+ def processMarketRuleMsg(self, fields):
1105
+ marketRuleId = decode(int, fields)
1106
+
1107
+ nPriceIncrements = decode(int, fields)
1108
+ priceIncrements = []
1109
+
1110
+ if nPriceIncrements > 0:
1111
+ for _ in range(nPriceIncrements):
1112
+ prcInc = PriceIncrement()
1113
+ prcInc.lowEdge = decode(float, fields)
1114
+ prcInc.increment = decode(float, fields)
1115
+ priceIncrements.append(prcInc)
1116
+
1117
+ self.wrapper.marketRule(marketRuleId, priceIncrements)
1118
+
1119
+ def processPnLMsg(self, fields):
1120
+ reqId = decode(int, fields)
1121
+ dailyPnL = decode(float, fields)
1122
+ unrealizedPnL = None
1123
+ realizedPnL = None
1124
+
1125
+ if self.serverVersion >= MIN_SERVER_VER_UNREALIZED_PNL:
1126
+ unrealizedPnL = decode(float, fields)
1127
+
1128
+ if self.serverVersion >= MIN_SERVER_VER_REALIZED_PNL:
1129
+ realizedPnL = decode(float, fields)
1130
+
1131
+ self.wrapper.pnl(reqId, dailyPnL, unrealizedPnL, realizedPnL)
1132
+
1133
+ def processPnLSingleMsg(self, fields):
1134
+ reqId = decode(int, fields)
1135
+ pos = decode(Decimal, fields)
1136
+ dailyPnL = decode(float, fields)
1137
+ unrealizedPnL = None
1138
+ realizedPnL = None
1139
+
1140
+ if self.serverVersion >= MIN_SERVER_VER_UNREALIZED_PNL:
1141
+ unrealizedPnL = decode(float, fields)
1142
+
1143
+ if self.serverVersion >= MIN_SERVER_VER_REALIZED_PNL:
1144
+ realizedPnL = decode(float, fields)
1145
+
1146
+ value = decode(float, fields)
1147
+
1148
+ self.wrapper.pnlSingle(reqId, pos, dailyPnL, unrealizedPnL, realizedPnL, value)
1149
+
1150
+ def processHistoricalTicks(self, fields):
1151
+ reqId = decode(int, fields)
1152
+ tickCount = decode(int, fields)
1153
+
1154
+ ticks = []
1155
+
1156
+ for _ in range(tickCount):
1157
+ historicalTick = HistoricalTick()
1158
+ historicalTick.time = decode(int, fields)
1159
+ next(fields) # for consistency
1160
+ historicalTick.price = decode(float, fields)
1161
+ historicalTick.size = decode(Decimal, fields)
1162
+ ticks.append(historicalTick)
1163
+
1164
+ done = decode(bool, fields)
1165
+
1166
+ self.wrapper.historicalTicks(reqId, ticks, done)
1167
+
1168
+ def processHistoricalTicksBidAsk(self, fields):
1169
+ reqId = decode(int, fields)
1170
+ tickCount = decode(int, fields)
1171
+
1172
+ ticks = []
1173
+
1174
+ for _ in range(tickCount):
1175
+ historicalTickBidAsk = HistoricalTickBidAsk()
1176
+ historicalTickBidAsk.time = decode(int, fields)
1177
+ mask = decode(int, fields)
1178
+ tickAttribBidAsk = TickAttribBidAsk()
1179
+ tickAttribBidAsk.askPastHigh = mask & 1 != 0
1180
+ tickAttribBidAsk.bidPastLow = mask & 2 != 0
1181
+ historicalTickBidAsk.tickAttribBidAsk = tickAttribBidAsk
1182
+ historicalTickBidAsk.priceBid = decode(float, fields)
1183
+ historicalTickBidAsk.priceAsk = decode(float, fields)
1184
+ historicalTickBidAsk.sizeBid = decode(Decimal, fields)
1185
+ historicalTickBidAsk.sizeAsk = decode(Decimal, fields)
1186
+ ticks.append(historicalTickBidAsk)
1187
+
1188
+ done = decode(bool, fields)
1189
+
1190
+ self.wrapper.historicalTicksBidAsk(reqId, ticks, done)
1191
+
1192
+ def processHistoricalTicksLast(self, fields):
1193
+ reqId = decode(int, fields)
1194
+ tickCount = decode(int, fields)
1195
+
1196
+ ticks = []
1197
+
1198
+ for _ in range(tickCount):
1199
+ historicalTickLast = HistoricalTickLast()
1200
+ historicalTickLast.time = decode(int, fields)
1201
+ mask = decode(int, fields)
1202
+ tickAttribLast = TickAttribLast()
1203
+ tickAttribLast.pastLimit = mask & 1 != 0
1204
+ tickAttribLast.unreported = mask & 2 != 0
1205
+ historicalTickLast.tickAttribLast = tickAttribLast
1206
+ historicalTickLast.price = decode(float, fields)
1207
+ historicalTickLast.size = decode(Decimal, fields)
1208
+ historicalTickLast.exchange = decode(str, fields)
1209
+ historicalTickLast.specialConditions = decode(str, fields)
1210
+ ticks.append(historicalTickLast)
1211
+
1212
+ done = decode(bool, fields)
1213
+
1214
+ self.wrapper.historicalTicksLast(reqId, ticks, done)
1215
+
1216
+ def processTickByTickMsg(self, fields):
1217
+ reqId = decode(int, fields)
1218
+ tickType = decode(int, fields)
1219
+ time = decode(int, fields)
1220
+
1221
+ if tickType == 0:
1222
+ # None
1223
+ pass
1224
+ elif tickType == 1 or tickType == 2:
1225
+ # Last or AllLast
1226
+ price = decode(float, fields)
1227
+ size = decode(Decimal, fields)
1228
+ mask = decode(int, fields)
1229
+
1230
+ tickAttribLast = TickAttribLast()
1231
+ tickAttribLast.pastLimit = mask & 1 != 0
1232
+ tickAttribLast.unreported = mask & 2 != 0
1233
+ exchange = decode(str, fields)
1234
+ specialConditions = decode(str, fields)
1235
+
1236
+ self.wrapper.tickByTickAllLast(
1237
+ reqId,
1238
+ tickType,
1239
+ time,
1240
+ price,
1241
+ size,
1242
+ tickAttribLast,
1243
+ exchange,
1244
+ specialConditions,
1245
+ )
1246
+ elif tickType == 3:
1247
+ # BidAsk
1248
+ bidPrice = decode(float, fields)
1249
+ askPrice = decode(float, fields)
1250
+ bidSize = decode(Decimal, fields)
1251
+ askSize = decode(Decimal, fields)
1252
+ mask = decode(int, fields)
1253
+ tickAttribBidAsk = TickAttribBidAsk()
1254
+ tickAttribBidAsk.bidPastLow = mask & 1 != 0
1255
+ tickAttribBidAsk.askPastHigh = mask & 2 != 0
1256
+
1257
+ self.wrapper.tickByTickBidAsk(
1258
+ reqId, time, bidPrice, askPrice, bidSize, askSize, tickAttribBidAsk
1259
+ )
1260
+ elif tickType == 4:
1261
+ # MidPoint
1262
+ midPoint = decode(float, fields)
1263
+
1264
+ self.wrapper.tickByTickMidPoint(reqId, time, midPoint)
1265
+
1266
+ def processOrderBoundMsg(self, fields):
1267
+ permId = decode(int, fields)
1268
+ clientId = decode(int, fields)
1269
+ orderId = decode(int, fields)
1270
+
1271
+ self.wrapper.orderBound(permId, clientId, orderId)
1272
+
1273
+ def processMarketDepthMsg(self, fields):
1274
+ decode(int, fields)
1275
+ reqId = decode(int, fields)
1276
+
1277
+ position = decode(int, fields)
1278
+ operation = decode(int, fields)
1279
+ side = decode(int, fields)
1280
+ price = decode(float, fields)
1281
+ size = decode(Decimal, fields)
1282
+
1283
+ self.wrapper.updateMktDepth(reqId, position, operation, side, price, size)
1284
+
1285
+ def processMarketDepthL2Msg(self, fields):
1286
+ decode(int, fields)
1287
+ reqId = decode(int, fields)
1288
+
1289
+ position = decode(int, fields)
1290
+ marketMaker = decode(str, fields)
1291
+ operation = decode(int, fields)
1292
+ side = decode(int, fields)
1293
+ price = decode(float, fields)
1294
+ size = decode(Decimal, fields)
1295
+ isSmartDepth = False
1296
+
1297
+ if self.serverVersion >= MIN_SERVER_VER_SMART_DEPTH:
1298
+ isSmartDepth = decode(bool, fields)
1299
+
1300
+ self.wrapper.updateMktDepthL2(
1301
+ reqId, position, marketMaker, operation, side, price, size, isSmartDepth
1302
+ )
1303
+
1304
+ def processCompletedOrderMsg(self, fields):
1305
+ order = Order()
1306
+ contract = Contract()
1307
+ orderState = OrderState()
1308
+
1309
+ OrderDecoder.__init__(
1310
+ self, contract, order, orderState, UNSET_INTEGER, self.serverVersion
1311
+ )
1312
+
1313
+ # read contract fields
1314
+ OrderDecoder.decodeContractFields(self, fields)
1315
+
1316
+ # read order fields
1317
+ OrderDecoder.decodeAction(self, fields)
1318
+ OrderDecoder.decodeTotalQuantity(self, fields)
1319
+ OrderDecoder.decodeOrderType(self, fields)
1320
+ OrderDecoder.decodeLmtPrice(self, fields)
1321
+ OrderDecoder.decodeAuxPrice(self, fields)
1322
+ OrderDecoder.decodeTIF(self, fields)
1323
+ OrderDecoder.decodeOcaGroup(self, fields)
1324
+ OrderDecoder.decodeAccount(self, fields)
1325
+ OrderDecoder.decodeOpenClose(self, fields)
1326
+ OrderDecoder.decodeOrigin(self, fields)
1327
+ OrderDecoder.decodeOrderRef(self, fields)
1328
+ OrderDecoder.decodePermId(self, fields)
1329
+ OrderDecoder.decodeOutsideRth(self, fields)
1330
+ OrderDecoder.decodeHidden(self, fields)
1331
+ OrderDecoder.decodeDiscretionaryAmt(self, fields)
1332
+ OrderDecoder.decodeGoodAfterTime(self, fields)
1333
+ OrderDecoder.decodeFAParams(self, fields)
1334
+ OrderDecoder.decodeModelCode(self, fields)
1335
+ OrderDecoder.decodeGoodTillDate(self, fields)
1336
+ OrderDecoder.decodeRule80A(self, fields)
1337
+ OrderDecoder.decodePercentOffset(self, fields)
1338
+ OrderDecoder.decodeSettlingFirm(self, fields)
1339
+ OrderDecoder.decodeShortSaleParams(self, fields)
1340
+ OrderDecoder.decodeBoxOrderParams(self, fields)
1341
+ OrderDecoder.decodePegToStkOrVolOrderParams(self, fields)
1342
+ OrderDecoder.decodeDisplaySize(self, fields)
1343
+ OrderDecoder.decodeSweepToFill(self, fields)
1344
+ OrderDecoder.decodeAllOrNone(self, fields)
1345
+ OrderDecoder.decodeMinQty(self, fields)
1346
+ OrderDecoder.decodeOcaType(self, fields)
1347
+ OrderDecoder.decodeTriggerMethod(self, fields)
1348
+ OrderDecoder.decodeVolOrderParams(self, fields, False)
1349
+ OrderDecoder.decodeTrailParams(self, fields)
1350
+ OrderDecoder.decodeComboLegs(self, fields)
1351
+ OrderDecoder.decodeSmartComboRoutingParams(self, fields)
1352
+ OrderDecoder.decodeScaleOrderParams(self, fields)
1353
+ OrderDecoder.decodeHedgeParams(self, fields)
1354
+ OrderDecoder.decodeClearingParams(self, fields)
1355
+ OrderDecoder.decodeNotHeld(self, fields)
1356
+ OrderDecoder.decodeDeltaNeutral(self, fields)
1357
+ OrderDecoder.decodeAlgoParams(self, fields)
1358
+ OrderDecoder.decodeSolicited(self, fields)
1359
+ OrderDecoder.decodeOrderStatus(self, fields)
1360
+ OrderDecoder.decodeVolRandomizeFlags(self, fields)
1361
+ OrderDecoder.decodePegToBenchParams(self, fields)
1362
+ OrderDecoder.decodeConditions(self, fields)
1363
+ OrderDecoder.decodeStopPriceAndLmtPriceOffset(self, fields)
1364
+ OrderDecoder.decodeCashQty(self, fields)
1365
+ OrderDecoder.decodeDontUseAutoPriceForHedge(self, fields)
1366
+ OrderDecoder.decodeIsOmsContainers(self, fields)
1367
+ OrderDecoder.decodeAutoCancelDate(self, fields)
1368
+ OrderDecoder.decodeFilledQuantity(self, fields)
1369
+ OrderDecoder.decodeRefFuturesConId(self, fields)
1370
+ OrderDecoder.decodeAutoCancelParent(self, fields)
1371
+ OrderDecoder.decodeShareholder(self, fields)
1372
+ OrderDecoder.decodeImbalanceOnly(self, fields)
1373
+ OrderDecoder.decodeRouteMarketableToBbo(self, fields)
1374
+ OrderDecoder.decodeParentPermId(self, fields)
1375
+ OrderDecoder.decodeCompletedTime(self, fields)
1376
+ OrderDecoder.decodeCompletedStatus(self, fields)
1377
+ OrderDecoder.decodePegBestPegMidOrderAttributes(self, fields)
1378
+ OrderDecoder.decodeCustomerAccount(self, fields)
1379
+ OrderDecoder.decodeProfessionalCustomer(self, fields)
1380
+ OrderDecoder.decodeSubmitter(self, fields)
1381
+
1382
+ self.wrapper.completedOrder(contract, order, orderState)
1383
+
1384
+ def processCompletedOrdersEndMsg(self, fields):
1385
+ self.wrapper.completedOrdersEnd()
1386
+
1387
+ def processReplaceFAEndMsg(self, fields):
1388
+ reqId = decode(int, fields)
1389
+ text = decode(str, fields)
1390
+
1391
+ self.wrapper.replaceFAEnd(reqId, text)
1392
+
1393
+ def processWshMetaDataMsg(self, fields):
1394
+ reqId = decode(int, fields)
1395
+ dataJson = decode(str, fields)
1396
+
1397
+ self.wrapper.wshMetaData(reqId, dataJson)
1398
+
1399
+ def processWshEventDataMsg(self, fields):
1400
+ reqId = decode(int, fields)
1401
+ dataJson = decode(str, fields)
1402
+
1403
+ self.wrapper.wshEventData(reqId, dataJson)
1404
+
1405
+ def processHistoricalSchedule(self, fields):
1406
+ reqId = decode(int, fields)
1407
+ startDateTime = decode(str, fields)
1408
+ endDateTime = decode(str, fields)
1409
+ timeZone = decode(str, fields)
1410
+ sessionsCount = decode(int, fields)
1411
+
1412
+ sessions = []
1413
+
1414
+ for _ in range(sessionsCount):
1415
+ historicalSession = HistoricalSession()
1416
+ historicalSession.startDateTime = decode(str, fields)
1417
+ historicalSession.endDateTime = decode(str, fields)
1418
+ historicalSession.refDate = decode(str, fields)
1419
+ sessions.append(historicalSession)
1420
+
1421
+ self.wrapper.historicalSchedule(
1422
+ reqId, startDateTime, endDateTime, timeZone, sessions
1423
+ )
1424
+
1425
+ def processUserInfo(self, fields):
1426
+ reqId = decode(int, fields)
1427
+ whiteBrandingId = decode(str, fields)
1428
+
1429
+ self.wrapper.userInfo(reqId, whiteBrandingId)
1430
+
1431
+ def processCurrentTimeInMillis(self, fields):
1432
+ timeInMillis = decode(int, fields)
1433
+
1434
+ self.wrapper.currentTimeInMillis(timeInMillis)
1435
+
1436
+ def processErrorMsg(self, fields):
1437
+ if self.serverVersion < MIN_SERVER_VER_ERROR_TIME:
1438
+ decode(int, fields)
1439
+ reqId = decode(TickerId, fields)
1440
+ errorCode = decode(int, fields)
1441
+ errorString = decode(
1442
+ str, fields, False, self.serverVersion >= MIN_SERVER_VER_ENCODE_MSG_ASCII7
1443
+ )
1444
+ advancedOrderRejectJson = ""
1445
+ if self.serverVersion >= MIN_SERVER_VER_ADVANCED_ORDER_REJECT:
1446
+ advancedOrderRejectJson = decode(str, fields, False, True)
1447
+ errorTime = 0
1448
+ if self.serverVersion >= MIN_SERVER_VER_ERROR_TIME:
1449
+ errorTime = decode(int, fields)
1450
+
1451
+ self.wrapper.error(reqId, errorTime, errorCode, errorString, advancedOrderRejectJson)
1452
+
1453
+ def processErrorMsgProtoBuf(self, protobuf):
1454
+ errorMessageProto = ErrorMessageProto()
1455
+ errorMessageProto.ParseFromString(protobuf)
1456
+
1457
+ self.wrapper.errorProtoBuf(errorMessageProto)
1458
+
1459
+ reqId = errorMessageProto.id if errorMessageProto.HasField('id') else 0
1460
+ errorCode = errorMessageProto.errorCode if errorMessageProto.HasField('errorCode') else 0
1461
+ errorMsg = errorMessageProto.errorMsg if errorMessageProto.HasField('errorMsg') else ""
1462
+ advancedOrderRejectJson = errorMessageProto.advancedOrderRejectJson if errorMessageProto.HasField('advancedOrderRejectJson') else ""
1463
+ errorTime = errorMessageProto.errorTime if errorMessageProto.HasField('errorTime') else 0
1464
+
1465
+ self.wrapper.error(reqId, errorTime, errorCode, errorMsg, advancedOrderRejectJson)
1466
+
1467
+ ######################################################################
1468
+
1469
+ def readLastTradeDate(self, fields, contract: ContractDetails, isBond: bool):
1470
+ lastTradeDateOrContractMonth = decode(str, fields)
1471
+ if lastTradeDateOrContractMonth is not None:
1472
+ if "-" in lastTradeDateOrContractMonth:
1473
+ split = lastTradeDateOrContractMonth.split("-")
1474
+ else:
1475
+ split = lastTradeDateOrContractMonth.split()
1476
+
1477
+ if len(split) > 0:
1478
+ if isBond:
1479
+ contract.maturity = split[0]
1480
+ else:
1481
+ contract.contract.lastTradeDateOrContractMonth = split[0]
1482
+
1483
+ if len(split) > 1:
1484
+ contract.lastTradeTime = split[1]
1485
+
1486
+ if isBond and len(split) > 2:
1487
+ contract.timeZoneId = split[2]
1488
+
1489
+ ######################################################################
1490
+
1491
+ def discoverParams(self):
1492
+ meth2handleInfo = {}
1493
+ for handleInfo in self.msgId2handleInfo.values():
1494
+ meth2handleInfo[handleInfo.wrapperMeth] = handleInfo
1495
+
1496
+ methods = inspect.getmembers(EWrapper, inspect.isfunction)
1497
+ for _, meth in methods:
1498
+ # logger.debug("meth %s", name)
1499
+ sig = inspect.signature(meth)
1500
+ handleInfo = meth2handleInfo.get(meth, None)
1501
+ if handleInfo is not None:
1502
+ handleInfo.wrapperParams = sig.parameters
1503
+
1504
+ # for (pname, param) in sig.parameters.items():
1505
+ # logger.debug("\tparam %s %s %s", pname, param.name, param.annotation)
1506
+
1507
+ def printParams(self):
1508
+ for _, handleInfo in self.msgId2handleInfo.items():
1509
+ if handleInfo.wrapperMeth is not None:
1510
+ logger.debug("meth %s", handleInfo.wrapperMeth.__name__)
1511
+ if handleInfo.wrapperParams is not None:
1512
+ for pname, param in handleInfo.wrapperParams.items():
1513
+ logger.debug(
1514
+ "\tparam %s %s %s", pname, param.name, param.annotation
1515
+ )
1516
+
1517
+ def interpretWithSignature(self, fields, handleInfo):
1518
+ if handleInfo.wrapperParams is None:
1519
+ logger.debug("%s: no param info in %s", fields, handleInfo)
1520
+ return
1521
+
1522
+ nIgnoreFields = 1 # bypass msgId faster this way
1523
+ if len(fields) - nIgnoreFields != len(handleInfo.wrapperParams) - 1:
1524
+ logger.error(
1525
+ "diff len fields and params %d %d for fields: %s and handleInfo: %s",
1526
+ len(fields),
1527
+ len(handleInfo.wrapperParams),
1528
+ fields,
1529
+ handleInfo,
1530
+ )
1531
+ return
1532
+
1533
+ fieldIdx = nIgnoreFields
1534
+ args = []
1535
+ for pname, param in handleInfo.wrapperParams.items():
1536
+ if pname != "self":
1537
+ logger.debug("field %s ", fields[fieldIdx])
1538
+ try:
1539
+ arg = fields[fieldIdx].decode(
1540
+ "unicode-escape"
1541
+ if self.serverVersion >= MIN_SERVER_VER_ENCODE_MSG_ASCII7
1542
+ else "UTF-8"
1543
+ )
1544
+ except UnicodeDecodeError:
1545
+ arg = fields[fieldIdx].decode("latin-1")
1546
+ logger.debug("arg %s type %s", arg, param.annotation)
1547
+ if param.annotation is int:
1548
+ arg = int(arg)
1549
+ elif param.annotation is float:
1550
+ arg = float(arg)
1551
+ elif param.annotation is Decimal:
1552
+ if arg is None or len(arg) == 0:
1553
+ return UNSET_DECIMAL
1554
+ else:
1555
+ return Decimal(arg)
1556
+
1557
+ args.append(arg)
1558
+ fieldIdx += 1
1559
+
1560
+ method = getattr(self.wrapper, handleInfo.wrapperMeth.__name__)
1561
+ logger.debug("calling %s with %s %s", method, self.wrapper, args)
1562
+ method(*args)
1563
+
1564
+ def interpret(self, fields, msgId):
1565
+ if msgId == 0:
1566
+ logger.debug("Unset message id:%d", msgId)
1567
+ return
1568
+
1569
+ handleInfo = self.msgId2handleInfo.get(msgId, None)
1570
+
1571
+ if handleInfo is None:
1572
+ logger.debug("msgId:%d - %s: no handleInfo", fields)
1573
+ return
1574
+
1575
+ try:
1576
+ if handleInfo.wrapperMeth is not None:
1577
+ logger.debug("In interpret(), handleInfo: %s", handleInfo)
1578
+ self.interpretWithSignature(fields, handleInfo)
1579
+ elif handleInfo.processMeth is not None:
1580
+ handleInfo.processMeth(self, iter(fields))
1581
+ except BadMessage:
1582
+ theBadMsg = ",".join(fields)
1583
+ self.wrapper.error(
1584
+ NO_VALID_ID, currentTimeMillis(), BAD_MESSAGE.code(), BAD_MESSAGE.msg() + theBadMsg
1585
+ )
1586
+ raise
1587
+
1588
+ def processProtoBuf(self, protoBuf, msgId):
1589
+ if msgId == 0:
1590
+ logger.debug("Unset message id:%d", msgId)
1591
+ return
1592
+
1593
+ handleInfo = self.msgId2handleInfoProtoBuf.get(msgId, None)
1594
+
1595
+ if handleInfo is None:
1596
+ logger.debug("msgId:%d - %s: no handleInfo for protobuf", msgId, protoBuf)
1597
+ return
1598
+
1599
+ try:
1600
+ if handleInfo.processMeth is not None:
1601
+ handleInfo.processMeth(self, protoBuf)
1602
+ except BadMessage:
1603
+ theBadMsg = ",".join(protoBuf)
1604
+ self.wrapper.error(
1605
+ NO_VALID_ID, currentTimeMillis(), BAD_MESSAGE.code(), BAD_MESSAGE.msg() + theBadMsg
1606
+ )
1607
+ raise
1608
+
1609
+ msgId2handleInfo = {
1610
+ IN.TICK_PRICE: HandleInfo(proc=processTickPriceMsg),
1611
+ IN.TICK_SIZE: HandleInfo(proc=processTickSizeMsg),
1612
+ IN.ORDER_STATUS: HandleInfo(proc=processOrderStatusMsg),
1613
+ IN.ERR_MSG: HandleInfo(proc=processErrorMsg),
1614
+ IN.OPEN_ORDER: HandleInfo(proc=processOpenOrder),
1615
+ IN.ACCT_VALUE: HandleInfo(wrap=EWrapper.updateAccountValue),
1616
+ IN.PORTFOLIO_VALUE: HandleInfo(proc=processPortfolioValueMsg),
1617
+ IN.ACCT_UPDATE_TIME: HandleInfo(wrap=EWrapper.updateAccountTime),
1618
+ IN.NEXT_VALID_ID: HandleInfo(
1619
+ wrap=EWrapper.nextValidId,
1620
+ ),
1621
+ IN.CONTRACT_DATA: HandleInfo(proc=processContractDataMsg),
1622
+ IN.EXECUTION_DATA: HandleInfo(proc=processExecutionDataMsg),
1623
+ IN.MARKET_DEPTH: HandleInfo(proc=processMarketDepthMsg),
1624
+ IN.MARKET_DEPTH_L2: HandleInfo(proc=processMarketDepthL2Msg),
1625
+ IN.NEWS_BULLETINS: HandleInfo(wrap=EWrapper.updateNewsBulletin),
1626
+ IN.MANAGED_ACCTS: HandleInfo(wrap=EWrapper.managedAccounts),
1627
+ IN.RECEIVE_FA: HandleInfo(wrap=EWrapper.receiveFA),
1628
+ IN.HISTORICAL_DATA: HandleInfo(proc=processHistoricalDataMsg),
1629
+ IN.HISTORICAL_DATA_UPDATE: HandleInfo(proc=processHistoricalDataUpdateMsg),
1630
+ IN.BOND_CONTRACT_DATA: HandleInfo(proc=processBondContractDataMsg),
1631
+ IN.SCANNER_PARAMETERS: HandleInfo(wrap=EWrapper.scannerParameters),
1632
+ IN.SCANNER_DATA: HandleInfo(proc=processScannerDataMsg),
1633
+ IN.TICK_OPTION_COMPUTATION: HandleInfo(proc=processTickOptionComputationMsg),
1634
+ IN.TICK_GENERIC: HandleInfo(wrap=EWrapper.tickGeneric),
1635
+ IN.TICK_STRING: HandleInfo(wrap=EWrapper.tickString),
1636
+ IN.TICK_EFP: HandleInfo(wrap=EWrapper.tickEFP),
1637
+ IN.CURRENT_TIME: HandleInfo(wrap=EWrapper.currentTime),
1638
+ IN.REAL_TIME_BARS: HandleInfo(proc=processRealTimeBarMsg),
1639
+ IN.FUNDAMENTAL_DATA: HandleInfo(wrap=EWrapper.fundamentalData),
1640
+ IN.CONTRACT_DATA_END: HandleInfo(wrap=EWrapper.contractDetailsEnd),
1641
+ IN.OPEN_ORDER_END: HandleInfo(wrap=EWrapper.openOrderEnd),
1642
+ IN.ACCT_DOWNLOAD_END: HandleInfo(wrap=EWrapper.accountDownloadEnd),
1643
+ IN.EXECUTION_DATA_END: HandleInfo(wrap=EWrapper.execDetailsEnd),
1644
+ IN.DELTA_NEUTRAL_VALIDATION: HandleInfo(proc=processDeltaNeutralValidationMsg),
1645
+ IN.TICK_SNAPSHOT_END: HandleInfo(wrap=EWrapper.tickSnapshotEnd),
1646
+ IN.MARKET_DATA_TYPE: HandleInfo(wrap=EWrapper.marketDataType),
1647
+ IN.COMMISSION_AND_FEES_REPORT: HandleInfo(proc=processCommissionAndFeesReportMsg),
1648
+ IN.POSITION_DATA: HandleInfo(proc=processPositionDataMsg),
1649
+ IN.POSITION_END: HandleInfo(wrap=EWrapper.positionEnd),
1650
+ IN.ACCOUNT_SUMMARY: HandleInfo(wrap=EWrapper.accountSummary),
1651
+ IN.ACCOUNT_SUMMARY_END: HandleInfo(wrap=EWrapper.accountSummaryEnd),
1652
+ IN.VERIFY_MESSAGE_API: HandleInfo(wrap=EWrapper.verifyMessageAPI),
1653
+ IN.VERIFY_COMPLETED: HandleInfo(wrap=EWrapper.verifyCompleted),
1654
+ IN.DISPLAY_GROUP_LIST: HandleInfo(wrap=EWrapper.displayGroupList),
1655
+ IN.DISPLAY_GROUP_UPDATED: HandleInfo(wrap=EWrapper.displayGroupUpdated),
1656
+ IN.VERIFY_AND_AUTH_MESSAGE_API: HandleInfo(
1657
+ wrap=EWrapper.verifyAndAuthMessageAPI
1658
+ ),
1659
+ IN.VERIFY_AND_AUTH_COMPLETED: HandleInfo(wrap=EWrapper.verifyAndAuthCompleted),
1660
+ IN.POSITION_MULTI: HandleInfo(proc=processPositionMultiMsg),
1661
+ IN.POSITION_MULTI_END: HandleInfo(wrap=EWrapper.positionMultiEnd),
1662
+ IN.ACCOUNT_UPDATE_MULTI: HandleInfo(wrap=EWrapper.accountUpdateMulti),
1663
+ IN.ACCOUNT_UPDATE_MULTI_END: HandleInfo(wrap=EWrapper.accountUpdateMultiEnd),
1664
+ IN.SECURITY_DEFINITION_OPTION_PARAMETER: HandleInfo(
1665
+ proc=processSecurityDefinitionOptionParameterMsg
1666
+ ),
1667
+ IN.SECURITY_DEFINITION_OPTION_PARAMETER_END: HandleInfo(
1668
+ proc=processSecurityDefinitionOptionParameterEndMsg
1669
+ ),
1670
+ IN.SOFT_DOLLAR_TIERS: HandleInfo(proc=processSoftDollarTiersMsg),
1671
+ IN.FAMILY_CODES: HandleInfo(proc=processFamilyCodesMsg),
1672
+ IN.SYMBOL_SAMPLES: HandleInfo(proc=processSymbolSamplesMsg),
1673
+ IN.SMART_COMPONENTS: HandleInfo(proc=processSmartComponents),
1674
+ IN.TICK_REQ_PARAMS: HandleInfo(proc=processTickReqParams),
1675
+ IN.MKT_DEPTH_EXCHANGES: HandleInfo(proc=processMktDepthExchanges),
1676
+ IN.HEAD_TIMESTAMP: HandleInfo(proc=processHeadTimestamp),
1677
+ IN.TICK_NEWS: HandleInfo(proc=processTickNews),
1678
+ IN.NEWS_PROVIDERS: HandleInfo(proc=processNewsProviders),
1679
+ IN.NEWS_ARTICLE: HandleInfo(proc=processNewsArticle),
1680
+ IN.HISTORICAL_NEWS: HandleInfo(proc=processHistoricalNews),
1681
+ IN.HISTORICAL_NEWS_END: HandleInfo(proc=processHistoricalNewsEnd),
1682
+ IN.HISTOGRAM_DATA: HandleInfo(proc=processHistogramData),
1683
+ IN.REROUTE_MKT_DATA_REQ: HandleInfo(proc=processRerouteMktDataReq),
1684
+ IN.REROUTE_MKT_DEPTH_REQ: HandleInfo(proc=processRerouteMktDepthReq),
1685
+ IN.MARKET_RULE: HandleInfo(proc=processMarketRuleMsg),
1686
+ IN.PNL: HandleInfo(proc=processPnLMsg),
1687
+ IN.PNL_SINGLE: HandleInfo(proc=processPnLSingleMsg),
1688
+ IN.HISTORICAL_TICKS: HandleInfo(proc=processHistoricalTicks),
1689
+ IN.HISTORICAL_TICKS_BID_ASK: HandleInfo(proc=processHistoricalTicksBidAsk),
1690
+ IN.HISTORICAL_TICKS_LAST: HandleInfo(proc=processHistoricalTicksLast),
1691
+ IN.TICK_BY_TICK: HandleInfo(proc=processTickByTickMsg),
1692
+ IN.ORDER_BOUND: HandleInfo(proc=processOrderBoundMsg),
1693
+ IN.COMPLETED_ORDER: HandleInfo(proc=processCompletedOrderMsg),
1694
+ IN.COMPLETED_ORDERS_END: HandleInfo(proc=processCompletedOrdersEndMsg),
1695
+ IN.REPLACE_FA_END: HandleInfo(proc=processReplaceFAEndMsg),
1696
+ IN.WSH_META_DATA: HandleInfo(proc=processWshMetaDataMsg),
1697
+ IN.WSH_EVENT_DATA: HandleInfo(proc=processWshEventDataMsg),
1698
+ IN.HISTORICAL_SCHEDULE: HandleInfo(proc=processHistoricalSchedule),
1699
+ IN.USER_INFO: HandleInfo(proc=processUserInfo),
1700
+ IN.HISTORICAL_DATA_END: HandleInfo(proc=processHistoricalDataEndMsg),
1701
+ IN.CURRENT_TIME_IN_MILLIS: HandleInfo(proc=processCurrentTimeInMillis),
1702
+ }
1703
+
1704
+ msgId2handleInfoProtoBuf = {
1705
+ IN.ORDER_STATUS: HandleInfo(proc=processOrderStatusMsgProtoBuf),
1706
+ IN.ERR_MSG: HandleInfo(proc=processErrorMsgProtoBuf),
1707
+ IN.OPEN_ORDER: HandleInfo(proc=processOpenOrderMsgProtoBuf),
1708
+ IN.EXECUTION_DATA: HandleInfo(proc=processExecutionDataMsgProtoBuf),
1709
+ IN.OPEN_ORDER_END: HandleInfo(proc=processOpenOrdersEndMsgProtoBuf),
1710
+ IN.EXECUTION_DATA_END: HandleInfo(proc=processExecutionDataEndMsgProtoBuf),
1711
+ }