ib-api 972.0

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +16 -0
  7. data/Gemfile.lock +105 -0
  8. data/Guardfile +24 -0
  9. data/LICENSE +674 -0
  10. data/README.md +65 -0
  11. data/Rakefile +11 -0
  12. data/VERSION +1 -0
  13. data/api.gemspec +43 -0
  14. data/bin/console +95 -0
  15. data/bin/console.yml +3 -0
  16. data/bin/setup +8 -0
  17. data/changelog.md +7 -0
  18. data/example/README.md +76 -0
  19. data/example/account_info +54 -0
  20. data/example/account_positions +30 -0
  21. data/example/account_summary +88 -0
  22. data/example/cancel_orders +74 -0
  23. data/example/fa_accounts +25 -0
  24. data/example/fundamental_data +40 -0
  25. data/example/historic_data_cli +186 -0
  26. data/example/list_orders +45 -0
  27. data/example/portfolio_csv +81 -0
  28. data/example/scanner_data +62 -0
  29. data/example/template +19 -0
  30. data/example/tick_data +28 -0
  31. data/lib/extensions/class-extensions.rb +87 -0
  32. data/lib/ib-api.rb +7 -0
  33. data/lib/ib/base.rb +103 -0
  34. data/lib/ib/base_properties.rb +160 -0
  35. data/lib/ib/connection.rb +450 -0
  36. data/lib/ib/constants.rb +393 -0
  37. data/lib/ib/errors.rb +44 -0
  38. data/lib/ib/logger.rb +26 -0
  39. data/lib/ib/messages.rb +99 -0
  40. data/lib/ib/messages/abstract_message.rb +101 -0
  41. data/lib/ib/messages/incoming.rb +251 -0
  42. data/lib/ib/messages/incoming/abstract_message.rb +116 -0
  43. data/lib/ib/messages/incoming/account_value.rb +78 -0
  44. data/lib/ib/messages/incoming/alert.rb +34 -0
  45. data/lib/ib/messages/incoming/contract_data.rb +102 -0
  46. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  47. data/lib/ib/messages/incoming/execution_data.rb +50 -0
  48. data/lib/ib/messages/incoming/historical_data.rb +84 -0
  49. data/lib/ib/messages/incoming/market_depths.rb +44 -0
  50. data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
  51. data/lib/ib/messages/incoming/open_order.rb +277 -0
  52. data/lib/ib/messages/incoming/order_status.rb +85 -0
  53. data/lib/ib/messages/incoming/portfolio_value.rb +78 -0
  54. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  55. data/lib/ib/messages/incoming/scanner_data.rb +54 -0
  56. data/lib/ib/messages/incoming/ticks.rb +268 -0
  57. data/lib/ib/messages/outgoing.rb +437 -0
  58. data/lib/ib/messages/outgoing/abstract_message.rb +88 -0
  59. data/lib/ib/messages/outgoing/account_requests.rb +112 -0
  60. data/lib/ib/messages/outgoing/bar_requests.rb +250 -0
  61. data/lib/ib/messages/outgoing/place_order.rb +209 -0
  62. data/lib/ib/messages/outgoing/request_marketdata.rb +99 -0
  63. data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
  64. data/lib/ib/model.rb +4 -0
  65. data/lib/ib/models.rb +14 -0
  66. data/lib/ib/server_versions.rb +114 -0
  67. data/lib/ib/socket.rb +185 -0
  68. data/lib/ib/support.rb +160 -0
  69. data/lib/ib/version.rb +6 -0
  70. data/lib/models/ib/account.rb +85 -0
  71. data/lib/models/ib/account_value.rb +33 -0
  72. data/lib/models/ib/bag.rb +55 -0
  73. data/lib/models/ib/bar.rb +31 -0
  74. data/lib/models/ib/combo_leg.rb +105 -0
  75. data/lib/models/ib/condition.rb +245 -0
  76. data/lib/models/ib/contract.rb +415 -0
  77. data/lib/models/ib/contract_detail.rb +108 -0
  78. data/lib/models/ib/execution.rb +67 -0
  79. data/lib/models/ib/forex.rb +13 -0
  80. data/lib/models/ib/future.rb +15 -0
  81. data/lib/models/ib/index.rb +15 -0
  82. data/lib/models/ib/option.rb +78 -0
  83. data/lib/models/ib/option_detail.rb +55 -0
  84. data/lib/models/ib/order.rb +519 -0
  85. data/lib/models/ib/order_state.rb +152 -0
  86. data/lib/models/ib/portfolio_value.rb +64 -0
  87. data/lib/models/ib/stock.rb +16 -0
  88. data/lib/models/ib/underlying.rb +34 -0
  89. data/lib/models/ib/vertical.rb +96 -0
  90. data/lib/requires.rb +12 -0
  91. metadata +203 -0
@@ -0,0 +1,32 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # RealTimeBar contains following @data:
6
+ # :request_id - The ID of the *request* to which this is responding
7
+ # :time - The date-time stamp of the start of the bar. The format is offset in
8
+ # seconds from the beginning of 1970, same format as the UNIX epoch time
9
+ # :bar - received RT Bar
10
+ RealTimeBar = def_message [50, 3],
11
+ [:request_id, :int],
12
+ [:bar, :time, :int_date],
13
+ [:bar, :open, :decimal],
14
+ [:bar, :high, :decimal],
15
+ [:bar, :low, :decimal],
16
+ [:bar, :close, :decimal],
17
+ [:bar, :volume, :int],
18
+ [:bar, :wap, :decimal],
19
+ [:bar, :trades, :int]
20
+ class RealTimeBar
21
+ def bar
22
+ @bar = IB::Bar.new @data[:bar]
23
+ end
24
+
25
+ def to_human
26
+ "<RealTimeBar: #{request_id} #{bar}>"
27
+ end
28
+ end # RealTimeBar
29
+
30
+ end # module Incoming
31
+ end # module Messages
32
+ end # module IB
@@ -0,0 +1,54 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # This method receives the requested market scanner data results.
6
+ # ScannerData contains following @data:
7
+ # :request_id - The ID of the request to which this row is responding
8
+ # :count - Number of data points returned (size of :results).
9
+ # :results - an Array of Hashes, each hash contains a set of
10
+ # data about one scanned Contract:
11
+ # :contract - a full description of the contract (details).
12
+ # :distance - Varies based on query.
13
+ # :benchmark - Varies based on query.
14
+ # :projection - Varies based on query.
15
+ # :legs - Describes combo legs when scan is returning EFP.
16
+ ScannerData = def_message [20, 3],
17
+ [:request_id, :int], # request id
18
+ [:count, :int]
19
+ class ScannerData
20
+ attr_accessor :results
21
+ using IBSupport # extended Array-Class from abstract_message
22
+
23
+ def load
24
+ super
25
+
26
+ @results = Array.new(@data[:count]) do |_|
27
+ {:rank => buffer.read_int,
28
+ :contract =>
29
+ Contract.build(
30
+ :con_id => buffer.read_int,
31
+ :symbol => buffer.read_string,
32
+ :sec_type => buffer.read_string,
33
+ :expiry => buffer.read_string,
34
+ :strike => buffer.read_decimal,
35
+ :right => buffer.read_string,
36
+ :exchange => buffer.read_string,
37
+ :currency => buffer.read_string,
38
+ :local_symbol => buffer.read_string,
39
+ :contract_detail =>
40
+ IB::ContractDetail.new(
41
+ :market_name => buffer.read_string,
42
+ :trading_class => buffer.read_string)),
43
+ :distance => buffer.read_string,
44
+ :benchmark => buffer.read_string,
45
+ :projection => buffer.read_string,
46
+ :legs => buffer.read_string,
47
+ }
48
+ end
49
+ end
50
+ end # ScannerData
51
+
52
+ end # module Incoming
53
+ end # module Messages
54
+ end # module IB
@@ -0,0 +1,268 @@
1
+ # All message classes related to ticks located here
2
+ module IB
3
+ module Messages
4
+ module Incoming
5
+
6
+ class AbstractTick < AbstractMessage
7
+ # Returns Symbol with a meaningful name for received tick type
8
+ def type
9
+ TICK_TYPES[@data[:tick_type]]
10
+ end
11
+
12
+ def to_human
13
+ "<#{self.message_type} #{type}:" +
14
+ @data.map do |key, value|
15
+ " #{key} #{value}" unless [:version, :ticker_id, :tick_type].include?(key)
16
+ end.compact.join(',') + " >"
17
+ end
18
+
19
+ def the_data
20
+ @data.reject{|k,_| [:version, :ticker_id].include? k }
21
+ end
22
+ end
23
+
24
+
25
+ # The IB code seems to dispatch up to two wrapped objects for this message, a tickPrice
26
+ # and sometimes a tickSize, which seems to be identical to the TICK_SIZE object.
27
+ #
28
+ # Important note from
29
+ # http://chuckcaplan.com/twsapi/index.php/void%20tickPrice%28%29 :
30
+ #
31
+ # "The low you get is NOT the low for the day as you'd expect it
32
+ # to be. It appears IB calculates the low based on all
33
+ # transactions after 4pm the previous day. The most inaccurate
34
+ # results occur when the stock moves up in the 4-6pm aftermarket
35
+ # on the previous day and then gaps open upward in the
36
+ # morning. The low you receive from TWS can be easily be several
37
+ # points different from the actual 9:30am-4pm low for the day in
38
+ # cases like this. If you require a correct traded low for the
39
+ # day, you can't get it from the TWS API. One possible source to
40
+ # help build the right data would be to compare against what Yahoo
41
+ # lists on finance.yahoo.com/q?s=ticker under the "Day's Range"
42
+ # statistics (be careful here, because Yahoo will use anti-Denial
43
+ # of Service techniques to hang your connection if you try to
44
+ # request too many bytes in a short period of time from them). For
45
+ # most purposes, a good enough approach would start by replacing
46
+ # the TWS low for the day with Yahoo's day low when you first
47
+ # start watching a stock ticker; let's call this time T. Then,
48
+ # update your internal low if the bid or ask tick you receive is
49
+ # lower than that for the remainder of the day. You should check
50
+ # against Yahoo again at time T+20min to handle the occasional
51
+ # case where the stock set a new low for the day in between
52
+ # T-20min (the real time your original quote was from, taking into
53
+ # account the delay) and time T. After that you should have a
54
+ # correct enough low for the rest of the day as long as you keep
55
+ # updating based on the bid/ask. It could still get slightly off
56
+ # in a case where a short transaction setting a new low appears in
57
+ # between ticks of data that TWS sends you. The high is probably
58
+ # distorted in the same way the low is, which would throw your
59
+ # results off if the stock traded after-hours and gapped down. It
60
+ # should be corrected in a similar way as described above if this
61
+ # is important to you."
62
+ #
63
+ # IB then emits at most 2 events on eWrapper:
64
+ # tickPrice( tickerId, tickType, price, canAutoExecute)
65
+ # tickSize( tickerId, sizeTickType, size)
66
+ TickPrice = def_message [1, 6], AbstractTick,
67
+ [:ticker_id, :int],
68
+ [:tick_type, :int],
69
+ [:price, :float],
70
+ [:size, :int],
71
+ [:can_auto_execute, :int]
72
+ class TickPrice
73
+ def valid?
74
+ super && !price.zero?
75
+ end
76
+ end
77
+
78
+ TickSize = def_message [2, 6], AbstractTick,
79
+ [:ticker_id, :int],
80
+ [:tick_type, :int],
81
+ [:size, :int]
82
+
83
+ TickGeneric = def_message [45, 6], AbstractTick,
84
+ [:ticker_id, :int],
85
+ [:tick_type, :int],
86
+ [:value, :decimal]
87
+
88
+ TickString = def_message [46, 6], AbstractTick,
89
+ [:ticker_id, :int],
90
+ [:tick_type, :int],
91
+ [:value, :string]
92
+
93
+ TickEFP = def_message [47, 6], AbstractTick,
94
+ [:ticker_id, :int],
95
+ [:tick_type, :int],
96
+ [:basis_points, :decimal],
97
+ [:formatted_basis_points, :string],
98
+ [:implied_futures_price, :decimal],
99
+ [:hold_days, :int],
100
+ [:dividend_impact, :decimal],
101
+ [:dividends_to_expiry, :decimal]
102
+
103
+ # This message is received when the market in an option or its underlier moves.
104
+ # TWS option model volatilities, prices, and deltas, along with the present
105
+ # value of dividends expected on that options underlier are received.
106
+ # TickOption message contains following @data:
107
+ # :ticker_id - Id that was specified previously in the call to reqMktData()
108
+ # :tick_type - Specifies the type of option computation (see TICK_TYPES).
109
+ # :implied_volatility - The implied volatility calculated by the TWS option
110
+ # modeler, using the specified :tick_type value.
111
+ # :delta - The option delta value.
112
+ # :option_price - The option price.
113
+ # :pv_dividend - The present value of dividends expected on the options underlier
114
+ # :gamma - The option gamma value.
115
+ # :vega - The option vega value.
116
+ # :theta - The option theta value.
117
+ # :under_price - The price of the underlying.
118
+ TickOptionComputation = TickOption =
119
+ def_message([21, 6], AbstractTick,
120
+ [:ticker_id, :int],
121
+ [:tick_type, :int],
122
+ # What is the "not yet computed" indicator:
123
+ [:implied_volatility, :decimal_limit_1], # -1 and below
124
+ [:delta, :decimal_limit_2], # -2 and below
125
+ [:option_price, :decimal_limit_1], # -1 -"-
126
+ [:pv_dividend, :decimal_limit_1], # -1 -"-
127
+ [:gamma, :decimal_limit_2], # -2 -"-
128
+ [:vega, :decimal_limit_2], # -2 -"-
129
+ [:theta, :decimal_limit_2], # -2 -"-
130
+ [:under_price, :decimal_limit_1]) do
131
+
132
+ "<TickOption #{type} for #{ticker_id}: underlying @ #{under_price}, "+
133
+ "option @ #{option_price}, IV #{implied_volatility}%, delta #{delta}, " +
134
+ "gamma #{gamma}, vega #{vega}, theta #{theta}, pv_dividend #{pv_dividend}>"
135
+ end
136
+
137
+ TickSnapshotEnd = def_message 57, [:ticker_id, :int]
138
+ =begin
139
+ def processTickByTickMsg(self, fields):
140
+ next(fields)
141
+ reqId = decode(int, fields)
142
+ tickType = decode(int, fields)
143
+ time = decode(int, fields)
144
+
145
+ if tickType == 0:
146
+ # None
147
+ pass
148
+ elif tickType == 1 or tickType == 2:
149
+ # Last or AllLast
150
+ price = decode(float, fields)
151
+ size = decode(int, fields)
152
+ mask = decode(int, fields)
153
+ class TickAttribLast(Object):
154
+ def __init__(self):
155
+ self.pastLimit = False
156
+ self.unreported = False
157
+
158
+ def __str__(self):
159
+ return "PastLimit: %d, Unreported: %d" % (self.pastLimit, self.unreported)
160
+
161
+ tickAttribLast = TickAttribLast()
162
+ tickAttribLast.pastLimit = mask & 1 != 0
163
+ tickAttribLast.unreported = mask & 2 != 0
164
+ exchange = decode(str, fields)
165
+ specialConditions = decode(str, fields)
166
+
167
+ self.wrapper.tickByTickAllLast(reqId, tickType, time, price, size, tickAttribLast,
168
+ exchange, specialConditions)
169
+ elif tickType == 3:
170
+ # BidAsk
171
+ bidPrice = decode(float, fields)
172
+ askPrice = decode(float, fields)
173
+ bidSize = decode(int, fields)
174
+ askSize = decode(int, fields)
175
+ mask = decode(int, fields)
176
+ class TickAttribBidAsk(Object):
177
+ def __init__(self):
178
+ self.bidPastLow = False
179
+ self.askPastHigh = False
180
+
181
+ def __str__(self):
182
+ return "BidPastLow: %d, AskPastHigh: %d" % (self.bidPastLow, self.askPastHigh)
183
+
184
+
185
+ tickAttribBidAsk = TickAttribBidAsk()
186
+ tickAttribBidAsk.bidPastLow = mask & 1 != 0
187
+ tickAttribBidAsk.askPastHigh = mask & 2 != 0
188
+
189
+ self.wrapper.tickByTickBidAsk(reqId, time, bidPrice, askPrice, bidSize,
190
+ askSize, tickAttribBidAsk)
191
+ elif tickType == 4:
192
+ # MidPoint
193
+ midPoint = decode(float, fields)
194
+
195
+ self.wrapper.tickByTickMidPoint(reqId, time, midPoint)
196
+ =end
197
+ TickByTick = def_message [99, 0], [:ticker_id, :int ],
198
+ [ :tick_type, :int],
199
+ [ :time, :int_date ]
200
+
201
+ ## error messages: (10189) "Failed to request tick-by-tick data:Historical data request pacing violation"
202
+ #
203
+ class TickByTick
204
+ using IBSupport # extended Array-Class from abstract_message
205
+
206
+ def resolve_mask
207
+ @data[:mask].present? ? [ @data[:mask] & 1 , @data[:mask] & 2 ] : []
208
+ end
209
+
210
+ def load
211
+ super
212
+ case @data[:tick_type ]
213
+ when 0
214
+ # do nothing
215
+ when 1, 2 # Last, AllLast
216
+ load_map [ :price, :decimal ] ,
217
+ [ :size, :int ] ,
218
+ [ :mask, :int ] ,
219
+ [ :exchange, :string ],
220
+ [ :special_conditions, :string ]
221
+ when 3 # bid/ask
222
+ load_map [ :bid_price, :decimal ],
223
+ [ :ask_price, :decimal],
224
+ [ :bid_size, :int ],
225
+ [ :ask_size, :int] ,
226
+ [ :mask, :int ]
227
+ when 4
228
+ load_map [ :mid_point, :decimal ]
229
+ end
230
+
231
+ @out_labels = case @data[ :tick_tpye ]
232
+ when 1, 2
233
+ [ "PastLimit", "Unreported" ]
234
+ when 3
235
+ [ "BitPastLow", "BidPastHigh" ]
236
+ else
237
+ []
238
+ end
239
+ end
240
+ def to_human
241
+ "< TickByTick:" + case @data[ :tick_type ]
242
+ when 1,2
243
+ "(Last) #{size} @ #{price} [#{exchange}] "
244
+ when 3
245
+ "(Bid/Ask) #{bid_size} @ #{bid_price} / #{ask_size } @ #{ask_price} "
246
+ when 4
247
+ "(Midpoint) #{mid_point } "
248
+ else
249
+ ""
250
+ end + @out_labels.zip(resolve_mask).join( "/" )
251
+ end
252
+
253
+ [:price, :size, :mask, :exchange, :specialConditions, :bid_price, :ask_price, :bid_size, :ask_size, :mid_point].each do |name|
254
+ define_method name do
255
+ @data[name]
256
+ end
257
+ end
258
+ # def method_missing method, *args
259
+ # if @data.keys.include? method
260
+ # @data[method]
261
+ # else
262
+ # error "method #{method} not known"
263
+ # end
264
+ # end
265
+ end
266
+ end # module Incoming
267
+ end # module Messages
268
+ end # module IB
@@ -0,0 +1,437 @@
1
+ require 'ib/messages/outgoing/abstract_message'
2
+
3
+ # TODO: Don't instantiate messages, use their classes as just namespace for .encode/decode
4
+
5
+ module IB
6
+ module Messages
7
+
8
+ # Outgoing IB messages (sent to TWS/Gateway)
9
+ module Outgoing
10
+ extend Messages # def_message macros
11
+
12
+ ### Defining (short) Outgoing Message classes for IB:
13
+
14
+ ## Empty messages (no data)
15
+
16
+ # Request the open orders that were placed from THIS client. Each open order
17
+ # will be fed back through the OpenOrder and OrderStatus messages ONCE.
18
+ # NB: Client with a client_id of 0 will also receive the TWS-owned open orders.
19
+ # These orders will be associated with the client and a new orderId will be
20
+ # generated. This association will persist over multiple API and TWS sessions.
21
+ RequestOpenOrders = def_message 5
22
+
23
+ # Request the open orders placed from all clients and also from TWS. Each open
24
+ # order will be fed back through the OpenOrder and OrderStatus messages ONCE.
25
+ # Note this does not re-bind those Orders to requesting Client!
26
+ # Use RequestAutoOpenOrders to request such re-binding.
27
+ RequestAllOpenOrders = def_message 16
28
+
29
+ # Request that newly created TWS orders be implicitly associated with this client.
30
+ # When a new TWS order is created, the order will be associated with this client
31
+ # and automatically fed back through the OpenOrder and OrderStatus messages.
32
+ # It is a 'continuous' request such that it gets turned 'on' when called with a
33
+ # TRUE auto_bind parameter. When it's called with FALSE auto_bind, new TWS orders
34
+ # will not bind to this client going forward. Note that TWS orders can only be
35
+ # bound to clients with a client_id of 0. TODO: how to properly test this?
36
+ # data = { :auto_bind => boolean }
37
+ RequestAutoOpenOrders = def_message 15, :auto_bind
38
+
39
+ # Requests an XML document that describes the valid parameters that a scanner
40
+ # subscription can have (for outgoing RequestScannerSubscription message).
41
+ RequestScannerParameters = def_message 24
42
+
43
+ RequestNewsArticle = def_message 84,
44
+ :request_id , # autogenerated
45
+ :provider_code,
46
+ :article_id,
47
+ :options # taglist
48
+
49
+
50
+ RequestNewsProviders = def_message 85 # no further parameters
51
+ RequestHistoricalNews = def_message 86,
52
+ :request_id , # autogenerated
53
+ :con_id,
54
+ :provider_code,
55
+ :start, # date
56
+ :total_results,
57
+ :options # taglist
58
+
59
+
60
+ CancelNewsBulletins = def_message 13
61
+ RequestCurrentTime = def_message 49
62
+ RequestGlobalCancel = def_message 58
63
+
64
+ ## Data format is: @data = { :id => ticker_id}
65
+ CancelMarketData = def_message [2, 2]
66
+ CancelMarketDepth = def_message 11
67
+ CancelScannerSubscription = def_message 23
68
+ CancelHistoricalData = def_message 25
69
+ CancelRealTimeBars = def_message 51
70
+
71
+ ## Data format is: @data = { :id => request_id }
72
+ CancelFundamentalData = def_message 53
73
+ CancelCalculateImpliedVolatility = CancelImpliedVolatility = def_message 56
74
+ CancelCalculateOptionPrice = CancelOptionPrice = def_message 57
75
+
76
+ ## Data format is: @data ={ :id => local_id of order to cancel }
77
+ CancelOrder = def_message 4
78
+
79
+ # Request the next valid ID that can be used when placing an order. Responds with
80
+ # NextValidId message, and the id returned is that next valid Id for orders.
81
+ # That ID will reflect any autobinding that has occurred (which generates new
82
+ # IDs and increments the next valid ID therein).
83
+ # @data = { :number of ids requested => int } NB: :number option is ignored by TWS!
84
+ RequestIds = def_message 8, [:number, 1]
85
+ # data = { :all_messages => boolean }
86
+ RequestNewsBulletins = def_message 12, :all_messages
87
+ # data = { :log_level => int }
88
+ SetServerLoglevel = def_message 14, :log_level
89
+ # data = { :fa_data_type => int } 1 -> groups, 2 -> Profiles, 3 -> Account Aliases
90
+ RequestFA = def_message 18, :fa_data_type
91
+ # data = { :fa_data_type => int, :xml => String }
92
+ ReplaceFA = def_message 19, :fa_data_type, :xml
93
+ # data = { :market_data_type => int }
94
+
95
+
96
+ # data => { :id => request_id (int), :contract => Contract }
97
+ #
98
+ # Special case for options: "wildcards" in the Contract fields retrieve Option chains
99
+ # strike = 0 means all strikes
100
+ # right = "" meanns both call and put
101
+ # expiry = "" means all expiries
102
+ # expiry = "2013" means all expiries in 2013
103
+ # expiry = "201311" means all expiries in Nov 2013
104
+ # You'll get several ContractData (10) messages back if there is more than one match.
105
+ # When all the matches are delivered you'll get ContractDataEnd (52) message.
106
+ RequestContractDetails = RequestContractData =
107
+ def_message([9, 8], :request_id , # autogenerated
108
+ [:contract, :serialize_long, [:sec_id_type]])
109
+
110
+ # Requests security definition option parameters for viewing a contract's option chain
111
+ # request_id: The ID chosen for the request
112
+ # underlyingSymbol
113
+ # futFopExchange: The exchange on which the returned options are trading.
114
+ # Can be set to the empty string "" for all exchanges.
115
+ # underlyingSecType: The type of the underlying security, i.e. STK
116
+ # underlyingConId: the contract ID of the underlying security.
117
+ # con_id:
118
+ # Responses via Messages::Incoming::SecurityDefinitionOptionParameter
119
+
120
+
121
+ RequestSecurityDefinitionOptionParameters = ReqSecDefOptParams = RequestOptionChainDefinition = def_message [78,0],
122
+ :request_id, # autogenerated if not specified
123
+ :symbol, # underlyingSymbol
124
+ [:exchange, ""], # futOptExchange
125
+ :sec_type, # underlyingSecType
126
+ :con_id # underlyingConId (required)
127
+
128
+ # data = { :id => ticker_id (int), :contract => Contract, :num_rows => int }
129
+
130
+
131
+ # Requests venues for which market data is returned to updateMktDepthL2
132
+ # returns MarketDepthExchanges-Message
133
+ #
134
+ RequestMarketDepthExchanges = # requires ServerVersion >= 112
135
+ def_message 82
136
+
137
+
138
+ ## actual Version supported is: 137
139
+ ## changes: MIN_SERVER_VER_SMART_DEPTH: 146 --> insert 'is_smarth_depth' after 'num_rows'
140
+ ## then: 'is_smart_depth' (bool) has to be specified in CancelMarketDepth, too
141
+ #
142
+ RequestMarketDepth = def_message([10, 5],
143
+ :request_id, # autogenerated if not specified
144
+ [:contract, :serialize_supershort ],
145
+ :num_rows,
146
+ "") # mktDataOptionsStr. ## not supported by api
147
+
148
+ # When this message is sent, TWS responds with ExecutionData messages, each
149
+ # containing the execution report that meets the specified criteria.
150
+ # @data={:id => int: :request_id,
151
+ # :client_id => int: Filter the results based on the clientId.
152
+ # :account => Filter the results based on based on account code.
153
+ # Note: this is only relevant for Financial Advisor accts.
154
+ # :sec_type => Filter the results based on the order security type.
155
+ # :time => Filter the results based on execution reports received
156
+ # after the specified time - format "yyyymmdd-hh:mm:ss"
157
+ # :symbol => Filter the results based on the order symbol.
158
+ # :exchange => Filter the results based on the order exchange
159
+ # :side => Filter the results based on the order action: BUY/SELL/SSHORT
160
+ RequestExecutions = def_message([7, 3],
161
+ :request_id, # autogenerated if not specified
162
+ :client_id,
163
+ :account,
164
+ :time, # Format "yyyymmdd-hh:mm:ss"
165
+ :symbol,
166
+ :sec_type,
167
+ :exchange,
168
+ :side)
169
+
170
+ # data = { :id => ticker_id (int),
171
+ # :contract => IB::Contract,
172
+ # :exercise_action => int, 1 = exercise, 2 = lapse
173
+ # :exercise_quantity => int, The number of contracts to be exercised
174
+ # :account => string,
175
+ # :override => int: Specifies whether your setting will override the
176
+ # system's natural action. For example, if your action
177
+ # is "exercise" and the option is not in-the-money, by
178
+ # natural action the option would not exercise. If you
179
+ # have override set to "yes" the natural action would be
180
+ # overridden and the out-of-the money option would be
181
+ # exercised. Values are:
182
+ # - 0 = do not override
183
+ # - 1 = override
184
+ ExerciseOptions = def_message([ 21, 2 ],
185
+ # :request_id, # id -> required # todo : TEST
186
+ [:contract, :serialize_short],
187
+ :exercise_action,
188
+ :exercise_quantity,
189
+ :account,
190
+ :override)
191
+
192
+
193
+ # The API can receive frozen market data from Trader Workstation. Frozen market
194
+ # data is the last data recorded in our system. During normal trading hours,
195
+ # the API receives real-time market data. If you use this function, you are
196
+ # telling TWS to automatically switch to frozen market data AFTER the close.
197
+ # Then, before the opening of the next trading day, market data will automatically
198
+ # switch back to real-time market data.
199
+ # :market_data_type = 1 (:real_time) for real-time streaming, 2 (:frozen) for frozen market data
200
+ # = 3 (:delayed) for delayed streaming , 4 (:frozen_delayed) for frozen delayed
201
+ RequestMarketDataType =
202
+ def_message 59, [:market_data_type,
203
+ lambda { |type| MARKET_DATA_TYPES.invert[type] || type }, []]
204
+
205
+ # Send this message to receive Reuters global fundamental data. There must be
206
+ # a subscription to Reuters Fundamental set up in Account Management before
207
+ # you can receive this data.
208
+ # data = { :id => int: :request_id,
209
+ # :contract => Contract,
210
+ # :report_type => String: one of the following:
211
+ # 'estimates' - Estimates
212
+ # 'finstat' - Financial statements
213
+ # 'snapshot' - Summary }a
214
+ # ReportsFinSummary Financial summary
215
+ #ReportsOwnership Company's ownership (Can be large in size)
216
+ #ReportSnapshot Company's financial overview
217
+ #ReportsFinStatements Financial Statements
218
+ #RESC Analyst Estimates
219
+ #CalendarReport Company's calendar
220
+ RequestFundamentalData =
221
+ def_message([52,2],
222
+ :request_id, # autogenerated if not specified
223
+ [:contract, :serialize, :primary_exchange],
224
+ :report_type,
225
+ "" )
226
+
227
+ # Returns the timestamp of earliest available historical data for a contract and data type.
228
+ # :what_to_show: type of data for head timestamp - "BID", "ASK", "TRADES", etc
229
+ # :use_rth : use regular trading hours only, 1 for yes or 0 for no
230
+ # format_data : set to 2 to obtain it like system time format in second ---> don't change
231
+ RequestHeadTimeStamp =
232
+ def_message( [87,0], :request_id, # autogenerated
233
+ [:contract, :serialize_short, [:primary_exchange,:include_expired] ],
234
+ [:use_rth, 1 ],
235
+ [:what_to_show, 'Trades' ],
236
+ [:format_date, 2 ] ) ## don't change!
237
+
238
+ CancelHeadTimeStamp =
239
+ def_message [90,0 ] # , :(request_)id #required
240
+
241
+
242
+
243
+ RequestHistogramData =
244
+ def_message( [88, 0], :request_id, # autogenerated
245
+ [:contract, :serialize_short, [:primary_exchange,:include_expired] ],
246
+ [:use_rth, 1 ],
247
+ [:time_period ] )
248
+
249
+ CancelHistogramData =
250
+ def_message [89,0 ] # , :(request_)id required
251
+
252
+ RequestCalculateImpliedVolatility = CalculateImpliedVolatility =
253
+ RequestImpliedVolatility =
254
+ def_message([ 54,3 ],:request_id, # autogenerated
255
+ [:contract, :serialize_short, :primary_exchange],
256
+ :option_price,
257
+ :under_price,
258
+ [:implied_volatility_options_count, 0],
259
+ [:implied_volatility_options_conditions, ''])
260
+
261
+ # data = { :request_id => int, :contract => Contract,
262
+ # :volatility => double, :under_price => double }
263
+ RequestCalculateOptionPrice = CalculateOptionPrice = RequestOptionPrice =
264
+ def_message([ 55, 3], :request_id, #autogenerated if not specified
265
+ [:contract, :serialize_short, :primary_exchange],
266
+ :volatility,
267
+ :under_price,
268
+ [:implied_volatility_options_count, 0],
269
+ [:implied_volatility_options_conditions, ''])
270
+
271
+ # Start receiving market scanner results through the ScannerData messages.
272
+ # @data = { :id => ticker_id (int),
273
+ # :number_of_rows => int: number of rows of data to return for a query.
274
+ # :instrument => The instrument type for the scan. Values include
275
+ # 'STK', - US stocks
276
+ # 'STOCK.HK' - Asian stocks
277
+ # 'STOCK.EU' - European stocks
278
+ # :location_code => Legal Values include:
279
+ # - STK.US - US stocks
280
+ # - STK.US.MAJOR - US stocks (without pink sheet)
281
+ # - STK.US.MINOR - US stocks (only pink sheet)
282
+ # - STK.HK.SEHK - Hong Kong stocks
283
+ # - STK.HK.ASX - Australian Stocks
284
+ # - STK.EU - European stocks
285
+ # :scan_code => The type of the scan, such as HIGH_OPT_VOLUME_PUT_CALL_RATIO.
286
+ # :above_price => double: Only contracts with a price above this value.
287
+ # :below_price => double: Only contracts with a price below this value.
288
+ # :above_volume => int: Only contracts with a volume above this value.
289
+ # :market_cap_above => double: Only contracts with a market cap above this
290
+ # :market_cap_below => double: Only contracts with a market cap below this value.
291
+ # :moody_rating_above => Only contracts with a Moody rating above this value.
292
+ # :moody_rating_below => Only contracts with a Moody rating below this value.
293
+ # :sp_rating_above => Only contracts with an S&P rating above this value.
294
+ # :sp_rating_below => Only contracts with an S&P rating below this value.
295
+ # :maturity_date_above => Only contracts with a maturity date later than this
296
+ # :maturity_date_below => Only contracts with a maturity date earlier than this
297
+ # :coupon_rate_above => double: Only contracts with a coupon rate above this
298
+ # :coupon_rate_below => double: Only contracts with a coupon rate below this
299
+ # :exclude_convertible => Exclude convertible bonds.
300
+ # :scanner_setting_pairs => Used with the scan_code to help further narrow your query.
301
+ # Scanner Setting Pairs are delimited by slashes, making
302
+ # this parameter open ended. Example is "Annual,true" -
303
+ # when used with 'Top Option Implied Vol % Gainers' scan
304
+ # would return annualized volatilities.
305
+ # :average_option_volume_above => int: Only contracts with average volume above this
306
+ # :stock_type_filter => Valid values are:
307
+ # 'ALL' (excludes nothing)
308
+ # 'STOCK' (excludes ETFs)
309
+ # 'ETF' (includes ETFs) }
310
+ # ------------
311
+ # To learn all valid parameter values that a scanner subscription can have,
312
+ # first subscribe to ScannerParameters and send RequestScannerParameters message.
313
+ # Available scanner parameters values will be listed in received XML document.
314
+ RequestScannerSubscription =
315
+ def_message([22, 3], :request_id ,
316
+ [:number_of_rows, -1], # was: EOL,
317
+ :instrument,
318
+ :location_code,
319
+ :scan_code,
320
+ :above_price,
321
+ :below_price,
322
+ :above_volume,
323
+ :market_cap_above,
324
+ :market_cap_below,
325
+ :moody_rating_above,
326
+ :moody_rating_below,
327
+ :sp_rating_above,
328
+ :sp_rating_below,
329
+ :maturity_date_above,
330
+ :maturity_date_below,
331
+ :coupon_rate_above,
332
+ :coupon_rate_below,
333
+ :exclude_convertible,
334
+ :average_option_volume_above, # ?
335
+ :scanner_setting_pairs,
336
+ :stock_type_filter)
337
+
338
+
339
+
340
+ require 'ib/messages/outgoing/place_order'
341
+ require 'ib/messages/outgoing/bar_requests'
342
+ require 'ib/messages/outgoing/account_requests'
343
+ require 'ib/messages/outgoing/request_marketdata'
344
+ require 'ib/messages/outgoing/request_tick_data'
345
+
346
+ end # module Outgoing
347
+ end # module Messages
348
+ end # module IB
349
+
350
+ __END__
351
+ ## python: message.py
352
+ REQ_MKT_DATA = 1
353
+ CANCEL_MKT_DATA = 2
354
+ PLACE_ORDER = 3
355
+ CANCEL_ORDER = 4
356
+ REQ_OPEN_ORDERS = 5
357
+ REQ_ACCT_DATA = 6
358
+ REQ_EXECUTIONS = 7
359
+ REQ_IDS = 8
360
+ REQ_CONTRACT_DATA = 9
361
+ REQ_MKT_DEPTH = 10
362
+ CANCEL_MKT_DEPTH = 11
363
+ REQ_NEWS_BULLETINS = 12
364
+ CANCEL_NEWS_BULLETINS = 13
365
+ SET_SERVER_LOGLEVEL = 14
366
+ REQ_AUTO_OPEN_ORDERS = 15
367
+ REQ_ALL_OPEN_ORDERS = 16
368
+ REQ_MANAGED_ACCTS = 17
369
+ REQ_FA = 18
370
+ REPLACE_FA = 19
371
+ REQ_HISTORICAL_DATA = 20
372
+ EXERCISE_OPTIONS = 21
373
+ REQ_SCANNER_SUBSCRIPTION = 22
374
+ CANCEL_SCANNER_SUBSCRIPTION = 23
375
+ REQ_SCANNER_PARAMETERS = 24
376
+ CANCEL_HISTORICAL_DATA = 25
377
+ REQ_CURRENT_TIME = 49
378
+ REQ_REAL_TIME_BARS = 50
379
+ CANCEL_REAL_TIME_BARS = 51
380
+ REQ_FUNDAMENTAL_DATA = 52
381
+ CANCEL_FUNDAMENTAL_DATA = 53
382
+ REQ_CALC_IMPLIED_VOLAT = 54
383
+ REQ_CALC_OPTION_PRICE = 55
384
+ CANCEL_CALC_IMPLIED_VOLAT = 56
385
+ CANCEL_CALC_OPTION_PRICE = 57
386
+ REQ_GLOBAL_CANCEL = 58
387
+ REQ_MARKET_DATA_TYPE = 59 --> supported by ib-ruby 0.94
388
+
389
+ REQ_POSITIONS = 61 supported now
390
+ REQ_ACCOUNT_SUMMARY = 62 supported now
391
+
392
+ CANCEL_ACCOUNT_SUMMARY = 63 supported now
393
+
394
+ CANCEL_POSITIONS = 64 supported now
395
+ VERIFY_REQUEST = 65
396
+ VERIFY_MESSAGE = 66
397
+ QUERY_DISPLAY_GROUPS = 67
398
+ SUBSCRIBE_TO_GROUP_EVENTS = 68
399
+ UPDATE_DISPLAY_GROUP = 69
400
+ UNSUBSCRIBE_FROM_GROUP_EVENTS = 70
401
+ START_API = 71
402
+ VERIFY_AND_AUTH_REQUEST = 72
403
+ VERIFY_AND_AUTH_MESSAGE = 73
404
+ REQ_POSITIONS_MULTI = 74 supported now
405
+ CANCEL_POSITIONS_MULTI = 75 supported now
406
+
407
+ REQ_ACCOUNT_UPDATES_MULTI = 76 supported now
408
+
409
+ CANCEL_ACCOUNT_UPDATES_MULTI = 77 supported now
410
+
411
+ REQ_SEC_DEF_OPT_PARAMS = 78 supported now
412
+ REQ_SOFT_DOLLAR_TIERS = 79
413
+ REQ_FAMILY_CODES = 80
414
+ REQ_MATCHING_SYMBOLS = 81
415
+ REQ_MKT_DEPTH_EXCHANGES = 82
416
+ REQ_SMART_COMPONENTS = 83
417
+ REQ_NEWS_ARTICLE = 84 in preparation
418
+ REQ_NEWS_PROVIDERS = 85 in preparatino
419
+ REQ_HISTORICAL_NEWS = 86 in preparation
420
+
421
+ REQ_HEAD_TIMESTAMP = 87 supported now
422
+
423
+ REQ_HISTOGRAM_DATA = 88 supported now
424
+
425
+ CANCEL_HISTOGRAM_DATA = 89 supported now
426
+
427
+ CANCEL_HEAD_TIMESTAMP = 90 supported now
428
+
429
+ REQ_MARKET_RULE = 91
430
+ REQ_PNL = 92
431
+ CANCEL_PNL = 93
432
+ REQ_PNL_SINGLE = 94
433
+ CANCEL_PNL_SINGLE = 95
434
+ REQ_HISTORICAL_TICKS = 96
435
+ REQ_TICK_BY_TICK_DATA = 97
436
+ CANCEL_TICK_BY_TICK_DATA = 98
437
+