ib-ruby 0.5.19 → 0.5.21
Sign up to get free protection for your applications and to get access to all the features.
- 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 }
|