ib-ruby 0.6.1 → 0.7.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.
- data/HISTORY +4 -0
- data/README.md +25 -17
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +2 -1
- data/bin/contract_details +3 -2
- data/bin/depth_of_market +1 -1
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +57 -104
- data/bin/list_orders +4 -3
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +63 -0
- data/bin/place_order +2 -4
- data/bin/template +1 -1
- data/bin/{generic_data.rb → tick_data} +3 -1
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +1 -0
- data/lib/ib-ruby/connection.rb +68 -68
- data/lib/ib-ruby/errors.rb +28 -0
- data/lib/ib-ruby/extensions.rb +7 -0
- data/lib/ib-ruby/messages.rb +1 -0
- data/lib/ib-ruby/messages/abstract_message.rb +16 -11
- data/lib/ib-ruby/messages/incoming.rb +125 -329
- data/lib/ib-ruby/messages/incoming/open_order.rb +193 -0
- data/lib/ib-ruby/messages/incoming/ticks.rb +131 -0
- data/lib/ib-ruby/messages/outgoing.rb +44 -45
- data/lib/ib-ruby/models/combo_leg.rb +16 -1
- data/lib/ib-ruby/models/contract.rb +18 -10
- data/lib/ib-ruby/models/contract/bag.rb +1 -7
- data/lib/ib-ruby/models/execution.rb +2 -1
- data/lib/ib-ruby/models/model.rb +1 -1
- data/lib/ib-ruby/models/order.rb +116 -56
- data/lib/ib-ruby/socket.rb +24 -3
- data/spec/account_helper.rb +2 -1
- data/spec/ib-ruby/messages/outgoing_spec.rb +1 -1
- data/spec/ib-ruby/models/combo_leg_spec.rb +0 -1
- data/spec/integration/account_info_spec.rb +2 -2
- data/spec/integration/contract_info_spec.rb +4 -4
- data/spec/integration/depth_data_spec.rb +3 -3
- data/spec/integration/historic_data_spec.rb +1 -1
- data/spec/integration/market_data_spec.rb +4 -4
- data/spec/integration/option_data_spec.rb +1 -1
- data/spec/integration/orders/combo_spec.rb +51 -0
- data/spec/integration/orders/execution_spec.rb +15 -8
- data/spec/integration/orders/placement_spec.rb +46 -72
- data/spec/integration/orders/valid_ids_spec.rb +6 -6
- data/spec/integration_helper.rb +0 -79
- data/spec/order_helper.rb +153 -0
- metadata +13 -4
data/lib/ib-ruby/extensions.rb
CHANGED
data/lib/ib-ruby/messages.rb
CHANGED
@@ -16,14 +16,12 @@ module IB
|
|
16
16
|
# @message_type - Symbol: message type (e.g. :OpenOrderEnd)
|
17
17
|
#
|
18
18
|
# Instance attributes (at least):
|
19
|
-
# version - int: current version of message format.
|
19
|
+
# @version - int: current version of message format.
|
20
20
|
# @data - Hash of actual data read from a stream.
|
21
|
-
#
|
22
|
-
# Override the load(socket) method in your subclass to do actual reading into @data.
|
23
21
|
class AbstractMessage
|
24
22
|
|
25
23
|
# Class methods
|
26
|
-
def self.data_map #
|
24
|
+
def self.data_map # Map for converting between structured message and raw data
|
27
25
|
@data_map ||= []
|
28
26
|
end
|
29
27
|
|
@@ -61,16 +59,18 @@ module IB
|
|
61
59
|
|
62
60
|
end # class AbstractMessage
|
63
61
|
|
64
|
-
# Macro that defines short message classes using a one-liner
|
65
|
-
#
|
62
|
+
# Macro that defines short message classes using a one-liner.
|
63
|
+
# First arg is either a [message_id, version] pair or just message_id (version 1)
|
66
64
|
# data_map contains instructions for processing @data Hash. Format:
|
67
65
|
# Incoming messages: [field, type] or [group, field, type]
|
68
|
-
# Outgoing messages: [field, default] or [field, method, [args]]
|
69
|
-
def def_message
|
66
|
+
# Outgoing messages: field, [field, default] or [field, method, [args]]
|
67
|
+
def def_message message_id_version, *data_map, &to_human
|
70
68
|
base = data_map.first.is_a?(Class) ? data_map.shift : self::AbstractMessage
|
71
|
-
|
72
|
-
|
73
|
-
|
69
|
+
message_id, version = message_id_version
|
70
|
+
|
71
|
+
# Define new message class
|
72
|
+
message_class = Class.new(base) do
|
73
|
+
@message_id, @version = message_id, version || 1
|
74
74
|
@data_map = data_map
|
75
75
|
|
76
76
|
@data_map.each do |(name, _, type_args)|
|
@@ -83,6 +83,11 @@ module IB
|
|
83
83
|
|
84
84
|
define_method(:to_human, &to_human) if to_human
|
85
85
|
end
|
86
|
+
|
87
|
+
# Add defined message class to Classes Hash keyed by its message_id
|
88
|
+
self::Classes[message_id] = message_class
|
89
|
+
|
90
|
+
message_class
|
86
91
|
end
|
87
92
|
|
88
93
|
end # module Messages
|
@@ -11,85 +11,106 @@ require 'ib-ruby/messages/abstract_message'
|
|
11
11
|
module IB
|
12
12
|
module Messages
|
13
13
|
|
14
|
-
# Incoming IB messages
|
14
|
+
# Incoming IB messages (received from TWS/Gateway)
|
15
15
|
module Incoming
|
16
16
|
extend Messages # def_message macros
|
17
17
|
|
18
|
-
|
18
|
+
# Container for specific message classes, keyed by their message_ids
|
19
|
+
Classes = {}
|
19
20
|
|
20
21
|
class AbstractMessage < IB::Messages::AbstractMessage
|
21
22
|
|
22
|
-
def self.inherited(by)
|
23
|
-
super(by)
|
24
|
-
Classes.push(by)
|
25
|
-
end
|
26
|
-
|
27
23
|
def version # Per message, received messages may have the different versions
|
28
24
|
@data[:version]
|
29
25
|
end
|
30
26
|
|
31
|
-
|
32
|
-
|
27
|
+
def check_version actual, expected
|
28
|
+
unless actual == expected || expected.is_a?(Array) && expected.include?(actual)
|
29
|
+
error "Unsupported version #{actual} received, expected #{expected}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create incoming message from a given source (IB server or data Hash)
|
34
|
+
def initialize source
|
33
35
|
@created_at = Time.now
|
34
|
-
if
|
35
|
-
@
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
if source[:socket] # Source is a server
|
37
|
+
@server = source
|
38
|
+
@data = Hash.new
|
39
|
+
begin
|
40
|
+
self.load
|
41
|
+
rescue => e
|
42
|
+
error "Reading #{self.class}: #{e.class}: #{e.message}", :load, e.backtrace
|
43
|
+
ensure
|
44
|
+
@server = nil
|
45
|
+
end
|
46
|
+
else # Source is a @data Hash
|
47
|
+
@data = source
|
41
48
|
end
|
42
49
|
end
|
43
50
|
|
51
|
+
def socket
|
52
|
+
@server[:socket]
|
53
|
+
end
|
54
|
+
|
44
55
|
# Every message loads received message version first
|
56
|
+
# Override the load method in your subclass to do actual reading into @data.
|
45
57
|
def load
|
46
|
-
@data[:version] =
|
58
|
+
@data[:version] = socket.read_int
|
47
59
|
|
48
|
-
|
49
|
-
raise "Unsupported version #{@data[:version]} of #{self.class} received"
|
50
|
-
end
|
60
|
+
check_version @data[:version], self.class.version
|
51
61
|
|
52
62
|
load_map *self.class.data_map
|
53
63
|
end
|
54
64
|
|
55
|
-
# Load @data from the socket according to the given map.
|
65
|
+
# Load @data from the socket according to the given data map.
|
56
66
|
#
|
57
67
|
# map is a series of Arrays in the format of
|
58
|
-
# [ [ :name, :type
|
59
|
-
# [ :group, :name, :type] ]
|
68
|
+
# [ :name, :type ], [ :group, :name, :type]
|
60
69
|
# type identifiers must have a corresponding read_type method on socket (read_int, etc.).
|
61
70
|
# group is used to lump together aggregates, such as Contract or Order fields
|
62
71
|
def load_map(*map)
|
63
|
-
map.each do |
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
map.each do |instruction|
|
73
|
+
# We determine the function of the first element
|
74
|
+
head = instruction.first
|
75
|
+
case head
|
76
|
+
when Integer # >= Version condition: [ min_version, [map]]
|
77
|
+
load_map *instruction.drop(1) if version >= head
|
78
|
+
|
79
|
+
when Proc # Callable condition: [ condition, [map]]
|
80
|
+
load_map *instruction.drop(1) if head.call
|
81
|
+
|
82
|
+
when true # Pre-condition already succeeded!
|
83
|
+
load_map *instruction.drop(1)
|
84
|
+
|
85
|
+
when nil, false # Pre-condition already failed! Do nothing...
|
86
|
+
|
87
|
+
when Symbol # Normal map
|
88
|
+
group, name, type, block =
|
89
|
+
if instruction[2].nil? || instruction[2].is_a?(Proc)
|
90
|
+
[nil] + instruction # No group, [ :name, :type, (:block) ]
|
91
|
+
else
|
92
|
+
instruction # [ :group, :name, :type, (:block)]
|
93
|
+
end
|
94
|
+
|
95
|
+
data = socket.__send__("read_#{type}", &block)
|
96
|
+
if group
|
97
|
+
@data[group] ||= {}
|
98
|
+
@data[group][name] = data
|
99
|
+
else
|
100
|
+
@data[name] = data
|
101
|
+
end
|
102
|
+
else
|
103
|
+
error "Unrecognized instruction #{instruction}"
|
72
104
|
end
|
73
105
|
end
|
74
106
|
end
|
75
|
-
end # class AbstractMessage
|
76
|
-
|
77
|
-
class AbstractTick < AbstractMessage
|
78
|
-
# Returns Symbol with a meaningful name for received tick type
|
79
|
-
def type
|
80
|
-
TICK_TYPES[@data[:tick_type]]
|
81
|
-
end
|
82
|
-
|
83
|
-
def to_human
|
84
|
-
"<#{self.message_type} #{type}:" +
|
85
|
-
@data.map do |key, value|
|
86
|
-
" #{key} #{value}" unless [:version, :ticker_id, :tick_type].include?(key)
|
87
|
-
end.compact.join(',') + " >"
|
88
|
-
end
|
89
107
|
end
|
90
108
|
|
109
|
+
# class AbstractMessage
|
110
|
+
|
91
111
|
### Actual message classes (short definitions):
|
92
|
-
|
112
|
+
|
113
|
+
# :status - String: Displays the order status. Possible values include:
|
93
114
|
# � PendingSubmit - indicates that you have transmitted the order, but
|
94
115
|
# have not yet received confirmation that it has been accepted by the
|
95
116
|
# order destination. NOTE: This order status is NOT sent back by TWS
|
@@ -133,7 +154,6 @@ module IB
|
|
133
154
|
" id/perm: #{order_id}/#{perm_id}>"
|
134
155
|
end
|
135
156
|
|
136
|
-
|
137
157
|
AccountValue = def_message([6, 2], [:key, :string],
|
138
158
|
[:value, :string],
|
139
159
|
[:currency, :string],
|
@@ -178,127 +198,25 @@ module IB
|
|
178
198
|
|
179
199
|
# Receive Reuters global fundamental market data. There must be a subscription to
|
180
200
|
# Reuters Fundamental set up in Account Management before you can receive this data.
|
181
|
-
FundamentalData = def_message 50, [:request_id, :int],
|
182
|
-
[:data, :string]
|
201
|
+
FundamentalData = def_message 50, [:request_id, :int], [:data, :string]
|
183
202
|
|
184
|
-
ContractDataEnd = def_message 52, [:request_id, :int]
|
203
|
+
ContractDataEnd = def_message 52, [:request_id, :int]
|
185
204
|
|
186
205
|
OpenOrderEnd = def_message 53
|
187
206
|
|
188
207
|
AccountDownloadEnd = def_message 54, [:account_name, :string]
|
189
208
|
|
190
|
-
ExecutionDataEnd = def_message 55, [:request_id, :int]
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
#
|
202
|
-
# "The low you get is NOT the low for the day as you'd expect it
|
203
|
-
# to be. It appears IB calculates the low based on all
|
204
|
-
# transactions after 4pm the previous day. The most inaccurate
|
205
|
-
# results occur when the stock moves up in the 4-6pm aftermarket
|
206
|
-
# on the previous day and then gaps open upward in the
|
207
|
-
# morning. The low you receive from TWS can be easily be several
|
208
|
-
# points different from the actual 9:30am-4pm low for the day in
|
209
|
-
# cases like this. If you require a correct traded low for the
|
210
|
-
# day, you can't get it from the TWS API. One possible source to
|
211
|
-
# help build the right data would be to compare against what Yahoo
|
212
|
-
# lists on finance.yahoo.com/q?s=ticker under the "Day's Range"
|
213
|
-
# statistics (be careful here, because Yahoo will use anti-Denial
|
214
|
-
# of Service techniques to hang your connection if you try to
|
215
|
-
# request too many bytes in a short period of time from them). For
|
216
|
-
# most purposes, a good enough approach would start by replacing
|
217
|
-
# the TWS low for the day with Yahoo's day low when you first
|
218
|
-
# start watching a stock ticker; let's call this time T. Then,
|
219
|
-
# update your internal low if the bid or ask tick you receive is
|
220
|
-
# lower than that for the remainder of the day. You should check
|
221
|
-
# against Yahoo again at time T+20min to handle the occasional
|
222
|
-
# case where the stock set a new low for the day in between
|
223
|
-
# T-20min (the real time your original quote was from, taking into
|
224
|
-
# account the delay) and time T. After that you should have a
|
225
|
-
# correct enough low for the rest of the day as long as you keep
|
226
|
-
# updating based on the bid/ask. It could still get slightly off
|
227
|
-
# in a case where a short transaction setting a new low appears in
|
228
|
-
# between ticks of data that TWS sends you. The high is probably
|
229
|
-
# distorted in the same way the low is, which would throw your
|
230
|
-
# results off if the stock traded after-hours and gapped down. It
|
231
|
-
# should be corrected in a similar way as described above if this
|
232
|
-
# is important to you."
|
233
|
-
#
|
234
|
-
# IB then emits at most 2 events on eWrapper:
|
235
|
-
# tickPrice( tickerId, tickType, price, canAutoExecute)
|
236
|
-
# tickSize( tickerId, sizeTickType, size)
|
237
|
-
TickPrice = def_message [1, 6], AbstractTick,
|
238
|
-
[:ticker_id, :int],
|
239
|
-
[:tick_type, :int],
|
240
|
-
[:price, :decimal],
|
241
|
-
[:size, :int],
|
242
|
-
[:can_auto_execute, :int]
|
243
|
-
|
244
|
-
TickSize = def_message [2, 6], AbstractTick,
|
245
|
-
[:ticker_id, :int],
|
246
|
-
[:tick_type, :int],
|
247
|
-
[:size, :int]
|
248
|
-
|
249
|
-
TickGeneric = def_message [45, 6], AbstractTick,
|
250
|
-
[:ticker_id, :int],
|
251
|
-
[:tick_type, :int],
|
252
|
-
[:value, :decimal]
|
253
|
-
|
254
|
-
TickString = def_message [46, 6], AbstractTick,
|
255
|
-
[:ticker_id, :int],
|
256
|
-
[:tick_type, :int],
|
257
|
-
[:value, :string]
|
258
|
-
|
259
|
-
TickEFP = def_message [47, 6], AbstractTick,
|
260
|
-
[:ticker_id, :int],
|
261
|
-
[:tick_type, :int],
|
262
|
-
[:basis_points, :decimal],
|
263
|
-
[:formatted_basis_points, :string],
|
264
|
-
[:implied_futures_price, :decimal],
|
265
|
-
[:hold_days, :int],
|
266
|
-
[:dividend_impact, :decimal],
|
267
|
-
[:dividends_to_expiry, :decimal]
|
268
|
-
|
269
|
-
# This message is received when the market in an option or its underlier moves.
|
270
|
-
# TWS�s option model volatilities, prices, and deltas, along with the present
|
271
|
-
# value of dividends expected on that options underlier are received.
|
272
|
-
# TickOption message contains following @data:
|
273
|
-
# :ticker_id - Id that was specified previously in the call to reqMktData()
|
274
|
-
# :tick_type - Specifies the type of option computation (see TICK_TYPES).
|
275
|
-
# :implied_volatility - The implied volatility calculated by the TWS option
|
276
|
-
# modeler, using the specified :tick_type value.
|
277
|
-
# :delta - The option delta value.
|
278
|
-
# :option_price - The option price.
|
279
|
-
# :pv_dividend - The present value of dividends expected on the options underlier
|
280
|
-
# :gamma - The option gamma value.
|
281
|
-
# :vega - The option vega value.
|
282
|
-
# :theta - The option theta value.
|
283
|
-
# :under_price - The price of the underlying.
|
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
|
209
|
+
ExecutionDataEnd = def_message 55, [:request_id, :int]
|
210
|
+
|
211
|
+
MarketDataType = def_message 58, [:request_id, :int], [:market_data_type, :int]
|
212
|
+
|
213
|
+
CommissionReport =
|
214
|
+
def_message 59, [:exec_id, :int],
|
215
|
+
[:commission, :decimal], # Commission amount.
|
216
|
+
[:currency, :int], # Commission currency
|
217
|
+
[:realized_pnl, :decimal],
|
218
|
+
[:yield, :decimal],
|
219
|
+
[:yield_redemption_date, :int]
|
302
220
|
|
303
221
|
MarketDepth =
|
304
222
|
def_message 12, [:request_id, :int],
|
@@ -433,7 +351,7 @@ module IB
|
|
433
351
|
end # ContractData
|
434
352
|
|
435
353
|
ExecutionData =
|
436
|
-
def_message [11,
|
354
|
+
def_message [11, 8],
|
437
355
|
# The reqID that was specified previously in the call to reqExecution()
|
438
356
|
[:request_id, :int],
|
439
357
|
[:execution, :order_id, :int],
|
@@ -463,6 +381,11 @@ module IB
|
|
463
381
|
class ExecutionData
|
464
382
|
def load
|
465
383
|
super
|
384
|
+
|
385
|
+
# As of client v.53, we can receive orderRef in ExecutionData
|
386
|
+
load_map [proc { | | @server[:client_version] >= 53 },
|
387
|
+
[:execution, :order_ref, :string]
|
388
|
+
]
|
466
389
|
@contract = Models::Contract.build @data[:contract]
|
467
390
|
@execution = Models::Execution.new @data[:execution]
|
468
391
|
end
|
@@ -470,11 +393,12 @@ module IB
|
|
470
393
|
def to_human
|
471
394
|
"<ExecutionData #{request_id}: #{contract.to_human}, #{execution}>"
|
472
395
|
end
|
396
|
+
|
473
397
|
end # ExecutionData
|
474
398
|
|
475
399
|
BondContractData =
|
476
400
|
def_message [18, 4],
|
477
|
-
[:request_id, :int],
|
401
|
+
[:request_id, :int],
|
478
402
|
[:contract, :symbol, :string],
|
479
403
|
[:contract, :sec_type, :string],
|
480
404
|
[:contract, :cusip, :string],
|
@@ -571,23 +495,23 @@ module IB
|
|
571
495
|
def load
|
572
496
|
super
|
573
497
|
|
574
|
-
@results = Array.new(@data[:count]) do |
|
575
|
-
{:rank =>
|
576
|
-
:contract => Contract.build(:con_id =>
|
577
|
-
:symbol =>
|
578
|
-
:sec_type =>
|
579
|
-
:expiry =>
|
580
|
-
:strike =>
|
581
|
-
:right =>
|
582
|
-
:exchange =>
|
583
|
-
:currency =>
|
584
|
-
:local_symbol =>
|
585
|
-
:market_name =>
|
586
|
-
:trading_class =>
|
587
|
-
:distance =>
|
588
|
-
:benchmark =>
|
589
|
-
:projection =>
|
590
|
-
:legs =>
|
498
|
+
@results = Array.new(@data[:count]) do |_|
|
499
|
+
{:rank => socket.read_int,
|
500
|
+
:contract => Contract.build(:con_id => socket.read_int,
|
501
|
+
:symbol => socket.read_str,
|
502
|
+
:sec_type => socket.read_str,
|
503
|
+
:expiry => socket.read_str,
|
504
|
+
:strike => socket.read_decimal,
|
505
|
+
:right => socket.read_str,
|
506
|
+
:exchange => socket.read_str,
|
507
|
+
:currency => socket.read_str,
|
508
|
+
:local_symbol => socket.read_str,
|
509
|
+
:market_name => socket.read_str,
|
510
|
+
:trading_class => socket.read_str),
|
511
|
+
:distance => socket.read_str,
|
512
|
+
:benchmark => socket.read_str,
|
513
|
+
:projection => socket.read_str,
|
514
|
+
:legs => socket.read_str,
|
591
515
|
}
|
592
516
|
end
|
593
517
|
end
|
@@ -624,16 +548,16 @@ module IB
|
|
624
548
|
def load
|
625
549
|
super
|
626
550
|
|
627
|
-
@results = Array.new(@data[:count]) do |
|
628
|
-
Models::Bar.new :time =>
|
629
|
-
:open =>
|
630
|
-
:high =>
|
631
|
-
:low =>
|
632
|
-
:close =>
|
633
|
-
:volume =>
|
634
|
-
:wap =>
|
635
|
-
:has_gaps =>
|
636
|
-
:trades =>
|
551
|
+
@results = Array.new(@data[:count]) do |_|
|
552
|
+
Models::Bar.new :time => socket.read_string,
|
553
|
+
:open => socket.read_decimal,
|
554
|
+
:high => socket.read_decimal,
|
555
|
+
:low => socket.read_decimal,
|
556
|
+
:close => socket.read_decimal,
|
557
|
+
:volume => socket.read_int,
|
558
|
+
:wap => socket.read_decimal,
|
559
|
+
:has_gaps => socket.read_string,
|
560
|
+
:trades => socket.read_int
|
637
561
|
end
|
638
562
|
end
|
639
563
|
|
@@ -642,147 +566,17 @@ module IB
|
|
642
566
|
end
|
643
567
|
end # HistoricalData
|
644
568
|
|
645
|
-
|
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
|
728
|
-
|
729
|
-
def load
|
730
|
-
super
|
731
|
-
|
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]
|
767
|
-
end
|
768
|
-
|
769
|
-
def to_human
|
770
|
-
"<OpenOrder: #{@contract.to_human} #{@order.to_human}>"
|
771
|
-
end
|
772
|
-
end
|
773
|
-
|
774
|
-
# OpenOrder
|
775
|
-
|
776
|
-
Table = Hash.new
|
777
|
-
Classes.each { |msg_class| Table[msg_class.message_id] = msg_class }
|
778
|
-
|
779
569
|
end # module Incoming
|
780
570
|
end # module Messages
|
781
571
|
end # module IB
|
782
|
-
__END__
|
783
572
|
|
573
|
+
# Require standalone message source files
|
574
|
+
require 'ib-ruby/messages/incoming/ticks'
|
575
|
+
require 'ib-ruby/messages/incoming/open_order'
|
576
|
+
|
577
|
+
__END__
|
784
578
|
// incoming msg id's
|
785
|
-
static final int TICK_PRICE = 1; *
|
579
|
+
static final int TICK_PRICE = 1; *
|
786
580
|
static final int TICK_SIZE = 2; *
|
787
581
|
static final int ORDER_STATUS = 3; *
|
788
582
|
static final int ERR_MSG = 4; *
|
@@ -792,7 +586,7 @@ __END__
|
|
792
586
|
static final int ACCT_UPDATE_TIME = 8; *
|
793
587
|
static final int NEXT_VALID_ID = 9; *
|
794
588
|
static final int CONTRACT_DATA = 10; *
|
795
|
-
static final int EXECUTION_DATA = 11;
|
589
|
+
static final int EXECUTION_DATA = 11; ?
|
796
590
|
static final int MARKET_DEPTH = 12; *
|
797
591
|
static final int MARKET_DEPTH_L2 = 13; *
|
798
592
|
static final int NEWS_BULLETINS = 14; *
|
@@ -815,3 +609,5 @@ __END__
|
|
815
609
|
static final int EXECUTION_DATA_END = 55; *
|
816
610
|
static final int DELTA_NEUTRAL_VALIDATION = 56; *
|
817
611
|
static final int TICK_SNAPSHOT_END = 57; *
|
612
|
+
static final int MARKET_DATA_TYPE = 58; ?
|
613
|
+
static final int COMMISSION_REPORT = 59; ?
|