ib-ruby 0.5.19 → 0.5.21
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.
- data/HISTORY +4 -0
- data/TODO +0 -3
- data/VERSION +1 -1
- data/bin/contract_details +3 -3
- data/bin/depth_of_market +1 -1
- data/bin/historic_data +5 -8
- data/bin/market_data +2 -2
- data/bin/option_data +2 -2
- data/lib/ib-ruby/connection.rb +1 -9
- data/lib/ib-ruby/extensions.rb +8 -0
- data/lib/ib-ruby/messages/abstract_message.rb +89 -0
- data/lib/ib-ruby/messages/incoming.rb +415 -487
- data/lib/ib-ruby/messages/outgoing.rb +241 -305
- data/lib/ib-ruby/models/bar.rb +3 -3
- data/lib/ib-ruby/models/contract/bag.rb +1 -5
- data/lib/ib-ruby/models/contract.rb +50 -33
- data/lib/ib-ruby/models/execution.rb +6 -3
- data/lib/ib-ruby/models/order.rb +7 -5
- data/lib/ib-ruby/socket.rb +13 -0
- data/lib/ib-ruby/symbols/forex.rb +7 -14
- data/lib/ib-ruby/symbols/futures.rb +16 -20
- data/lib/ib-ruby/symbols/options.rb +6 -4
- data/lib/ib-ruby/symbols/stocks.rb +1 -1
- data/lib/ib-ruby.rb +1 -0
- data/spec/README.md +34 -0
- data/spec/ib-ruby/connection_spec.rb +4 -4
- data/spec/ib-ruby/messages/incoming_spec.rb +50 -0
- data/spec/ib-ruby/messages/outgoing_spec.rb +32 -0
- data/spec/ib-ruby/models/contract_spec.rb +27 -25
- data/spec/ib-ruby/models/order_spec.rb +56 -23
- data/spec/integration/account_info_spec.rb +85 -0
- data/spec/integration/contract_info_spec.rb +209 -0
- data/spec/integration/depth_data_spec.rb +46 -0
- data/spec/integration/historic_data_spec.rb +82 -0
- data/spec/integration/market_data_spec.rb +97 -0
- data/spec/integration/option_data_spec.rb +96 -0
- data/spec/integration/orders/execution_spec.rb +135 -0
- data/spec/{ib-ruby/messages → integration/orders}/open_order +9 -205
- data/spec/integration/orders/placement_spec.rb +150 -0
- data/spec/integration/orders/valid_ids_spec.rb +84 -0
- data/spec/integration_helper.rb +110 -0
- data/spec/message_helper.rb +13 -18
- data/spec/spec_helper.rb +35 -26
- metadata +33 -17
- data/spec/ib-ruby/messages/README.md +0 -16
- data/spec/ib-ruby/messages/account_info_spec.rb +0 -84
- data/spec/ib-ruby/messages/just_connect_spec.rb +0 -33
- data/spec/ib-ruby/messages/market_data_spec.rb +0 -92
- data/spec/ib-ruby/messages/orders_spec.rb +0 -219
- data/spec/ib-ruby_spec.rb +0 -0
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'ib-ruby/messages/abstract_message'
|
2
|
+
|
1
3
|
# EClientSocket.java uses sendMax() rather than send() for a number of these.
|
2
4
|
# It sends an EOL rather than a number if the value == Integer.MAX_VALUE (or Double.MAX_VALUE).
|
3
5
|
# These fields are initialized to this MAX_VALUE.
|
@@ -11,82 +13,64 @@ module IB
|
|
11
13
|
|
12
14
|
# Incoming IB messages
|
13
15
|
module Incoming
|
16
|
+
extend Messages # def_message macros
|
17
|
+
|
14
18
|
Classes = Array.new
|
15
19
|
|
16
|
-
|
17
|
-
#
|
18
|
-
# Class variables:
|
19
|
-
# @message_id - int: message id.
|
20
|
-
# @version - int: current version of message format.
|
21
|
-
#
|
22
|
-
# Instance attributes (at least):
|
23
|
-
# @data - Hash of actual data read from a stream.
|
24
|
-
#
|
25
|
-
# Override the load(socket) method in your subclass to do actual reading into @data.
|
26
|
-
class AbstractMessage
|
27
|
-
attr_accessor :created_at, :data
|
20
|
+
class AbstractMessage < IB::Messages::AbstractMessage
|
28
21
|
|
29
22
|
def self.inherited(by)
|
30
23
|
super(by)
|
31
24
|
Classes.push(by)
|
32
25
|
end
|
33
26
|
|
34
|
-
def
|
35
|
-
@
|
27
|
+
def version # Per message, received messages may have the different versions
|
28
|
+
@data[:version]
|
36
29
|
end
|
37
30
|
|
38
|
-
|
39
|
-
|
31
|
+
# Read incoming message from given socket or instantiate with given data
|
32
|
+
def initialize socket_or_data
|
40
33
|
@created_at = Time.now
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
self.load()
|
45
|
-
|
46
|
-
@socket = nil
|
47
|
-
end
|
48
|
-
|
49
|
-
def to_human
|
50
|
-
self.inspect
|
51
|
-
end
|
52
|
-
|
53
|
-
# Object#id is always defined, we cannot rely on method_missing
|
54
|
-
def id
|
55
|
-
@data.has_key?(:id) ? @data[:id] : super
|
56
|
-
end
|
57
|
-
|
58
|
-
def respond_to? method
|
59
|
-
getter = method.to_s.sub(/=$/, '').to_sym
|
60
|
-
@data.has_key?(method) || @data.has_key?(getter) || super
|
61
|
-
end
|
62
|
-
|
63
|
-
protected
|
64
|
-
|
65
|
-
# TODO: method compilation instead of method_missing
|
66
|
-
def method_missing method, *args
|
67
|
-
getter = method.to_s.sub(/=$/, '').to_sym
|
68
|
-
if @data.has_key? method
|
69
|
-
@data[method]
|
70
|
-
elsif @data.has_key? getter
|
71
|
-
@data[getter] = *args
|
34
|
+
if socket_or_data.is_a?(Hash)
|
35
|
+
@data = socket_or_data
|
72
36
|
else
|
73
|
-
|
37
|
+
@data = {}
|
38
|
+
@socket = socket_or_data
|
39
|
+
self.load
|
40
|
+
@socket = nil
|
74
41
|
end
|
75
42
|
end
|
76
43
|
|
77
44
|
# Every message loads received message version first
|
78
45
|
def load
|
79
46
|
@data[:version] = @socket.read_int
|
47
|
+
|
48
|
+
if @data[:version] != self.class.version
|
49
|
+
raise "Unsupported version #{@data[:version]} of #{self.class} received"
|
50
|
+
end
|
51
|
+
|
52
|
+
load_map *self.class.data_map
|
80
53
|
end
|
81
54
|
|
82
55
|
# Load @data from the socket according to the given map.
|
83
56
|
#
|
84
|
-
# map is a series of Arrays in the format
|
57
|
+
# map is a series of Arrays in the format of
|
58
|
+
# [ [ :name, :type ],
|
59
|
+
# [ :group, :name, :type] ]
|
85
60
|
# type identifiers must have a corresponding read_type method on socket (read_int, etc.).
|
86
|
-
#
|
87
|
-
#
|
61
|
+
# group is used to lump together aggregates, such as Contract or Order fields
|
88
62
|
def load_map(*map)
|
89
|
-
map.each
|
63
|
+
map.each do |(m1, m2, m3)|
|
64
|
+
group, name, type = m3 ? [m1, m2, m3] : [nil, m1, m2]
|
65
|
+
|
66
|
+
data = @socket.__send__("read_#{type}")
|
67
|
+
if group
|
68
|
+
@data[group] ||= {}
|
69
|
+
@data[group][name] = data
|
70
|
+
else
|
71
|
+
@data[name] = data
|
72
|
+
end
|
73
|
+
end
|
90
74
|
end
|
91
75
|
end # class AbstractMessage
|
92
76
|
|
@@ -97,28 +81,13 @@ module IB
|
|
97
81
|
end
|
98
82
|
|
99
83
|
def to_human
|
100
|
-
"<#{self.
|
84
|
+
"<#{self.message_type} #{type}:" +
|
101
85
|
@data.map do |key, value|
|
102
|
-
" #{key} #{value}" unless [:version, :
|
86
|
+
" #{key} #{value}" unless [:version, :ticker_id, :tick_type].include?(key)
|
103
87
|
end.compact.join(',') + " >"
|
104
88
|
end
|
105
89
|
end
|
106
90
|
|
107
|
-
# Macro that defines short message classes using a one-liner
|
108
|
-
def self.def_message message_id, *keys, &to_human
|
109
|
-
base = keys.first.is_a?(Class) ? keys.shift : AbstractMessage
|
110
|
-
Class.new(base) do
|
111
|
-
@message_id = message_id
|
112
|
-
|
113
|
-
define_method(:load) do
|
114
|
-
super()
|
115
|
-
load_map *keys
|
116
|
-
end
|
117
|
-
|
118
|
-
define_method(:to_human, &to_human) if to_human
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
91
|
### Actual message classes (short definitions):
|
123
92
|
#:status - String: Displays the order status. Possible values include:
|
124
93
|
# � PendingSubmit - indicates that you have transmitted the order, but
|
@@ -147,7 +116,7 @@ module IB
|
|
147
116
|
# the order is inactive due to system, exchange or other issues.
|
148
117
|
# :why_held - This field is used to identify an order held when TWS is trying to
|
149
118
|
# locate shares for a short sell. The value used to indicate this is 'locate'.
|
150
|
-
OrderStatus = def_message 3, [:
|
119
|
+
OrderStatus = def_message [3, 6], [:order_id, :int],
|
151
120
|
[:status, :string],
|
152
121
|
[:filled, :int],
|
153
122
|
[:remaining, :int],
|
@@ -161,28 +130,26 @@ module IB
|
|
161
130
|
" @ last/avg: #{last_fill_price}/#{average_fill_price}" +
|
162
131
|
(parent_id > 0 ? "parent_id: #{parent_id}" : "") +
|
163
132
|
(why_held != "" ? "why_held: #{why_held}" : "") +
|
164
|
-
" id/perm: #{
|
133
|
+
" id/perm: #{order_id}/#{perm_id}>"
|
165
134
|
end
|
166
135
|
|
167
136
|
|
168
|
-
AccountValue = def_message(6, [:key, :string],
|
137
|
+
AccountValue = def_message([6, 2], [:key, :string],
|
169
138
|
[:value, :string],
|
170
139
|
[:currency, :string],
|
171
140
|
[:account_name, :string]) do
|
172
141
|
"<AccountValue: #{account_name}, #{key}=#{value} #{currency}>"
|
173
142
|
end
|
174
143
|
|
175
|
-
AccountUpdateTime = def_message
|
176
|
-
"<AccountUpdateTime: #{time_stamp}>"
|
177
|
-
end
|
144
|
+
AccountUpdateTime = def_message 8, [:time_stamp, :string]
|
178
145
|
|
179
146
|
# This message is always sent by TWS automatically at connect.
|
180
147
|
# The IB::Connection class subscribes to it automatically and stores
|
181
148
|
# the order id in its @next_order_id attribute.
|
182
|
-
NextValidID = def_message
|
149
|
+
NextValidID = def_message 9, [:order_id, :int]
|
183
150
|
|
184
151
|
NewsBulletins =
|
185
|
-
def_message 14, [:
|
152
|
+
def_message 14, [:request_id, :int], # unique incrementing bulletin ID.
|
186
153
|
[:type, :int], # Type of bulletin. Valid values include:
|
187
154
|
# 1 = Regular news bulletin
|
188
155
|
# 2 = Exchange no longer available for trading
|
@@ -200,8 +167,7 @@ module IB
|
|
200
167
|
# 1 = GROUPS
|
201
168
|
# 2 = PROFILE
|
202
169
|
# 3 = ACCOUNT ALIASES
|
203
|
-
[:xml, :string] # XML string
|
204
|
-
# FA configuration information.
|
170
|
+
[:xml, :string] # XML string with requested FA configuration information.
|
205
171
|
|
206
172
|
# Receives an XML document that describes the valid parameters that a scanner
|
207
173
|
# subscription can have (for outgoing RequestScannerSubscription message).
|
@@ -212,21 +178,18 @@ module IB
|
|
212
178
|
|
213
179
|
# Receive Reuters global fundamental market data. There must be a subscription to
|
214
180
|
# Reuters Fundamental set up in Account Management before you can receive this data.
|
215
|
-
FundamentalData = def_message 50, [:
|
181
|
+
FundamentalData = def_message 50, [:request_id, :int], # request_id
|
216
182
|
[:data, :string]
|
217
183
|
|
218
|
-
ContractDataEnd = def_message
|
219
|
-
|
220
|
-
OpenOrderEnd = def_message(53) { "<OpenOrderEnd>" }
|
184
|
+
ContractDataEnd = def_message 52, [:request_id, :int] # request_id
|
221
185
|
|
222
|
-
|
223
|
-
"<AccountDownloadEnd: #{account_name}}>"
|
224
|
-
end # request_id
|
186
|
+
OpenOrderEnd = def_message 53
|
225
187
|
|
188
|
+
AccountDownloadEnd = def_message 54, [:account_name, :string]
|
226
189
|
|
227
|
-
ExecutionDataEnd = def_message
|
190
|
+
ExecutionDataEnd = def_message 55, [:request_id, :int] # request_id
|
228
191
|
|
229
|
-
TickSnapshotEnd = def_message
|
192
|
+
TickSnapshotEnd = def_message 57, [:ticker_id, :int]
|
230
193
|
|
231
194
|
### Actual message classes (long definitions):
|
232
195
|
|
@@ -271,30 +234,30 @@ module IB
|
|
271
234
|
# IB then emits at most 2 events on eWrapper:
|
272
235
|
# tickPrice( tickerId, tickType, price, canAutoExecute)
|
273
236
|
# tickSize( tickerId, sizeTickType, size)
|
274
|
-
TickPrice = def_message 1, AbstractTick,
|
275
|
-
[:
|
237
|
+
TickPrice = def_message [1, 6], AbstractTick,
|
238
|
+
[:ticker_id, :int],
|
276
239
|
[:tick_type, :int],
|
277
240
|
[:price, :decimal],
|
278
241
|
[:size, :int],
|
279
242
|
[:can_auto_execute, :int]
|
280
243
|
|
281
|
-
TickSize = def_message 2, AbstractTick,
|
282
|
-
[:
|
244
|
+
TickSize = def_message [2, 6], AbstractTick,
|
245
|
+
[:ticker_id, :int],
|
283
246
|
[:tick_type, :int],
|
284
247
|
[:size, :int]
|
285
248
|
|
286
249
|
TickGeneric = def_message 45, AbstractTick,
|
287
|
-
[:
|
250
|
+
[:ticker_id, :int],
|
288
251
|
[:tick_type, :int],
|
289
252
|
[:value, :decimal]
|
290
253
|
|
291
|
-
TickString = def_message 46, AbstractTick,
|
292
|
-
[:
|
254
|
+
TickString = def_message [46, 6], AbstractTick,
|
255
|
+
[:ticker_id, :int],
|
293
256
|
[:tick_type, :int],
|
294
257
|
[:value, :string]
|
295
258
|
|
296
259
|
TickEFP = def_message 47, AbstractTick,
|
297
|
-
[:
|
260
|
+
[:ticker_id, :int],
|
298
261
|
[:tick_type, :int],
|
299
262
|
[:basis_points, :decimal],
|
300
263
|
[:formatted_basis_points, :string],
|
@@ -307,7 +270,7 @@ module IB
|
|
307
270
|
# TWS�s option model volatilities, prices, and deltas, along with the present
|
308
271
|
# value of dividends expected on that options underlier are received.
|
309
272
|
# TickOption message contains following @data:
|
310
|
-
# :
|
273
|
+
# :ticker_id - Id that was specified previously in the call to reqMktData()
|
311
274
|
# :tick_type - Specifies the type of option computation (see TICK_TYPES).
|
312
275
|
# :implied_volatility - The implied volatility calculated by the TWS option
|
313
276
|
# modeler, using the specified :tick_type value.
|
@@ -318,42 +281,27 @@ module IB
|
|
318
281
|
# :vega - The option vega value.
|
319
282
|
# :theta - The option theta value.
|
320
283
|
# :under_price - The price of the underlying.
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
read_computed :option_price, -1 # -1 is the "not yet computed" indicator
|
340
|
-
read_computed :pv_dividend, -1 # -1 is the "not yet computed" indicator
|
341
|
-
read_computed :gamma, -2 # -2 is the "not yet computed" indicator
|
342
|
-
read_computed :vega, -2 # -2 is the "not yet computed" indicator
|
343
|
-
read_computed :theta, -2 # -2 is the "not yet computed" indicator
|
344
|
-
read_computed :under_price, -1 # -1 is the "not yet computed" indicator
|
345
|
-
end
|
346
|
-
|
347
|
-
def to_human
|
348
|
-
"<TickOption #{type} for #{:id}: underlying @ #{under_price}, "+
|
349
|
-
"option @ #{option_price}, IV #{implied_volatility}%, delta #{delta}, " +
|
350
|
-
"gamma #{gamma}, vega #{vega}, theta #{theta}, pv_dividend #{pv_dividend}>"
|
351
|
-
end
|
352
|
-
end # TickOption
|
353
|
-
TickOptionComputation = TickOption
|
284
|
+
TickOptionComputation = TickOption =
|
285
|
+
def_message([21, 6], AbstractTick,
|
286
|
+
[:ticker_id, :int],
|
287
|
+
[:tick_type, :int],
|
288
|
+
# What is the "not yet computed" indicator:
|
289
|
+
[:implied_volatility, :decimal_limit_1], # -1 and below
|
290
|
+
[:delta, :decimal_limit_2], # -2 and below
|
291
|
+
[:option_price, :decimal_limit_1], # -1 -"-
|
292
|
+
[:pv_dividend, :decimal_limit_1], # -1 -"-
|
293
|
+
[:gamma, :decimal_limit_2], # -2 -"-
|
294
|
+
[:vega, :decimal_limit_2], # -2 -"-
|
295
|
+
[:theta, :decimal_limit_2], # -2 -"-
|
296
|
+
[:under_price, :decimal_limit_1]) do
|
297
|
+
|
298
|
+
"<TickOption #{type} for #{:ticker_id}: underlying @ #{under_price}, "+
|
299
|
+
"option @ #{option_price}, IV #{implied_volatility}%, delta #{delta}, " +
|
300
|
+
"gamma #{gamma}, vega #{vega}, theta #{theta}, pv_dividend #{pv_dividend}>"
|
301
|
+
end
|
354
302
|
|
355
303
|
MarketDepth =
|
356
|
-
def_message 12, [:
|
304
|
+
def_message 12, [:request_id, :int],
|
357
305
|
[:position, :int], # The row Id of this market depth entry.
|
358
306
|
[:operation, :int], # How it should be applied to the market depth:
|
359
307
|
# 0 = insert this new order into the row identified by :position
|
@@ -363,7 +311,6 @@ module IB
|
|
363
311
|
[:price, :decimal],
|
364
312
|
[:size, :int]
|
365
313
|
class MarketDepth
|
366
|
-
|
367
314
|
def side
|
368
315
|
@data[:side] == 0 ? :ask : :bid
|
369
316
|
end
|
@@ -373,28 +320,27 @@ module IB
|
|
373
320
|
end
|
374
321
|
|
375
322
|
def to_human
|
376
|
-
"<#{self.
|
323
|
+
"<#{self.message_type}: #{operation} #{side} @ "+
|
377
324
|
"#{position} = #{price} x #{size}>"
|
378
325
|
end
|
379
326
|
end
|
380
327
|
|
381
328
|
MarketDepthL2 =
|
382
|
-
def_message 13, MarketDepth,
|
383
|
-
[:
|
384
|
-
[:position, :int],
|
329
|
+
def_message 13, MarketDepth, # Fields descriptions - see above
|
330
|
+
[:request_id, :int],
|
331
|
+
[:position, :int],
|
385
332
|
[:market_maker, :string], # The exchange hosting this order.
|
386
|
-
[:operation, :int],
|
387
|
-
|
388
|
-
# 1 = update the existing order in the row identified by :position
|
389
|
-
# 2 = delete the existing order at the row identified by :position
|
390
|
-
[:side, :int], # side of the book: 0 = ask, 1 = bid
|
333
|
+
[:operation, :int],
|
334
|
+
[:side, :int],
|
391
335
|
[:price, :decimal],
|
392
336
|
[:size, :int]
|
393
337
|
|
394
338
|
# Called Error in Java code, but in fact this type of messages also
|
395
339
|
# deliver system alerts and additional (non-error) info from TWS.
|
396
|
-
|
397
|
-
|
340
|
+
ErrorMessage = Error = Alert = def_message([4, 2],
|
341
|
+
[:error_id, :int],
|
342
|
+
[:code, :int],
|
343
|
+
[:message, :string])
|
398
344
|
class Alert
|
399
345
|
# Is it an Error message?
|
400
346
|
def error?
|
@@ -412,347 +358,202 @@ module IB
|
|
412
358
|
end
|
413
359
|
|
414
360
|
def to_human
|
415
|
-
"TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'
|
416
|
-
} Message #{code}: #{message}"
|
361
|
+
"TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'} #{code}: #{message}"
|
417
362
|
end
|
418
363
|
end # class Alert
|
419
|
-
Error = Alert
|
420
|
-
ErrorMessage = Alert
|
421
|
-
|
422
|
-
class OpenOrder < AbstractMessage
|
423
|
-
@message_id = 5
|
424
|
-
|
425
|
-
# TODO: Add id accessor to unify with OrderStatus message
|
426
|
-
attr_accessor :order, :contract
|
427
|
-
|
428
|
-
def load
|
429
|
-
super
|
430
|
-
|
431
|
-
@order = Models::Order.new :id => @socket.read_int
|
432
|
-
|
433
|
-
@contract = Models::Contract.build :con_id => @socket.read_string,
|
434
|
-
:symbol => @socket.read_string,
|
435
|
-
:sec_type => @socket.read_string,
|
436
|
-
:expiry => @socket.read_string,
|
437
|
-
:strike => @socket.read_decimal,
|
438
|
-
:right => @socket.read_string,
|
439
|
-
:exchange => @socket.read_string,
|
440
|
-
:currency => @socket.read_string,
|
441
|
-
:local_symbol => @socket.read_string
|
442
|
-
|
443
|
-
@order.action = @socket.read_string
|
444
|
-
@order.total_quantity = @socket.read_int
|
445
|
-
@order.order_type = @socket.read_string
|
446
|
-
@order.limit_price = @socket.read_decimal
|
447
|
-
@order.aux_price = @socket.read_decimal
|
448
|
-
@order.tif = @socket.read_string
|
449
|
-
@order.oca_group = @socket.read_string
|
450
|
-
@order.account = @socket.read_string
|
451
|
-
@order.open_close = @socket.read_string
|
452
|
-
@order.origin = @socket.read_int
|
453
|
-
@order.order_ref = @socket.read_string
|
454
|
-
@order.client_id = @socket.read_int
|
455
|
-
@order.perm_id = @socket.read_int
|
456
|
-
@order.outside_rth = (@socket.read_int == 1)
|
457
|
-
@order.hidden = (@socket.read_int == 1)
|
458
|
-
@order.discretionary_amount = @socket.read_decimal
|
459
|
-
@order.good_after_time = @socket.read_string
|
460
|
-
@socket.read_string # skip deprecated sharesAllocation field
|
461
|
-
|
462
|
-
@order.fa_group = @socket.read_string
|
463
|
-
@order.fa_method = @socket.read_string
|
464
|
-
@order.fa_percentage = @socket.read_string
|
465
|
-
@order.fa_profile = @socket.read_string
|
466
|
-
@order.good_till_date = @socket.read_string
|
467
|
-
@order.rule_80a = @socket.read_string
|
468
|
-
@order.percent_offset = @socket.read_decimal
|
469
|
-
@order.settling_firm = @socket.read_string
|
470
|
-
@order.short_sale_slot = @socket.read_int
|
471
|
-
@order.designated_location = @socket.read_string
|
472
|
-
@order.exempt_code = @socket.read_int # skipped in ver 51?
|
473
|
-
@order.auction_strategy = @socket.read_int
|
474
|
-
@order.starting_price = @socket.read_decimal
|
475
|
-
@order.stock_ref_price = @socket.read_decimal
|
476
|
-
@order.delta = @socket.read_decimal
|
477
|
-
@order.stock_range_lower = @socket.read_decimal
|
478
|
-
@order.stock_range_upper = @socket.read_decimal
|
479
|
-
@order.display_size = @socket.read_int
|
480
|
-
#@order.rth_only = @socket.read_boolean
|
481
|
-
@order.block_order = @socket.read_boolean
|
482
|
-
@order.sweep_to_fill = @socket.read_boolean
|
483
|
-
@order.all_or_none = @socket.read_boolean
|
484
|
-
@order.min_quantity = @socket.read_int
|
485
|
-
@order.oca_type = @socket.read_int
|
486
|
-
@order.etrade_only = @socket.read_boolean
|
487
|
-
@order.firm_quote_only = @socket.read_boolean
|
488
|
-
@order.nbbo_price_cap = @socket.read_decimal
|
489
|
-
@order.parent_id = @socket.read_int
|
490
|
-
@order.trigger_method = @socket.read_int
|
491
|
-
@order.volatility = @socket.read_decimal
|
492
|
-
@order.volatility_type = @socket.read_int
|
493
|
-
@order.delta_neutral_order_type = @socket.read_string
|
494
|
-
@order.delta_neutral_aux_price = @socket.read_decimal
|
495
|
-
|
496
|
-
@order.continuous_update = @socket.read_int
|
497
|
-
@order.reference_price_type = @socket.read_int
|
498
|
-
@order.trail_stop_price = @socket.read_decimal
|
499
|
-
@order.basis_points = @socket.read_decimal
|
500
|
-
@order.basis_points_type = @socket.read_int
|
501
|
-
@contract.legs_description = @socket.read_string
|
502
|
-
@order.scale_init_level_size = @socket.read_int_max
|
503
|
-
@order.scale_subs_level_size = @socket.read_int_max
|
504
|
-
@order.scale_price_increment = @socket.read_decimal_max
|
505
|
-
@order.clearing_account = @socket.read_string
|
506
|
-
@order.clearing_intent = @socket.read_string
|
507
|
-
@order.not_held = (@socket.read_int == 1)
|
508
|
-
|
509
|
-
under_comp_present = (@socket.read_int == 1)
|
510
|
-
|
511
|
-
if under_comp_present
|
512
|
-
@contract.under_comp = true
|
513
|
-
@contract.under_con_id = @socket.read_int
|
514
|
-
@contract.under_delta = @socket.read_decimal
|
515
|
-
@contract.under_price = @socket.read_decimal
|
516
|
-
end
|
517
|
-
|
518
|
-
@order.algo_strategy = @socket.read_string
|
519
|
-
|
520
|
-
unless @order.algo_strategy.nil? || @order.algo_strategy.empty?
|
521
|
-
algo_params_count = @socket.read_int
|
522
|
-
if algo_params_count > 0
|
523
|
-
@order.algo_params = Hash.new
|
524
|
-
algo_params_count.times do
|
525
|
-
tag = @socket.read_string
|
526
|
-
value = @socket.read_string
|
527
|
-
@order.algo_params[tag] = value
|
528
|
-
end
|
529
|
-
end
|
530
|
-
end
|
531
|
-
|
532
|
-
@order.what_if = (@socket.read_int == 1)
|
533
|
-
@order.status = @socket.read_string
|
534
|
-
@order.init_margin = @socket.read_string
|
535
|
-
@order.maint_margin = @socket.read_string
|
536
|
-
@order.equity_with_loan = @socket.read_string
|
537
|
-
@order.commission = @socket.read_decimal_max # May be nil!
|
538
|
-
@order.min_commission = @socket.read_decimal_max # May be nil!
|
539
|
-
@order.max_commission = @socket.read_decimal_max # May be nil!
|
540
|
-
@order.commission_currency = @socket.read_string
|
541
|
-
@order.warning_text = @socket.read_string
|
542
|
-
end
|
543
|
-
|
544
|
-
def to_human
|
545
|
-
"<OpenOrder: #{@contract.to_human} #{@order.to_human}>"
|
546
|
-
end
|
547
|
-
end # OpenOrder
|
548
|
-
|
549
|
-
class PortfolioValue < AbstractMessage
|
550
|
-
@message_id = 7
|
551
364
|
|
552
|
-
|
365
|
+
PortfolioValue = def_message [7, 7],
|
366
|
+
[:contract, :con_id, :int],
|
367
|
+
[:contract, :symbol, :string],
|
368
|
+
[:contract, :sec_type, :string],
|
369
|
+
[:contract, :expiry, :string],
|
370
|
+
[:contract, :strike, :decimal],
|
371
|
+
[:contract, :right, :string],
|
372
|
+
[:contract, :multiplier, :string],
|
373
|
+
[:contract, :primary_exchange, :string],
|
374
|
+
[:contract, :currency, :string],
|
375
|
+
[:contract, :local_symbol, :string],
|
376
|
+
[:position, :int],
|
377
|
+
[:market_price, :decimal],
|
378
|
+
[:market_value, :decimal],
|
379
|
+
[:average_cost, :decimal],
|
380
|
+
[:unrealized_pnl, :decimal_max], # May be nil!
|
381
|
+
[:realized_pnl, :decimal_max], # May be nil!
|
382
|
+
[:account_name, :string]
|
383
|
+
class PortfolioValue
|
553
384
|
|
554
385
|
def load
|
555
386
|
super
|
556
|
-
|
557
|
-
@contract = Models::Contract.build :con_id => @socket.read_int,
|
558
|
-
:symbol => @socket.read_string,
|
559
|
-
:sec_type => @socket.read_string,
|
560
|
-
:expiry => @socket.read_string,
|
561
|
-
:strike => @socket.read_decimal,
|
562
|
-
:right => @socket.read_string,
|
563
|
-
:multiplier => @socket.read_string,
|
564
|
-
:primary_exchange => @socket.read_string,
|
565
|
-
:currency => @socket.read_string,
|
566
|
-
:local_symbol => @socket.read_string
|
567
|
-
load_map [:position, :int],
|
568
|
-
[:market_price, :decimal],
|
569
|
-
[:market_value, :decimal],
|
570
|
-
[:average_cost, :decimal],
|
571
|
-
[:unrealized_pnl, :decimal_max], # May be nil!
|
572
|
-
[:realized_pnl, :decimal_max], # May be nil!
|
573
|
-
[:account_name, :string]
|
387
|
+
@contract = Models::Contract.build @data[:contract]
|
574
388
|
end
|
575
389
|
|
576
390
|
def to_human
|
577
|
-
"<PortfolioValue: #{
|
391
|
+
"<PortfolioValue: #{contract.to_human} (#{position}): Market #{market_price}" +
|
578
392
|
" price #{market_value} value; PnL: #{unrealized_pnl} unrealized," +
|
579
393
|
" #{realized_pnl} realized; account #{account_name}>"
|
580
394
|
end
|
581
|
-
|
582
395
|
end # PortfolioValue
|
583
396
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
397
|
+
ContractDetails = ContractData =
|
398
|
+
def_message([10, 6],
|
399
|
+
[:request_id, :int], # request id
|
400
|
+
[:contract, :symbol, :string],
|
401
|
+
[:contract, :sec_type, :string],
|
402
|
+
[:contract, :expiry, :string],
|
403
|
+
[:contract, :strike, :decimal],
|
404
|
+
[:contract, :right, :string],
|
405
|
+
[:contract, :exchange, :string],
|
406
|
+
[:contract, :currency, :string],
|
407
|
+
[:contract, :local_symbol, :string],
|
408
|
+
|
409
|
+
[:contract, :market_name, :string], # extended
|
410
|
+
[:contract, :trading_class, :string],
|
411
|
+
[:contract, :con_id, :int],
|
412
|
+
[:contract, :min_tick, :decimal],
|
413
|
+
[:contract, :multiplier, :string],
|
414
|
+
[:contract, :order_types, :string],
|
415
|
+
[:contract, :valid_exchanges, :string],
|
416
|
+
[:contract, :price_magnifier, :int],
|
417
|
+
[:contract, :under_con_id, :int],
|
418
|
+
[:contract, :long_name, :string],
|
419
|
+
[:contract, :primary_exchange, :string],
|
420
|
+
[:contract, :contract_month, :string],
|
421
|
+
[:contract, :industry, :string],
|
422
|
+
[:contract, :category, :string],
|
423
|
+
[:contract, :subcategory, :string],
|
424
|
+
[:contract, :time_zone, :string],
|
425
|
+
[:contract, :trading_hours, :string],
|
426
|
+
[:contract, :liquid_hours, :string])
|
427
|
+
|
428
|
+
class ContractData
|
589
429
|
def load
|
590
430
|
super
|
591
|
-
|
592
|
-
|
593
|
-
@contract =
|
594
|
-
Models::Contract.build :symbol => @socket.read_string,
|
595
|
-
:sec_type => @socket.read_string,
|
596
|
-
:expiry => @socket.read_string,
|
597
|
-
:strike => @socket.read_decimal,
|
598
|
-
:right => @socket.read_string,
|
599
|
-
:exchange => @socket.read_string,
|
600
|
-
:currency => @socket.read_string,
|
601
|
-
:local_symbol => @socket.read_string,
|
602
|
-
|
603
|
-
:market_name => @socket.read_string,
|
604
|
-
:trading_class => @socket.read_string,
|
605
|
-
:con_id => @socket.read_int,
|
606
|
-
:min_tick => @socket.read_decimal,
|
607
|
-
:multiplier => @socket.read_string,
|
608
|
-
:order_types => @socket.read_string,
|
609
|
-
:valid_exchanges => @socket.read_string,
|
610
|
-
:price_magnifier => @socket.read_int,
|
611
|
-
|
612
|
-
:under_con_id => @socket.read_int,
|
613
|
-
:long_name => @socket.read_string,
|
614
|
-
:primary_exchange => @socket.read_string,
|
615
|
-
:contract_month => @socket.read_string,
|
616
|
-
:industry => @socket.read_string,
|
617
|
-
:category => @socket.read_string,
|
618
|
-
:subcategory => @socket.read_string,
|
619
|
-
:time_zone => @socket.read_string,
|
620
|
-
:trading_hours => @socket.read_string,
|
621
|
-
:liquid_hours => @socket.read_string
|
431
|
+
@contract = Models::Contract.build @data[:contract]
|
622
432
|
end
|
623
433
|
end # ContractData
|
624
|
-
ContractDetails = ContractData
|
625
|
-
|
626
|
-
class ExecutionData < AbstractMessage
|
627
|
-
@message_id = 11
|
628
|
-
|
629
|
-
attr_accessor :contract, :execution
|
630
434
|
|
435
|
+
ExecutionData =
|
436
|
+
def_message [11, 7],
|
437
|
+
# The reqID that was specified previously in the call to reqExecution()
|
438
|
+
[:request_id, :int],
|
439
|
+
[:execution, :order_id, :int],
|
440
|
+
[:contract, :con_id, :int],
|
441
|
+
[:contract, :symbol, :string],
|
442
|
+
[:contract, :sec_type, :string],
|
443
|
+
[:contract, :expiry, :string],
|
444
|
+
[:contract, :strike, :decimal],
|
445
|
+
[:contract, :right, :string],
|
446
|
+
[:contract, :exchange, :string],
|
447
|
+
[:contract, :currency, :string],
|
448
|
+
[:contract, :local_symbol, :string],
|
449
|
+
|
450
|
+
[:execution, :exec_id, :string], # Weird format
|
451
|
+
[:execution, :time, :string],
|
452
|
+
[:execution, :account_name, :string],
|
453
|
+
[:execution, :exchange, :string],
|
454
|
+
[:execution, :side, :string],
|
455
|
+
[:execution, :shares, :int],
|
456
|
+
[:execution, :price, :decimal],
|
457
|
+
[:execution, :perm_id, :int],
|
458
|
+
[:execution, :client_id, :int],
|
459
|
+
[:execution, :liquidation, :int],
|
460
|
+
[:execution, :cumulative_quantity, :int],
|
461
|
+
[:execution, :average_price, :decimal]
|
462
|
+
|
463
|
+
class ExecutionData
|
631
464
|
def load
|
632
465
|
super
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
@contract =
|
637
|
-
Models::Contract.build :con_id => @socket.read_int,
|
638
|
-
:symbol => @socket.read_string,
|
639
|
-
:sec_type => @socket.read_string,
|
640
|
-
:expiry => @socket.read_string,
|
641
|
-
:strike => @socket.read_decimal,
|
642
|
-
:right => @socket.read_string,
|
643
|
-
:exchange => @socket.read_string,
|
644
|
-
:currency => @socket.read_string,
|
645
|
-
:local_symbol => @socket.read_string
|
646
|
-
@execution =
|
647
|
-
Models::Execution.new :order_id => @data[:order_id],
|
648
|
-
:exec_id => @socket.read_string,
|
649
|
-
:time => @socket.read_string,
|
650
|
-
:account_number => @socket.read_string,
|
651
|
-
:exchange => @socket.read_string,
|
652
|
-
:side => @socket.read_string,
|
653
|
-
:shares => @socket.read_int,
|
654
|
-
:price => @socket.read_decimal,
|
655
|
-
:perm_id => @socket.read_int,
|
656
|
-
:client_id => @socket.read_int,
|
657
|
-
:liquidation => @socket.read_int,
|
658
|
-
:cumulative_quantity => @socket.read_int,
|
659
|
-
:average_price => @socket.read_decimal
|
466
|
+
@contract = Models::Contract.build @data[:contract]
|
467
|
+
@execution = Models::Execution.new @data[:execution]
|
660
468
|
end
|
661
469
|
|
662
470
|
def to_human
|
663
|
-
"<ExecutionData: #{contract.to_human}, #{execution}>"
|
471
|
+
"<ExecutionData #{request_id}: #{contract.to_human}, #{execution}>"
|
664
472
|
end
|
665
473
|
end # ExecutionData
|
666
474
|
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
475
|
+
BondContractData =
|
476
|
+
def_message [18, 4],
|
477
|
+
[:request_id, :int], # request id
|
478
|
+
[:contract, :symbol, :string],
|
479
|
+
[:contract, :sec_type, :string],
|
480
|
+
[:contract, :cusip, :string],
|
481
|
+
[:contract, :coupon, :decimal],
|
482
|
+
[:contract, :maturity, :string],
|
483
|
+
[:contract, :issue_date, :string],
|
484
|
+
[:contract, :ratings, :string],
|
485
|
+
[:contract, :bond_type, :string],
|
486
|
+
[:contract, :coupon_type, :string],
|
487
|
+
[:contract, :convertible, :boolean],
|
488
|
+
[:contract, :callable, :boolean],
|
489
|
+
[:contract, :puttable, :boolean],
|
490
|
+
[:contract, :desc_append, :string],
|
491
|
+
[:contract, :exchange, :string],
|
492
|
+
[:contract, :currency, :string],
|
493
|
+
[:contract, :market_name, :string], # extended
|
494
|
+
[:contract, :trading_class, :string],
|
495
|
+
[:contract, :con_id, :int],
|
496
|
+
[:contract, :min_tick, :decimal],
|
497
|
+
[:contract, :order_types, :string],
|
498
|
+
[:contract, :valid_exchanges, :string],
|
499
|
+
[:contract, :valid_next_option_date, :string],
|
500
|
+
[:contract, :valid_next_option_type, :string],
|
501
|
+
[:contract, :valid_next_option_partial, :string],
|
502
|
+
[:contract, :notes, :string],
|
503
|
+
[:contract, :long_name, :string]
|
504
|
+
|
505
|
+
class BondContractData
|
689
506
|
def load
|
690
507
|
super
|
691
|
-
|
692
|
-
[:start_date, :string],
|
693
|
-
[:end_date, :string],
|
694
|
-
[:count, :int]
|
695
|
-
|
696
|
-
@data[:results] = Array.new(@data[:count]) do |index|
|
697
|
-
Models::Bar.new :date => @socket.read_string,
|
698
|
-
:open => @socket.read_decimal,
|
699
|
-
:high => @socket.read_decimal,
|
700
|
-
:low => @socket.read_decimal,
|
701
|
-
:close => @socket.read_decimal,
|
702
|
-
:volume => @socket.read_int,
|
703
|
-
:wap => @socket.read_decimal,
|
704
|
-
:has_gaps => @socket.read_string,
|
705
|
-
:trades => @socket.read_int
|
706
|
-
end
|
508
|
+
@contract = Models::Contract.build @data[:contract]
|
707
509
|
end
|
510
|
+
end # BondContractData
|
708
511
|
|
709
|
-
|
710
|
-
|
512
|
+
# The server sends this message upon accepting a Delta-Neutral DN RFQ
|
513
|
+
# - see API Reference p. 26
|
514
|
+
DeltaNeutralValidation = def_message 56,
|
515
|
+
[:request_id, :int],
|
516
|
+
[:contract, :under_con_id, :int],
|
517
|
+
[:contract, :under_delta, :decimal],
|
518
|
+
[:contract, :under_price, :decimal]
|
519
|
+
class DeltaNeutralValidation
|
520
|
+
def load
|
521
|
+
super
|
522
|
+
@contract = Models::Contract.build @data[:contract].merge(:under_comp => true)
|
711
523
|
end
|
712
|
-
end #
|
713
|
-
|
714
|
-
class BondContractData < AbstractMessage
|
715
|
-
@message_id = 18
|
716
|
-
|
717
|
-
attr_accessor :contract
|
524
|
+
end # DeltaNeutralValidation
|
718
525
|
|
526
|
+
# RealTimeBar contains following @data:
|
527
|
+
# :request_id - The ID of the *request* to which this is responding
|
528
|
+
# :time - The date-time stamp of the start of the bar. The format is offset in
|
529
|
+
# seconds from the beginning of 1970, same format as the UNIX epoch time
|
530
|
+
# :bar - received RT Bar
|
531
|
+
RealTimeBar = def_message 50,
|
532
|
+
[:request_id, :int],
|
533
|
+
[:bar, :time, :int],
|
534
|
+
[:bar, :open, :decimal],
|
535
|
+
[:bar, :high, :decimal],
|
536
|
+
[:bar, :low, :decimal],
|
537
|
+
[:bar, :close, :decimal],
|
538
|
+
[:bar, :volume, :int],
|
539
|
+
[:bar, :wap, :decimal],
|
540
|
+
[:bar, :trades, :int]
|
541
|
+
class RealTimeBar
|
719
542
|
def load
|
720
543
|
super
|
721
|
-
|
722
|
-
|
723
|
-
@contract =
|
724
|
-
Models::Contract.build :symbol => @socket.read_string,
|
725
|
-
:sec_type => @socket.read_string,
|
726
|
-
:cusip => @socket.read_string,
|
727
|
-
:coupon => @socket.read_decimal,
|
728
|
-
:maturity => @socket.read_string,
|
729
|
-
:issue_date => @socket.read_string,
|
730
|
-
:ratings => @socket.read_string,
|
731
|
-
:bond_type => @socket.read_string,
|
732
|
-
:coupon_type => @socket.read_string,
|
733
|
-
:convertible => @socket.read_boolean,
|
734
|
-
:callable => @socket.read_boolean,
|
735
|
-
:puttable => @socket.read_boolean,
|
736
|
-
:desc_append => @socket.read_string,
|
737
|
-
:exchange => @socket.read_string,
|
738
|
-
:currency => @socket.read_string,
|
739
|
-
:market_name => @socket.read_string,
|
740
|
-
:trading_class => @socket.read_string,
|
741
|
-
:con_id => @socket.read_int,
|
742
|
-
:min_tick => @socket.read_decimal,
|
743
|
-
:order_types => @socket.read_string,
|
744
|
-
:valid_exchanges => @socket.read_string,
|
745
|
-
:valid_next_option_date => @socket.read_string,
|
746
|
-
:valid_next_option_type => @socket.read_string,
|
747
|
-
:valid_next_option_partial => @socket.read_string,
|
748
|
-
:notes => @socket.read_string,
|
749
|
-
:long_name => @socket.read_string
|
544
|
+
@bar = Models::Bar.new @data[:bar]
|
750
545
|
end
|
751
|
-
|
546
|
+
|
547
|
+
def to_human
|
548
|
+
"<RealTimeBar: #{request_id} #{time}, #{bar}>"
|
549
|
+
end
|
550
|
+
end # RealTimeBar
|
551
|
+
|
552
|
+
### Messages with really complicated message loading logics (cycles, conditions)
|
752
553
|
|
753
554
|
# This method receives the requested market scanner data results.
|
754
555
|
# ScannerData contains following @data:
|
755
|
-
# :
|
556
|
+
# :request_id - The ID of the request to which this row is responding
|
756
557
|
# :count - Number of data points returned (size of :results).
|
757
558
|
# :results - an Array of Hashes, each hash contains a set of
|
758
559
|
# data about one scanned Contract:
|
@@ -761,15 +562,16 @@ module IB
|
|
761
562
|
# :benchmark - Varies based on query.
|
762
563
|
# :projection - Varies based on query.
|
763
564
|
# :legs - Describes combo legs when scan is returning EFP.
|
764
|
-
|
765
|
-
|
565
|
+
ScannerData = def_message [20, 3],
|
566
|
+
[:request_id, :int], # request id
|
567
|
+
[:count, :int]
|
568
|
+
class ScannerData
|
569
|
+
attr_accessor :results
|
766
570
|
|
767
571
|
def load
|
768
572
|
super
|
769
|
-
load_map [:id, :int],
|
770
|
-
[:count, :int]
|
771
573
|
|
772
|
-
@
|
574
|
+
@results = Array.new(@data[:count]) do |index|
|
773
575
|
{:rank => @socket.read_int,
|
774
576
|
:contract => Contract.build(:con_id => @socket.read_int,
|
775
577
|
:symbol => @socket.read_str,
|
@@ -787,63 +589,189 @@ module IB
|
|
787
589
|
:projection => @socket.read_str,
|
788
590
|
:legs => @socket.read_str,
|
789
591
|
}
|
790
|
-
#eWrapper().scannerData(tickerId, rank, contract, distance,
|
791
|
-
# benchmark, projection, legsStr);
|
792
|
-
|
793
592
|
end
|
794
|
-
|
795
|
-
#eWrapper().scannerDataEnd(tickerId);
|
796
593
|
end
|
797
594
|
end # ScannerData
|
798
595
|
|
799
596
|
# HistoricalData contains following @data:
|
800
|
-
#
|
801
|
-
# :
|
802
|
-
#
|
803
|
-
# :
|
804
|
-
|
805
|
-
|
597
|
+
# General:
|
598
|
+
# :request_id - The ID of the request to which this is responding
|
599
|
+
# :count - Number of Historical data points returned (size of :results).
|
600
|
+
# :results - an Array of Historical Data Bars
|
601
|
+
# :start_date - beginning of returned Historical data period
|
602
|
+
# :end_date - end of returned Historical data period
|
603
|
+
# Each returned Bar in @data[:results] Array contains this data:
|
604
|
+
# :date - The date-time stamp of the start of the bar. The format is
|
605
|
+
# determined by the RequestHistoricalData formatDate parameter.
|
606
|
+
# :open - The bar opening price.
|
607
|
+
# :high - The high price during the time covered by the bar.
|
608
|
+
# :low - The low price during the time covered by the bar.
|
609
|
+
# :close - The bar closing price.
|
610
|
+
# :volume - The volume during the time covered by the bar.
|
611
|
+
# :trades - When TRADES historical data is returned, represents number of trades
|
612
|
+
# that occurred during the time period the bar covers
|
613
|
+
# :wap - The weighted average price during the time covered by the bar.
|
614
|
+
# :has_gaps - Whether or not there are gaps in the data.
|
806
615
|
|
807
|
-
|
616
|
+
HistoricalData = def_message [17, 3],
|
617
|
+
[:request_id, :int],
|
618
|
+
[:start_date, :string],
|
619
|
+
[:end_date, :string],
|
620
|
+
[:count, :int]
|
621
|
+
class HistoricalData
|
622
|
+
attr_accessor :results
|
808
623
|
|
809
624
|
def load
|
810
625
|
super
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
626
|
+
|
627
|
+
@results = Array.new(@data[:count]) do |index|
|
628
|
+
Models::Bar.new :time => @socket.read_string,
|
629
|
+
:open => @socket.read_decimal,
|
630
|
+
:high => @socket.read_decimal,
|
631
|
+
:low => @socket.read_decimal,
|
632
|
+
:close => @socket.read_decimal,
|
633
|
+
:volume => @socket.read_int,
|
634
|
+
:wap => @socket.read_decimal,
|
635
|
+
:has_gaps => @socket.read_string,
|
636
|
+
:trades => @socket.read_int
|
637
|
+
end
|
822
638
|
end
|
823
639
|
|
824
640
|
def to_human
|
825
|
-
"<
|
641
|
+
"<HistoricalData: #{request_id}, #{count} items, #{start_date} to #{end_date}>"
|
826
642
|
end
|
827
|
-
end #
|
828
|
-
RealTimeBars = RealTimeBar
|
643
|
+
end # HistoricalData
|
829
644
|
|
830
|
-
# The server sends this message upon accepting a Delta-Neutral DN RFQ
|
831
|
-
# - see API Reference p. 26
|
832
|
-
class DeltaNeutralValidation < AbstractMessage
|
833
|
-
@message_id = 56
|
834
645
|
|
835
|
-
|
646
|
+
OpenOrder =
|
647
|
+
def_message [5, 23],
|
648
|
+
# The reqID that was specified previously in the call to reqExecution()
|
649
|
+
[:order, :order_id, :int],
|
650
|
+
|
651
|
+
[:contract, :con_id, :int],
|
652
|
+
[:contract, :symbol, :string],
|
653
|
+
[:contract, :sec_type, :string],
|
654
|
+
[:contract, :expiry, :string],
|
655
|
+
[:contract, :strike, :decimal],
|
656
|
+
[:contract, :right, :string],
|
657
|
+
[:contract, :exchange, :string],
|
658
|
+
[:contract, :currency, :string],
|
659
|
+
[:contract, :local_symbol, :string],
|
660
|
+
|
661
|
+
[:order, :action, :string],
|
662
|
+
[:order, :total_quantity, :int],
|
663
|
+
[:order, :order_type, :string],
|
664
|
+
[:order, :limit_price, :decimal],
|
665
|
+
[:order, :aux_price, :decimal],
|
666
|
+
[:order, :tif, :string],
|
667
|
+
[:order, :oca_group, :string],
|
668
|
+
[:order, :account, :string],
|
669
|
+
[:order, :open_close, :string],
|
670
|
+
[:order, :origin, :int],
|
671
|
+
[:order, :order_ref, :string],
|
672
|
+
[:order, :client_id, :int],
|
673
|
+
[:order, :perm_id, :int],
|
674
|
+
[:order, :outside_rth, :boolean], # (@socket.read_int == 1)
|
675
|
+
[:order, :hidden, :boolean], # (@socket.read_int == 1)
|
676
|
+
[:order, :discretionary_amount, :decimal],
|
677
|
+
[:order, :good_after_time, :string],
|
678
|
+
[:skip, :string], # skip deprecated sharesAllocation field
|
679
|
+
|
680
|
+
[:order, :fa_group, :string],
|
681
|
+
[:order, :fa_method, :string],
|
682
|
+
[:order, :fa_percentage, :string],
|
683
|
+
[:order, :fa_profile, :string],
|
684
|
+
[:order, :good_till_date, :string],
|
685
|
+
[:order, :rule_80a, :string],
|
686
|
+
[:order, :percent_offset, :decimal],
|
687
|
+
[:order, :settling_firm, :string],
|
688
|
+
[:order, :short_sale_slot, :int],
|
689
|
+
[:order, :designated_location, :string],
|
690
|
+
[:order, :exempt_code, :int], # skipped in ver 51?
|
691
|
+
[:order, :auction_strategy, :int],
|
692
|
+
[:order, :starting_price, :decimal],
|
693
|
+
[:order, :stock_ref_price, :decimal],
|
694
|
+
[:order, :delta, :decimal],
|
695
|
+
[:order, :stock_range_lower, :decimal],
|
696
|
+
[:order, :stock_range_upper, :decimal],
|
697
|
+
[:order, :display_size, :int],
|
698
|
+
#@order.rth_only = @socket.read_boolean
|
699
|
+
[:order, :block_order, :boolean],
|
700
|
+
[:order, :sweep_to_fill, :boolean],
|
701
|
+
[:order, :all_or_none, :boolean],
|
702
|
+
[:order, :min_quantity, :int],
|
703
|
+
[:order, :oca_type, :int],
|
704
|
+
[:order, :etrade_only, :boolean],
|
705
|
+
[:order, :firm_quote_only, :boolean],
|
706
|
+
[:order, :nbbo_price_cap, :decimal],
|
707
|
+
[:order, :parent_id, :int],
|
708
|
+
[:order, :trigger_method, :int],
|
709
|
+
[:order, :volatility, :decimal],
|
710
|
+
[:order, :volatility_type, :int],
|
711
|
+
[:order, :delta_neutral_order_type, :string],
|
712
|
+
[:order, :delta_neutral_aux_price, :decimal],
|
713
|
+
|
714
|
+
[:order, :continuous_update, :int],
|
715
|
+
[:order, :reference_price_type, :int],
|
716
|
+
[:order, :trail_stop_price, :decimal],
|
717
|
+
[:order, :basis_points, :decimal],
|
718
|
+
[:order, :basis_points_type, :int],
|
719
|
+
[:contract, :legs_description, :string],
|
720
|
+
[:order, :scale_init_level_size, :int_max],
|
721
|
+
[:order, :scale_subs_level_size, :int_max],
|
722
|
+
[:order, :scale_price_increment, :decimal_max],
|
723
|
+
[:order, :clearing_account, :string],
|
724
|
+
[:order, :clearing_intent, :string],
|
725
|
+
[:order, :not_held, :boolean] # (@socket.read_int == 1)
|
726
|
+
|
727
|
+
class OpenOrder
|
836
728
|
|
837
729
|
def load
|
838
730
|
super
|
839
|
-
load_map [:id, :int] # request id
|
840
731
|
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
732
|
+
load_map [:contract, :under_comp, :boolean] # (@socket.read_int == 1)
|
733
|
+
|
734
|
+
if @data[:contract][:under_comp]
|
735
|
+
load_map [:contract, :under_con_id, :int],
|
736
|
+
[:contract, :under_delta, :decimal],
|
737
|
+
[:contract, :under_price, :decimal]
|
738
|
+
end
|
739
|
+
|
740
|
+
load_map [:order, :algo_strategy, :string]
|
741
|
+
|
742
|
+
unless @data[:order][:algo_strategy].nil? || @data[:order][:algo_strategy].empty?
|
743
|
+
load_map [:algo_params_count, :int]
|
744
|
+
if @data[:algo_params_count] > 0
|
745
|
+
@data[:order][:algo_params] = Hash.new
|
746
|
+
@data[:algo_params_count].times do
|
747
|
+
tag = @socket.read_string
|
748
|
+
value = @socket.read_string
|
749
|
+
@data[:order][:algo_params][tag] = value
|
750
|
+
end
|
751
|
+
end
|
752
|
+
end
|
753
|
+
|
754
|
+
load_map [:order, :what_if, :boolean], # (@socket.read_int == 1)
|
755
|
+
[:order, :status, :string],
|
756
|
+
[:order, :init_margin, :string],
|
757
|
+
[:order, :maint_margin, :string],
|
758
|
+
[:order, :equity_with_loan, :string],
|
759
|
+
[:order, :commission, :decimal_max], # May be nil!
|
760
|
+
[:order, :min_commission, :decimal_max], # May be nil!
|
761
|
+
[:order, :max_commission, :decimal_max], # May be nil!
|
762
|
+
[:order, :commission_currency, :string],
|
763
|
+
[:order, :warning_text, :string]
|
764
|
+
|
765
|
+
@order = Models::Order.new @data[:order]
|
766
|
+
@contract = Models::Contract.build @data[:contract]
|
845
767
|
end
|
846
|
-
|
768
|
+
|
769
|
+
def to_human
|
770
|
+
"<OpenOrder: #{@contract.to_human} #{@order.to_human}>"
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
# OpenOrder
|
847
775
|
|
848
776
|
Table = Hash.new
|
849
777
|
Classes.each { |msg_class| Table[msg_class.message_id] = msg_class }
|