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/client_utils.py ADDED
@@ -0,0 +1,412 @@
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
+ from ibapi.const import UNSET_DOUBLE
7
+ from ibapi.execution import ExecutionFilter
8
+
9
+ from ibapi.contract import Contract, DeltaNeutralContract, ComboLeg
10
+ from ibapi.order import Order
11
+ from ibapi.order_condition import OrderCondition, OperatorCondition, ContractCondition, PriceCondition, TimeCondition, MarginCondition, ExecutionCondition, VolumeCondition, PercentChangeCondition
12
+ from ibapi.tag_value import TagValue
13
+ from ibapi.utils import isValidIntValue, isValidFloatValue, isValidLongValue, isValidDecimalValue, decimalMaxString
14
+ from ibapi.order_condition import Create
15
+
16
+ from ibapi.protobuf.ComboLeg_pb2 import ComboLeg as ComboLegProto
17
+ from ibapi.protobuf.Contract_pb2 import Contract as ContractProto
18
+ from ibapi.protobuf.DeltaNeutralContract_pb2 import DeltaNeutralContract as DeltaNeutralContractProto
19
+ from ibapi.protobuf.OrderCancel_pb2 import OrderCancel as OrderCancelProto
20
+ from ibapi.protobuf.OrderCondition_pb2 import OrderCondition as OrderConditionProto
21
+ from ibapi.protobuf.PlaceOrderRequest_pb2 import PlaceOrderRequest as PlaceOrderRequestProto
22
+ from ibapi.protobuf.CancelOrderRequest_pb2 import CancelOrderRequest as CancelOrderRequestProto
23
+ from ibapi.protobuf.GlobalCancelRequest_pb2 import GlobalCancelRequest as GlobalCancelRequestProto
24
+ from ibapi.protobuf.ExecutionFilter_pb2 import ExecutionFilter as ExecutionFilterProto
25
+ from ibapi.protobuf.ExecutionRequest_pb2 import ExecutionRequest as ExecutionRequestProto
26
+ from ibapi.protobuf.Order_pb2 import Order as OrderProto
27
+ from ibapi.protobuf.SoftDollarTier_pb2 import SoftDollarTier as SoftDollarTierProto
28
+
29
+ @staticmethod
30
+ def createExecutionRequestProto(reqId: int, execFilter: ExecutionFilter) -> ExecutionRequestProto:
31
+ executionFilterProto = ExecutionFilterProto()
32
+ if isValidIntValue(execFilter.clientId): executionFilterProto.clientId = execFilter.clientId
33
+ if execFilter.acctCode: executionFilterProto.acctCode = execFilter.acctCode
34
+ if execFilter.time: executionFilterProto.time = execFilter.time
35
+ if execFilter.symbol: executionFilterProto.symbol = execFilter.symbol
36
+ if execFilter.secType: executionFilterProto.secType = execFilter.secType
37
+ if execFilter.exchange: executionFilterProto.exchange = execFilter.exchange
38
+ if execFilter.side: executionFilterProto.side = execFilter.side
39
+ if isValidIntValue(execFilter.lastNDays): executionFilterProto.lastNDays = execFilter.lastNDays
40
+ if execFilter.specificDates is not None and execFilter.specificDates: executionFilterProto.specificDates.extend(execFilter.specificDates)
41
+ executionRequestProto = ExecutionRequestProto()
42
+ if isValidIntValue(reqId): executionRequestProto.reqId = reqId
43
+ executionRequestProto.executionFilter.CopyFrom(executionFilterProto)
44
+ return executionRequestProto
45
+
46
+ @staticmethod
47
+ def createPlaceOrderRequestProto(orderId: int, contract: Contract, order: Order) -> PlaceOrderRequestProto:
48
+ placeOrderRequestProto = PlaceOrderRequestProto()
49
+ if isValidIntValue(orderId): placeOrderRequestProto.orderId = orderId
50
+ contractProto = createContractProto(contract, order)
51
+ if contractProto is not None: placeOrderRequestProto.contract.CopyFrom(contractProto)
52
+ orderProto = createOrderProto(order)
53
+ if orderProto is not None: placeOrderRequestProto.order.CopyFrom(orderProto)
54
+ return placeOrderRequestProto
55
+
56
+ @staticmethod
57
+ def createContractProto(contract: Contract, order: Order) -> ContractProto:
58
+ contractProto = ContractProto()
59
+ if isValidIntValue(contract.conId): contractProto.conId = contract.conId
60
+ if contract.symbol: contractProto.symbol = contract.symbol
61
+ if contract.secType: contractProto.secType = contract.secType
62
+ if contract.lastTradeDateOrContractMonth: contractProto.lastTradeDateOrContractMonth = contract.lastTradeDateOrContractMonth
63
+ if isValidFloatValue(contract.strike): contractProto.strike = contract.strike
64
+ if contract.right: contractProto.right = contract.right
65
+ if contract.multiplier: contractProto.multiplier = float(contract.multiplier)
66
+ if contract.exchange: contractProto.exchange = contract.exchange
67
+ if contract.primaryExchange: contractProto.primaryExchange = contract.primaryExchange
68
+ if contract.currency: contractProto.currency = contract.currency
69
+ if contract.localSymbol: contractProto.localSymbol = contract.localSymbol
70
+ if contract.tradingClass: contractProto.tradingClass = contract.tradingClass
71
+ if contract.secIdType: contractProto.secIdType = contract.secIdType
72
+ if contract.secId: contractProto.secId = contract.secId
73
+ if contract.includeExpired: contractProto.includeExpired = contract.includeExpired
74
+ if contract.comboLegsDescrip: contractProto.comboLegsDescrip = contract.comboLegsDescrip
75
+ if contract.description: contractProto.description = contract.description
76
+ if contract.issuerId: contractProto.issuerId = contract.issuerId
77
+
78
+ comboLegProtoList = createComboLegProtoList(contract, order)
79
+ if comboLegProtoList is not None and comboLegProtoList: contractProto.comboLegs.extend(comboLegProtoList)
80
+
81
+ deltaNeutralContractProto = createDeltaNeutralContractProto(contract)
82
+ if deltaNeutralContractProto is not None: contractProto.deltaNeutralContract.CopyFrom(deltaNeutralContractProto)
83
+
84
+ return contractProto
85
+
86
+ @staticmethod
87
+ def createDeltaNeutralContractProto(contract: Contract) -> DeltaNeutralContractProto:
88
+ deltaNeutralContractProto = None
89
+ if contract.deltaNeutralContract is not None:
90
+ deltaNeutralContract = contract.deltaNeutralContract
91
+ deltaNeutralContractProto = DeltaNeutralContractProto()
92
+ if isValidIntValue(deltaNeutralContract.conId): deltaNeutralContractProto.conId = deltaNeutralContract.conId
93
+ if isValidFloatValue(deltaNeutralContract.delta): deltaNeutralContractProto.delta = deltaNeutralContract.delta
94
+ if isValidFloatValue(deltaNeutralContract.price): deltaNeutralContractProto.price = deltaNeutralContract.price
95
+ return deltaNeutralContractProto
96
+
97
+
98
+ @staticmethod
99
+ def createComboLegProtoList(contract: Contract, order: Order) -> list[ComboLegProto]:
100
+ comboLegs = contract.comboLegs
101
+ orderComboLegs = order.orderComboLegs
102
+ comboLegProtoList = []
103
+ if comboLegs is not None and comboLegs:
104
+ for i, comboLeg in enumerate(comboLegs):
105
+ perLegPrice = UNSET_DOUBLE
106
+ if orderComboLegs is not None and i < len(orderComboLegs):
107
+ perLegPrice = orderComboLegs[i].price
108
+ comboLegProto = createComboLegProto(comboLeg, perLegPrice)
109
+ comboLegProtoList.append(comboLegProto)
110
+ return comboLegProtoList
111
+
112
+ @staticmethod
113
+ def createComboLegProto(comboLeg: ComboLeg, perLegPrice: float) -> ComboLegProto:
114
+ comboLegProto = ComboLegProto()
115
+ if isValidIntValue(comboLeg.conId): comboLegProto.conId = comboLeg.conId
116
+ if isValidIntValue(comboLeg.ratio): comboLegProto.ratio = comboLeg.ratio
117
+ if comboLeg.action: comboLegProto.action = comboLeg.action
118
+ if comboLeg.exchange: comboLegProto.exchange = comboLeg.exchange
119
+ if isValidIntValue(comboLeg.openClose): comboLegProto.openClose = comboLeg.openClose
120
+ if isValidIntValue(comboLeg.shortSaleSlot): comboLegProto.shortSalesSlot = comboLeg.shortSaleSlot
121
+ if comboLeg.designatedLocation: comboLegProto.designatedLocation = comboLeg.designatedLocation
122
+ if isValidIntValue(comboLeg.exemptCode): comboLegProto.exemptCode = comboLeg.exemptCode
123
+ if isValidFloatValue(perLegPrice): comboLegProto.perLegPrice = perLegPrice
124
+ return comboLegProto
125
+
126
+ @staticmethod
127
+ def createOrderProto(order: Order) -> OrderProto:
128
+ orderProto = OrderProto()
129
+ if isValidIntValue(order.clientId): order.clientId = order.clientId
130
+ if isValidLongValue(order.permId): orderProto.permId = order.permId
131
+ if isValidIntValue(order.parentId): orderProto.parentId = order.parentId
132
+ if order.action: orderProto.action = order.action
133
+ if isValidDecimalValue(order.totalQuantity): orderProto.totalQuantity = decimalMaxString(order.totalQuantity)
134
+ if isValidIntValue(order.displaySize): orderProto.displaySize = order.displaySize
135
+ if order.orderType: orderProto.orderType = order.orderType
136
+ if isValidFloatValue(order.lmtPrice): orderProto.lmtPrice = order.lmtPrice
137
+ if isValidFloatValue(order.auxPrice): orderProto.auxPrice = order.auxPrice
138
+ if order.tif: orderProto.tif = order.tif
139
+ if order.account: orderProto.account = order.account
140
+ if order.settlingFirm: orderProto.settlingFirm = order.settlingFirm
141
+ if order.clearingAccount: orderProto.clearingAccount = order.clearingAccount
142
+ if order.clearingIntent: orderProto.clearingIntent = order.clearingIntent
143
+ if order.allOrNone: orderProto.allOrNone = order.allOrNone
144
+ if order.blockOrder: orderProto.blockOrder = order.blockOrder
145
+ if order.hidden: orderProto.hidden = order.hidden
146
+ if order.outsideRth: orderProto.outsideRth = order.outsideRth
147
+ if order.sweepToFill: orderProto.sweepToFill = order.sweepToFill
148
+ if isValidFloatValue(order.percentOffset): orderProto.percentOffset = order.percentOffset
149
+ if isValidFloatValue(order.trailingPercent): orderProto.trailingPercent = order.trailingPercent
150
+ if isValidFloatValue(order.trailStopPrice): orderProto.trailStopPrice = order.trailStopPrice
151
+ if isValidIntValue(order.minQty): orderProto.minQty = order.minQty
152
+ if order.goodAfterTime: orderProto.goodAfterTime = order.goodAfterTime
153
+ if order.goodTillDate: orderProto.goodTillDate = order.goodTillDate
154
+ if order.ocaGroup: orderProto.ocaGroup = order.ocaGroup
155
+ if order.orderRef: orderProto.orderRef = order.orderRef
156
+ if order.rule80A: orderProto.rule80A = order.rule80A
157
+ if isValidIntValue(order.ocaType): orderProto.ocaType = order.ocaType
158
+ if isValidIntValue(order.triggerMethod): orderProto.triggerMethod = order.triggerMethod
159
+ if order.activeStartTime: orderProto.activeStartTime = order.activeStartTime
160
+ if order.activeStopTime: orderProto.activeStopTime = order.activeStopTime
161
+ if order.faGroup: orderProto.faGroup = order.faGroup
162
+ if order.faMethod: orderProto.faMethod = order.faMethod
163
+ if order.faPercentage: orderProto.faPercentage = order.faPercentage
164
+ if isValidFloatValue(order.volatility): orderProto.volatility = order.volatility
165
+ if isValidIntValue(order.volatilityType): orderProto.volatilityType = order.volatilityType
166
+ if order.continuousUpdate: orderProto.continuousUpdate = order.continuousUpdate
167
+ if isValidIntValue(order.referencePriceType): orderProto.referencePriceType = order.referencePriceType
168
+ if order.deltaNeutralOrderType: orderProto.deltaNeutralOrderType = order.deltaNeutralOrderType
169
+ if isValidFloatValue(order.deltaNeutralAuxPrice): orderProto.deltaNeutralAuxPrice = order.deltaNeutralAuxPrice
170
+ if isValidIntValue(order.deltaNeutralConId): orderProto.deltaNeutralConId = order.deltaNeutralConId
171
+ if order.deltaNeutralOpenClose: orderProto.deltaNeutralOpenClose = order.deltaNeutralOpenClose
172
+ if order.deltaNeutralShortSale: orderProto.deltaNeutralShortSale = order.deltaNeutralShortSale
173
+ if isValidIntValue(order.deltaNeutralShortSaleSlot): orderProto.deltaNeutralShortSaleSlot = order.deltaNeutralShortSaleSlot
174
+ if order.deltaNeutralDesignatedLocation: orderProto.deltaNeutralDesignatedLocation = order.deltaNeutralDesignatedLocation
175
+ if isValidIntValue(order.scaleInitLevelSize): orderProto.scaleInitLevelSize = order.scaleInitLevelSize
176
+ if isValidIntValue(order.scaleSubsLevelSize): orderProto.scaleSubsLevelSize = order.scaleSubsLevelSize
177
+ if isValidFloatValue(order.scalePriceIncrement): orderProto.scalePriceIncrement = order.scalePriceIncrement
178
+ if isValidFloatValue(order.scalePriceAdjustValue): orderProto.scalePriceAdjustValue = order.scalePriceAdjustValue
179
+ if isValidIntValue(order.scalePriceAdjustInterval): orderProto.scalePriceAdjustInterval = order.scalePriceAdjustInterval
180
+ if isValidFloatValue(order.scaleProfitOffset): orderProto.scaleProfitOffset = order.scaleProfitOffset
181
+ if order.scaleAutoReset: orderProto.scaleAutoReset = order.scaleAutoReset
182
+ if isValidIntValue(order.scaleInitPosition): orderProto.scaleInitPosition = order.scaleInitPosition
183
+ if isValidIntValue(order.scaleInitFillQty): orderProto.scaleInitFillQty = order.scaleInitFillQty
184
+ if order.scaleRandomPercent: orderProto.scaleRandomPercent = order.scaleRandomPercent
185
+ if order.scaleTable: orderProto.scaleTable = order.scaleTable
186
+ if order.hedgeType: orderProto.hedgeType = order.hedgeType
187
+ if order.hedgeParam: orderProto.hedgeParam = order.hedgeParam
188
+
189
+ if order.algoStrategy: orderProto.algoStrategy = order.algoStrategy
190
+ fillTagValueList(order.algoParams, orderProto.algoParams)
191
+ if order.algoId: orderProto.algoId = order.algoId
192
+
193
+ fillTagValueList(order.smartComboRoutingParams, orderProto.smartComboRoutingParams)
194
+
195
+ if order.whatIf: orderProto.whatIf = order.whatIf
196
+ if order.transmit: orderProto.transmit = order.transmit
197
+ if order.overridePercentageConstraints: orderProto.overridePercentageConstraints = order.overridePercentageConstraints
198
+ if order.openClose: orderProto.openClose = order.openClose
199
+ if isValidIntValue(order.origin): orderProto.origin = order.origin
200
+ if isValidIntValue(order.shortSaleSlot): orderProto.shortSaleSlot = order.shortSaleSlot
201
+ if order.designatedLocation: orderProto.designatedLocation = order.designatedLocation
202
+ if isValidIntValue(order.exemptCode): orderProto.exemptCode = order.exemptCode
203
+ if order.deltaNeutralSettlingFirm: orderProto.deltaNeutralSettlingFirm = order.deltaNeutralSettlingFirm
204
+ if order.deltaNeutralClearingAccount: orderProto.deltaNeutralClearingAccount = order.deltaNeutralClearingAccount
205
+ if order.deltaNeutralClearingIntent: orderProto.deltaNeutralClearingIntent = order.deltaNeutralClearingIntent
206
+ if isValidIntValue(order.discretionaryAmt): orderProto.discretionaryAmt = order.discretionaryAmt
207
+ if order.optOutSmartRouting: orderProto.optOutSmartRouting = order.optOutSmartRouting
208
+ if isValidIntValue(order.exemptCode): orderProto.exemptCode = order.exemptCode
209
+ if isValidFloatValue(order.startingPrice): orderProto.startingPrice = order.startingPrice
210
+ if isValidFloatValue(order.stockRefPrice): orderProto.stockRefPrice = order.stockRefPrice
211
+ if isValidFloatValue(order.delta): orderProto.delta = order.delta
212
+ if isValidFloatValue(order.stockRangeLower): orderProto.stockRangeLower = order.stockRangeLower
213
+ if isValidFloatValue(order.stockRangeUpper): orderProto.stockRangeUpper = order.stockRangeUpper
214
+ if order.notHeld: orderProto.notHeld = order.notHeld
215
+
216
+ fillTagValueList(order.orderMiscOptions, orderProto.orderMiscOptions)
217
+
218
+ if order.solicited: orderProto.solicited = order.solicited
219
+ if order.randomizeSize: orderProto.randomizeSize = order.randomizeSize
220
+ if order.randomizePrice: orderProto.randomizePrice = order.randomizePrice
221
+ if isValidIntValue(order.referenceContractId): orderProto.referenceContractId = order.referenceContractId
222
+ if isValidFloatValue(order.peggedChangeAmount): orderProto.peggedChangeAmount = order.peggedChangeAmount
223
+ if order.isPeggedChangeAmountDecrease: orderProto.isPeggedChangeAmountDecrease = order.isPeggedChangeAmountDecrease
224
+ if isValidFloatValue(order.referenceChangeAmount): orderProto.referenceChangeAmount = order.referenceChangeAmount
225
+ if order.referenceExchangeId: orderProto.referenceExchangeId = order.referenceExchangeId
226
+ if order.adjustedOrderType: orderProto.adjustedOrderType = order.adjustedOrderType
227
+ if isValidFloatValue(order.triggerPrice): orderProto.triggerPrice = order.triggerPrice
228
+ if isValidFloatValue(order.adjustedStopPrice): orderProto.adjustedStopPrice = order.adjustedStopPrice
229
+ if isValidFloatValue(order.adjustedStopLimitPrice): orderProto.adjustedStopLimitPrice = order.adjustedStopLimitPrice
230
+ if isValidFloatValue(order.adjustedTrailingAmount): orderProto.adjustedTrailingAmount = order.adjustedTrailingAmount
231
+ if isValidIntValue(order.adjustableTrailingUnit): orderProto.adjustableTrailingUnit = order.adjustableTrailingUnit
232
+ if isValidFloatValue(order.lmtPriceOffset): orderProto.lmtPriceOffset = order.lmtPriceOffset
233
+
234
+ orderConditionList = createConditionsProto(order)
235
+ if orderConditionList is not None and orderConditionList: orderProto.conditions.extend(orderConditionList)
236
+ if order.conditionsCancelOrder: orderProto.conditionsCancelOrder = order.conditionsCancelOrder
237
+ if order.conditionsIgnoreRth: orderProto.conditionsIgnoreRth = order.conditionsIgnoreRth
238
+
239
+ if order.modelCode: orderProto.modelCode = order.modelCode
240
+ if order.extOperator: orderProto.extOperator = order.extOperator
241
+
242
+ softDollarTier = createSoftDollarTierProto(order)
243
+ if softDollarTier is not None: orderProto.softDollarTier.CopyFrom(softDollarTier)
244
+
245
+ if isValidFloatValue(order.cashQty): orderProto.cashQty = order.cashQty
246
+ if order.mifid2DecisionMaker: orderProto.mifid2DecisionMaker = order.mifid2DecisionMaker
247
+ if order.mifid2DecisionAlgo: orderProto.mifid2DecisionAlgo = order.mifid2DecisionAlgo
248
+ if order.mifid2ExecutionTrader: orderProto.mifid2ExecutionTrader = order.mifid2ExecutionTrader
249
+ if order.mifid2ExecutionAlgo: orderProto.mifid2ExecutionAlgo = order.mifid2ExecutionAlgo
250
+ if order.dontUseAutoPriceForHedge: orderProto.dontUseAutoPriceForHedge = order.dontUseAutoPriceForHedge
251
+ if order.isOmsContainer: orderProto.isOmsContainer = order.isOmsContainer
252
+ if order.discretionaryUpToLimitPrice: orderProto.discretionaryUpToLimitPrice = order.discretionaryUpToLimitPrice
253
+ if order.usePriceMgmtAlgo is not None: orderProto.usePriceMgmtAlgo = 1 if order.usePriceMgmtAlgo else 0
254
+ if isValidIntValue(order.duration): orderProto.duration = order.duration
255
+ if isValidIntValue(order.postToAts): orderProto.postToAts = order.postToAts
256
+ if order.advancedErrorOverride: orderProto.advancedErrorOverride = order.advancedErrorOverride
257
+ if order.manualOrderTime: orderProto.manualOrderTime = order.manualOrderTime
258
+ if isValidIntValue(order.minTradeQty): orderProto.minTradeQty = order.minTradeQty
259
+ if isValidIntValue(order.minCompeteSize): orderProto.minCompeteSize = order.minCompeteSize
260
+ if isValidFloatValue(order.competeAgainstBestOffset): orderProto.competeAgainstBestOffset = order.competeAgainstBestOffset
261
+ if isValidFloatValue(order.midOffsetAtWhole): orderProto.midOffsetAtWhole = order.midOffsetAtWhole
262
+ if isValidFloatValue(order.midOffsetAtHalf): orderProto.midOffsetAtHalf = order.midOffsetAtHalf
263
+ if order.customerAccount: orderProto.customerAccount = order.customerAccount
264
+ if order.professionalCustomer: orderProto.professionalCustomer = order.professionalCustomer
265
+ if order.bondAccruedInterest: orderProto.bondAccruedInterest = order.bondAccruedInterest
266
+ if order.includeOvernight: orderProto.includeOvernight = order.includeOvernight
267
+ if isValidIntValue(order.manualOrderIndicator): orderProto.manualOrderIndicator = order.manualOrderIndicator
268
+ if order.submitter: orderProto.submitter = order.submitter
269
+ if order.autoCancelParent: orderProto.autoCancelParent = order.autoCancelParent
270
+ if order.imbalanceOnly: orderProto.imbalanceOnly = order.imbalanceOnly
271
+
272
+ return orderProto
273
+
274
+ def createConditionsProto(order: Order) -> list[OrderConditionProto]:
275
+ orderConditionProtoList = []
276
+ if order.conditions is not None and order.conditions:
277
+ for orderCondition in order.conditions:
278
+ conditionType = orderCondition.condType
279
+
280
+ if OrderCondition.Price == conditionType:
281
+ orderConditionProto = createPriceConditionProto(orderCondition)
282
+ elif OrderCondition.Time == conditionType:
283
+ orderConditionProto = createTimeConditionProto(orderCondition)
284
+ elif OrderCondition.Margin == conditionType:
285
+ orderConditionProto = createMarginConditionProto(orderCondition)
286
+ elif OrderCondition.Execution == conditionType:
287
+ orderConditionProto = createExecutionConditionProto(orderCondition)
288
+ elif OrderCondition.Volume == conditionType:
289
+ orderConditionProto = createVolumeConditionProto(orderCondition)
290
+ elif OrderCondition.PercentChange == conditionType:
291
+ orderConditionProto = createPercentChangeConditionProto(orderCondition)
292
+
293
+ if orderConditionProto is not None: orderConditionProtoList.append(orderConditionProto)
294
+
295
+ return orderConditionProtoList
296
+
297
+ @staticmethod
298
+ def createOrderConditionProto(orderCondition: OrderCondition) -> OrderConditionProto:
299
+ conditionType = orderCondition.condType
300
+ isConjunctionConnection = orderCondition.isConjunctionConnection
301
+ orderConditionProto = OrderConditionProto()
302
+ if isValidIntValue(conditionType): orderConditionProto.type = conditionType
303
+ orderConditionProto.isConjunctionConnection = isConjunctionConnection
304
+ return orderConditionProto
305
+
306
+ @staticmethod
307
+ def createOperatorConditionProto(operatorCondition: OperatorCondition) -> OrderConditionProto:
308
+ orderConditionProto = createOrderConditionProto(operatorCondition)
309
+ operatorConditionProto = OrderConditionProto()
310
+ operatorConditionProto.MergeFrom(orderConditionProto)
311
+ operatorConditionProto.isMore = operatorCondition.isMore
312
+ return operatorConditionProto
313
+
314
+ @staticmethod
315
+ def createContractConditionProto(contractCondition: ContractCondition) -> OrderConditionProto:
316
+ operatorConditionProto = createOperatorConditionProto(contractCondition)
317
+ contractConditionProto = OrderConditionProto()
318
+ contractConditionProto.MergeFrom(operatorConditionProto)
319
+ if isValidIntValue(contractCondition.conId): contractConditionProto.conId = contractCondition.conId
320
+ if contractCondition.exchange: contractConditionProto.exchange = contractCondition.exchange
321
+ return contractConditionProto
322
+
323
+ @staticmethod
324
+ def createPriceConditionProto(priceCondition: PriceCondition) -> OrderConditionProto:
325
+ contractConditionProto = createContractConditionProto(priceCondition)
326
+ priceConditionProto = OrderConditionProto()
327
+ priceConditionProto.MergeFrom(contractConditionProto)
328
+ if isValidFloatValue(priceCondition.price): priceConditionProto.price = priceCondition.price
329
+ if isValidIntValue(priceCondition.triggerMethod): priceConditionProto.triggerMethod = priceCondition.triggerMethod
330
+ return priceConditionProto
331
+
332
+ @staticmethod
333
+ def createTimeConditionProto(timeCondition: TimeCondition) -> OrderConditionProto:
334
+ operatorConditionProto = createOperatorConditionProto(timeCondition)
335
+ timeConditionProto = OrderConditionProto()
336
+ timeConditionProto.MergeFrom(operatorConditionProto)
337
+ if timeCondition.time: timeConditionProto.time = timeCondition.time
338
+ return timeConditionProto
339
+
340
+ @staticmethod
341
+ def createMarginConditionProto(marginCondition: MarginCondition) -> OrderConditionProto:
342
+ operatorConditionProto = createOperatorConditionProto(marginCondition)
343
+ marginConditionProto = OrderConditionProto()
344
+ marginConditionProto.MergeFrom(operatorConditionProto)
345
+ if isValidFloatValue(marginCondition.percent): marginConditionProto.percent = marginCondition.percent
346
+ return marginConditionProto
347
+
348
+ @staticmethod
349
+ def createExecutionConditionProto(executionCondition: ExecutionCondition) -> OrderConditionProto:
350
+ orderConditionProto = createOrderConditionProto(executionCondition)
351
+ executionConditionProto = OrderConditionProto()
352
+ executionConditionProto.MergeFrom(orderConditionProto)
353
+ if executionCondition.secType: executionConditionProto.secType = executionCondition.secType
354
+ if executionCondition.exchange: executionConditionProto.exchange = executionCondition.exchange
355
+ if executionCondition.symbol: executionConditionProto.symbol = executionCondition.symbol
356
+ return executionConditionProto
357
+
358
+ @staticmethod
359
+ def createVolumeConditionProto(volumeCondition: VolumeCondition) -> OrderConditionProto:
360
+ contractConditionProto = createContractConditionProto(volumeCondition)
361
+ volumeConditionProto = OrderConditionProto()
362
+ volumeConditionProto.MergeFrom(contractConditionProto)
363
+ if isValidIntValue(volumeCondition.volume): volumeConditionProto.volume = volumeCondition.volume
364
+ return volumeConditionProto
365
+
366
+ @staticmethod
367
+ def createPercentChangeConditionProto(percentChangeCondition: PercentChangeCondition) -> OrderConditionProto:
368
+ contractConditionProto = createContractConditionProto(percentChangeCondition)
369
+ percentChangeConditionProto = OrderConditionProto()
370
+ percentChangeConditionProto.MergeFrom(contractConditionProto)
371
+ if isValidFloatValue(percentChangeCondition.changePercent): percentChangeConditionProto.changePercent = percentChangeCondition.changePercent
372
+ return percentChangeConditionProto
373
+
374
+ @staticmethod
375
+ def createSoftDollarTierProto(order: Order) -> SoftDollarTierProto:
376
+ softDollarTierProto = None
377
+ tier = order.softDollarTier
378
+ if tier is not None:
379
+ softDollarTierProto = SoftDollarTierProto()
380
+ if tier.name: softDollarTierProto.name = tier.name
381
+ if tier.val: softDollarTierProto.value = tier.val
382
+ if tier.displayName: softDollarTierProto.displayName = tier.displayName
383
+ return softDollarTierProto
384
+
385
+ @staticmethod
386
+ def fillTagValueList(tagValueList: list, orderProtoMap: dict):
387
+ if tagValueList is not None and tagValueList:
388
+ for tagValue in tagValueList:
389
+ orderProtoMap[tagValue.tag] = tagValue.value
390
+
391
+ @staticmethod
392
+ def createCancelOrderRequestProto(orderId: int, orderCancel: OrderCancelProto) -> CancelOrderRequestProto:
393
+ cancelOrderRequestProto = CancelOrderRequestProto()
394
+ if isValidIntValue(orderId): cancelOrderRequestProto.orderId = orderId
395
+ orderCancelProto = createOrderCancelProto(orderCancel)
396
+ if orderCancelProto is not None: cancelOrderRequestProto.orderCancel.CopyFrom(orderCancelProto)
397
+ return cancelOrderRequestProto
398
+
399
+ @staticmethod
400
+ def createGlobalCancelRequestProto(orderCancel: OrderCancelProto) -> GlobalCancelRequestProto:
401
+ globalCancelRequestProto = GlobalCancelRequestProto()
402
+ orderCancelProto = createOrderCancelProto(orderCancel)
403
+ if orderCancelProto is not None: globalCancelRequestProto.orderCancel.CopyFrom(orderCancelProto)
404
+ return globalCancelRequestProto
405
+
406
+ @staticmethod
407
+ def createOrderCancelProto(orderCancel: OrderCancelProto) -> OrderCancelProto:
408
+ orderCancelProto = OrderCancelProto()
409
+ if orderCancel.manualOrderCancelTime: orderCancelProto.manualOrderCancelTime = orderCancel.manualOrderCancelTime
410
+ if orderCancel.extOperator: orderCancelProto.extOperator = orderCancel.extOperator
411
+ if isValidIntValue(orderCancel.manualOrderIndicator): orderCancelProto.manualOrderIndicator = orderCancel.manualOrderIndicator
412
+ return orderCancelProto
ibapi/comm.py ADDED
@@ -0,0 +1,100 @@
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
+ This module has tools for implementing the IB low level messaging.
6
+ """
7
+
8
+ import struct
9
+ import logging
10
+ import sys
11
+
12
+ from ibapi.const import UNSET_INTEGER, UNSET_DOUBLE, DOUBLE_INFINITY, INFINITY_STR
13
+ from ibapi.utils import ClientException
14
+ from ibapi.utils import isAsciiPrintable
15
+ from ibapi.errors import INVALID_SYMBOL
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ def make_msg_proto(msgId: int, protobufData: bytes) -> bytes:
20
+ """adds the length prefix"""
21
+ byteArray = msgId.to_bytes(4, 'big') + protobufData
22
+ msg = struct.pack(f"!I{len(byteArray)}s", len(byteArray), byteArray)
23
+ return msg
24
+
25
+ def make_msg(msgId:int, useRawIntMsgId: bool, text: str) -> bytes:
26
+ """adds the length prefix"""
27
+ if useRawIntMsgId:
28
+ text = msgId.to_bytes(4, 'big') + str.encode(text)
29
+ else:
30
+ text = str.encode(make_field(msgId) + text)
31
+
32
+ msg = struct.pack(f"!I{len(text)}s", len(text), text)
33
+ return msg
34
+
35
+ def make_initial_msg(text: str) -> bytes:
36
+ """adds the length prefix"""
37
+ msg = struct.pack(f"!I{len(text)}s", len(text), str.encode(text))
38
+ return msg
39
+
40
+
41
+ def make_field(val) -> str:
42
+ """adds the NULL string terminator"""
43
+ if val is None:
44
+ raise ValueError("Cannot send None to TWS")
45
+
46
+ # if string is not empty and contains invalid symbols
47
+ if val is not None and type(val) == str and val and not isAsciiPrintable(val):
48
+ raise ClientException(
49
+ INVALID_SYMBOL.code(),
50
+ INVALID_SYMBOL.msg(),
51
+ val.encode(sys.stdout.encoding, errors="ignore").decode(
52
+ sys.stdout.encoding
53
+ ),
54
+ )
55
+
56
+ # bool type is encoded as int
57
+ if val is not None and type(val) == bool:
58
+ val = int(val)
59
+
60
+ field = str(val) + "\0"
61
+ return field
62
+
63
+
64
+ def make_field_handle_empty(val) -> str:
65
+ if val is None:
66
+ raise ValueError("Cannot send None to TWS")
67
+
68
+ if UNSET_INTEGER == val or UNSET_DOUBLE == val:
69
+ val = ""
70
+
71
+ if DOUBLE_INFINITY == val:
72
+ val = INFINITY_STR
73
+
74
+ return make_field(val)
75
+
76
+
77
+ def read_msg(buf: bytes) -> tuple:
78
+ """first the size prefix and then the corresponding msg payload"""
79
+
80
+ if len(buf) < 4:
81
+ return (0, "", buf)
82
+ size = struct.unpack("!I", buf[0:4])[0]
83
+ logger.debug("read_msg: size: %d", size)
84
+ if len(buf) - 4 >= size:
85
+ text = struct.unpack("!%ds" % size, buf[4 : 4 + size])[0]
86
+ return (size, text, buf[4 + size :])
87
+ else:
88
+ return (size, "", buf)
89
+
90
+
91
+ def read_fields(buf: bytes) -> tuple:
92
+ if isinstance(buf, str):
93
+ buf = buf.encode()
94
+
95
+ """ msg payload is made of fields terminated/separated by NULL chars """
96
+ fields = buf.split(b"\0")
97
+
98
+ return tuple(
99
+ fields[0:-1]
100
+ ) # last one is empty; this may slow dow things though, TODO
@@ -0,0 +1,31 @@
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
+ from ibapi.object_implem import Object
7
+ from ibapi.utils import intMaxString
8
+ from ibapi.utils import floatMaxString
9
+
10
+
11
+ class CommissionAndFeesReport(Object):
12
+ def __init__(self):
13
+ self.execId = ""
14
+ self.commissionAndFees = 0.0
15
+ self.currency = ""
16
+ self.realizedPNL = 0.0
17
+ self.yield_ = 0.0
18
+ self.yieldRedemptionDate = 0 # YYYYMMDD format
19
+
20
+ def __str__(self):
21
+ return (
22
+ "ExecId: %s, CommissionAndFees: %s, Currency: %s, RealizedPnL: %s, Yield: %s, YieldRedemptionDate: %s"
23
+ % (
24
+ self.execId,
25
+ floatMaxString(self.commissionAndFees),
26
+ self.currency,
27
+ floatMaxString(self.realizedPNL),
28
+ floatMaxString(self.yield_),
29
+ intMaxString(self.yieldRedemptionDate),
30
+ )
31
+ )