ib-ruby 0.4.3 → 0.4.20
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/HISTORY +68 -0
- data/README.rdoc +9 -6
- data/VERSION +1 -1
- data/bin/account_info +29 -0
- data/bin/contract_details +37 -0
- data/bin/depth_of_market +43 -0
- data/bin/historic_data +62 -0
- data/bin/{RequestHistoricData → historic_data_cli} +46 -91
- data/bin/market_data +49 -0
- data/bin/option_data +45 -0
- data/bin/template +21 -0
- data/bin/time_and_sales +63 -0
- data/lib/ib-ruby/connection.rb +166 -0
- data/lib/ib-ruby/constants.rb +91 -0
- data/lib/ib-ruby/messages/incoming.rb +807 -0
- data/lib/ib-ruby/messages/outgoing.rb +573 -0
- data/lib/ib-ruby/messages.rb +8 -1445
- data/lib/ib-ruby/models/bar.rb +26 -0
- data/lib/ib-ruby/models/contract.rb +335 -0
- data/lib/ib-ruby/models/execution.rb +55 -0
- data/lib/ib-ruby/models/model.rb +20 -0
- data/lib/ib-ruby/models/order.rb +262 -0
- data/lib/ib-ruby/models.rb +11 -0
- data/lib/ib-ruby/socket.rb +50 -0
- data/lib/ib-ruby/symbols/forex.rb +32 -72
- data/lib/ib-ruby/symbols/futures.rb +47 -68
- data/lib/ib-ruby/symbols/options.rb +30 -0
- data/lib/ib-ruby/symbols/stocks.rb +23 -0
- data/lib/ib-ruby/symbols.rb +9 -0
- data/lib/ib-ruby.rb +7 -8
- data/lib/legacy/bin/account_info_old +36 -0
- data/lib/legacy/bin/historic_data_old +81 -0
- data/lib/legacy/bin/market_data_old +68 -0
- data/lib/legacy/datatypes.rb +485 -0
- data/lib/legacy/ib-ruby.rb +10 -0
- data/lib/legacy/ib.rb +226 -0
- data/lib/legacy/messages.rb +1458 -0
- data/lib/version.rb +2 -3
- data/spec/ib-ruby/models/contract_spec.rb +261 -0
- data/spec/ib-ruby/models/order_spec.rb +64 -0
- data/spec/ib-ruby_spec.rb +0 -131
- metadata +106 -76
- data/bin/AccountInfo +0 -67
- data/bin/HistoricToCSV +0 -111
- data/bin/RequestMarketData +0 -78
- data/bin/SimpleTimeAndSales +0 -98
- data/bin/ib-ruby +0 -8
- data/lib/ib-ruby/datatypes.rb +0 -400
- data/lib/ib-ruby/ib.rb +0 -242
@@ -0,0 +1,573 @@
|
|
1
|
+
# EClientSocket.java uses sendMax() rather than send() for a number of these.
|
2
|
+
# It sends an EOL rather than a number if the value == Integer.MAX_VALUE (or Double.MAX_VALUE).
|
3
|
+
# These fields are initialized to this MAX_VALUE.
|
4
|
+
# This has been implemented with nils in Ruby to represent the case where an EOL should be sent.
|
5
|
+
|
6
|
+
# TODO: Don't instantiate messages, use their classes as just namespace for .encode/decode
|
7
|
+
|
8
|
+
module IB
|
9
|
+
module Messages
|
10
|
+
module Outgoing
|
11
|
+
|
12
|
+
class AbstractMessage
|
13
|
+
# Class methods
|
14
|
+
def self.message_id
|
15
|
+
@message_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.version
|
19
|
+
@version
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :created_at, :data
|
23
|
+
|
24
|
+
# data is a Hash
|
25
|
+
def initialize(data = {})
|
26
|
+
@data = data
|
27
|
+
@created_at = Time.now
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_human
|
31
|
+
self.inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
# This causes the message to send itself over the server socket in server[:socket].
|
35
|
+
# "server" is the @server instance variable from the IB object.
|
36
|
+
# You can also use this to e.g. get the server version number.
|
37
|
+
#
|
38
|
+
# Subclasses can either override this method for precise control over how
|
39
|
+
# stuff gets sent to the server, or else define a method encode() that returns
|
40
|
+
# an Array of elements that ought to be sent to the server by calling to_s on
|
41
|
+
# each one and postpending a '\0'.
|
42
|
+
#
|
43
|
+
def send(server)
|
44
|
+
self.encode.flatten.each do |datum|
|
45
|
+
# TWS wants to receive booleans as 1 or 0... rewrite as necessary.
|
46
|
+
datum = "1" if datum == true
|
47
|
+
datum = "0" if datum == false
|
48
|
+
|
49
|
+
#print 'SENDING: '
|
50
|
+
#p datum
|
51
|
+
server[:socket].syswrite(datum.to_s + EOL)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# At minimum, Outgoing message contains message_id and version.
|
56
|
+
# Most messages also contain (ticker, request or order) :id.
|
57
|
+
def encode
|
58
|
+
[self.class.message_id,
|
59
|
+
self.class.version,
|
60
|
+
@data[:id] || []]
|
61
|
+
end
|
62
|
+
end # AbstractMessage
|
63
|
+
|
64
|
+
# Macro that defines short message classes using a one-liner
|
65
|
+
def self.def_message message_id, version=1, *keys
|
66
|
+
Class.new(AbstractMessage) do
|
67
|
+
@message_id = message_id
|
68
|
+
@version = version
|
69
|
+
|
70
|
+
define_method :encode do
|
71
|
+
[super(), keys.map { |key| @data[key] }]
|
72
|
+
end unless keys.empty?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
### Defining (short) Outgoing Message classes for IB:
|
77
|
+
|
78
|
+
# Empty messages (no data)
|
79
|
+
RequestOpenOrders = def_message 5
|
80
|
+
CancelNewsBulletins = def_message 13
|
81
|
+
RequestAllOpenOrders = def_message 16
|
82
|
+
RequestManagedAccounts = def_message 17
|
83
|
+
RequestScannerParameters = def_message 24
|
84
|
+
RequestCurrentTime = def_message 49
|
85
|
+
RequestGlobalCancel = def_message 58
|
86
|
+
|
87
|
+
# Data format is: @data = { :id => ticker_id}
|
88
|
+
CancelScannerSubscription = def_message 23
|
89
|
+
CancelMarketData = def_message 2
|
90
|
+
CancelHistoricalData = def_message 25
|
91
|
+
CancelRealTimeBars = def_message 51
|
92
|
+
CancelMarketDepth = def_message 11
|
93
|
+
|
94
|
+
# Data format is: @data = { :id => request_id }
|
95
|
+
CancelFundamentalData = def_message 53
|
96
|
+
CancelImpliedVolatility = def_message 56
|
97
|
+
CancelCalculateImpliedVolatility = CancelImpliedVolatility
|
98
|
+
CancelOptionPrice = def_message 57
|
99
|
+
CancelCalculateOptionPrice = CancelOptionPrice
|
100
|
+
|
101
|
+
# Data format is: @data ={ :id => order-id-to-cancel }
|
102
|
+
CancelOrder = def_message 4
|
103
|
+
|
104
|
+
# These messages contain just one or two keys, shown in the end of definition
|
105
|
+
# @data = { :number_of_ids => int }
|
106
|
+
RequestIds = def_message 8, 1, :number_of_ids
|
107
|
+
# data = { :all_messages => boolean }
|
108
|
+
RequestNewsBulletins = def_message 12, 1, :all_messages
|
109
|
+
# data = { :log_level => int }
|
110
|
+
SetServerLoglevel = def_message 14, 1, :log_level
|
111
|
+
# data = { :auto_bind => boolean }
|
112
|
+
RequestAutoOpenOrders = def_message 15, 1, :auto_bind
|
113
|
+
# data = { :fa_data_type => int }
|
114
|
+
RequestFA = def_message 18, 1, :fa_data_type
|
115
|
+
# data = { :fa_data_type => int, :xml => String }
|
116
|
+
ReplaceFA = def_message 19, 1, :fa_data_type, :xml
|
117
|
+
|
118
|
+
# Data is { :subscribe => boolean,
|
119
|
+
# :account_code => String: only necessary for advisor accounts. Set it
|
120
|
+
# to empty ('') for a standard account. }
|
121
|
+
class RequestAccountData < AbstractMessage
|
122
|
+
@message_id = 6
|
123
|
+
@version = 2
|
124
|
+
|
125
|
+
def encode
|
126
|
+
[super,
|
127
|
+
@data[:subscribe],
|
128
|
+
@data[:account_code] || '']
|
129
|
+
end
|
130
|
+
end
|
131
|
+
RequestAccountUpdates = RequestAccountData
|
132
|
+
|
133
|
+
|
134
|
+
### Defining (complex) Outgoing Message classes for IB:
|
135
|
+
|
136
|
+
# data = { :id => ticker_id (int), :subscription => ScannerSubscription}
|
137
|
+
class RequestScannerSubscription < AbstractMessage
|
138
|
+
@message_id = 22
|
139
|
+
@version = 3
|
140
|
+
|
141
|
+
def encode
|
142
|
+
[super,
|
143
|
+
@data[:subscription].number_of_rows || EOL,
|
144
|
+
@data[:subscription].instrument,
|
145
|
+
@data[:subscription].location_code,
|
146
|
+
@data[:subscription].scan_code,
|
147
|
+
@data[:subscription].above_price || EOL,
|
148
|
+
@data[:subscription].below_price || EOL,
|
149
|
+
@data[:subscription].above_volume || EOL,
|
150
|
+
@data[:subscription].market_cap_above || EOL,
|
151
|
+
@data[:subscription].market_cap_below || EOL,
|
152
|
+
@data[:subscription].moody_rating_above,
|
153
|
+
@data[:subscription].moody_rating_below,
|
154
|
+
@data[:subscription].sp_rating_above,
|
155
|
+
@data[:subscription].sp_rating_below,
|
156
|
+
@data[:subscription].maturity_date_above,
|
157
|
+
@data[:subscription].maturity_date_below,
|
158
|
+
@data[:subscription].coupon_rate_above || EOL,
|
159
|
+
@data[:subscription].coupon_rate_below || EOL,
|
160
|
+
@data[:subscription].exclude_convertible,
|
161
|
+
@data[:subscription].average_option_volume_above,
|
162
|
+
@data[:subscription].scanner_setting_pairs,
|
163
|
+
@data[:subscription].stock_type_filter
|
164
|
+
]
|
165
|
+
end
|
166
|
+
end # RequestScannerSubscription
|
167
|
+
|
168
|
+
# @data={:id => int: ticker_id - Must be a unique value. When the market data
|
169
|
+
# returns, it will be identified by this tag,
|
170
|
+
# :contract => Datatypes::Contract, requested contract.
|
171
|
+
# :tick_list => String: comma delimited list of requested tick groups:
|
172
|
+
# Group ID - Description - Requested Tick Types
|
173
|
+
# 100 - Option Volume (currently for stocks) - 29, 30
|
174
|
+
# 101 - Option Open Interest (currently for stocks) - 27, 28
|
175
|
+
# 104 - Historical Volatility (currently for stocks) - 23
|
176
|
+
# 106 - Option Implied Volatility (currently for stocks) - 24
|
177
|
+
# 162 - Index Future Premium - 31
|
178
|
+
# 165 - Miscellaneous Stats - 15, 16, 17, 18, 19, 20, 21
|
179
|
+
# 221 - Mark Price (used in TWS P&L computations) - 37
|
180
|
+
# 225 - Auction values (volume, price and imbalance) - 34, 35, 36
|
181
|
+
# 233 - RTVolume - 48
|
182
|
+
# 236 - Shortable - 46
|
183
|
+
# 256 - Inventory - ?
|
184
|
+
# 258 - Fundamental Ratios - 47
|
185
|
+
# 411 - Realtime Historical Volatility - 58
|
186
|
+
# :snapshot => bool: Check to return a single snapshot of market data and
|
187
|
+
# have the market data subscription canceled. Do not enter any
|
188
|
+
# :tick_list values if you use snapshot. }
|
189
|
+
class RequestMarketData < AbstractMessage
|
190
|
+
@message_id = 1
|
191
|
+
@version = 9 # message version number
|
192
|
+
|
193
|
+
def encode
|
194
|
+
tick_list = case @data[:tick_list]
|
195
|
+
when nil
|
196
|
+
''
|
197
|
+
when Array
|
198
|
+
@data[:tick_list].join ','
|
199
|
+
when String
|
200
|
+
@data[:tick_list]
|
201
|
+
end
|
202
|
+
[super,
|
203
|
+
@data[:contract].con_id, # part of serialize?
|
204
|
+
@data[:contract].serialize,
|
205
|
+
@data[:contract].serialize_combo_legs,
|
206
|
+
@data[:contract].serialize_under_comp,
|
207
|
+
tick_list,
|
208
|
+
@data[:snapshot] || false]
|
209
|
+
end
|
210
|
+
end # RequestMarketData
|
211
|
+
|
212
|
+
# data = { :id => int: Ticker id, needs to be different than the reqMktData ticker
|
213
|
+
# id. If you use the same ticker ID you used for the symbol when
|
214
|
+
# you did ReqMktData, nothing comes back for the historical data call
|
215
|
+
# :contract => Contract: requested ticker description
|
216
|
+
# :end_date_time => String: "yyyymmdd HH:mm:ss", with optional time zone
|
217
|
+
# allowed after a space: "20050701 18:26:44 GMT"
|
218
|
+
# :duration => String, time span the request will cover, and is specified
|
219
|
+
# using the format: <integer> <unit>, eg: '1 D', valid units are:
|
220
|
+
# '1 S' (seconds, default if no unit is specified)
|
221
|
+
# '1 D' (days)
|
222
|
+
# '1 W' (weeks)
|
223
|
+
# '1 M' (months)
|
224
|
+
# '1 Y' (years, currently limited to one)
|
225
|
+
# :bar_size => String: Specifies the size of the bars that will be returned
|
226
|
+
# (within IB/TWS limits). Valid values include:
|
227
|
+
# '1 sec'
|
228
|
+
# '5 secs'
|
229
|
+
# '15 secs'
|
230
|
+
# '30 secs'
|
231
|
+
# '1 min'
|
232
|
+
# '2 mins'
|
233
|
+
# '3 mins'
|
234
|
+
# '5 mins'
|
235
|
+
# '15 mins'
|
236
|
+
# '30 min'
|
237
|
+
# '1 hour'
|
238
|
+
# '1 day'
|
239
|
+
# :what_to_show => Symbol: one of :trades, :midpoint, :bid, or :ask -
|
240
|
+
# converts to "TRADES," "MIDPOINT," "BID," or "ASK."
|
241
|
+
# :use_rth => int: 0 - all data available during the time span requested
|
242
|
+
# is returned, even data bars covering time intervals where the
|
243
|
+
# market in question was illiquid. 1 - only data within the
|
244
|
+
# "Regular Trading Hours" of the product in question is returned,
|
245
|
+
# even if the time span requested falls partially or completely
|
246
|
+
# outside of them.
|
247
|
+
# :format_date => int: 1 - text format, like "20050307 11:32:16".
|
248
|
+
# 2 - offset in seconds from the beginning of 1970,
|
249
|
+
# which is the same format as the UNIX epoch time.
|
250
|
+
# }
|
251
|
+
#
|
252
|
+
# Note that as of 4/07 there is no historical data available for forex spot.
|
253
|
+
#
|
254
|
+
# data[:contract] may either be a Contract object or a String. A String should be
|
255
|
+
# in serialize_ib_ruby format; that is, it should be a colon-delimited string in
|
256
|
+
# the format (e.g. for Globex British pound futures contract expiring in Sep-2008):
|
257
|
+
#
|
258
|
+
# symbol:security_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
|
259
|
+
# GBP:FUT:200809:::62500:GLOBEX::USD:
|
260
|
+
#
|
261
|
+
# Fields not needed for a particular security should be left blank (e.g. strike
|
262
|
+
# and right are only relevant for options.)
|
263
|
+
#
|
264
|
+
# A Contract object will be automatically serialized into the required format.
|
265
|
+
#
|
266
|
+
# See also http://chuckcaplan.com/twsapi/index.php/void%20reqIntradayData%28%29
|
267
|
+
# for general information about how TWS handles historic data requests, whence
|
268
|
+
# the following has been adapted:
|
269
|
+
#
|
270
|
+
# The server providing historical prices appears to not always be
|
271
|
+
# available outside of market hours. If you call it outside of its
|
272
|
+
# supported time period, or if there is otherwise a problem with
|
273
|
+
# it, you will receive error #162 "Historical Market Data Service
|
274
|
+
# query failed.:HMDS query returned no data."
|
275
|
+
#
|
276
|
+
# For backfill on futures data, you may need to leave the Primary
|
277
|
+
# Exchange field of the Contract structure blank; see
|
278
|
+
# http://www.interactivebrokers.com/discus/messages/2/28477.html?1114646754
|
279
|
+
class RequestHistoricalData < AbstractMessage
|
280
|
+
@message_id = 20
|
281
|
+
@version = 4
|
282
|
+
|
283
|
+
def encode
|
284
|
+
if @data.has_key?(:what_to_show) && @data[:what_to_show].is_a?(String)
|
285
|
+
@data[:what_to_show] = @data[:what_to_show].downcase.to_sym
|
286
|
+
end
|
287
|
+
|
288
|
+
raise ArgumentError(":what_to_show must be one of #{DATA_TYPES}.") unless DATA_TYPES.include?(@data[:what_to_show])
|
289
|
+
raise ArgumentError(":bar_size must be one of #{BAR_SIZES}.") unless BAR_SIZES.include?(@data[:bar_size])
|
290
|
+
|
291
|
+
contract = @data[:contract].is_a?(Models::Contract) ?
|
292
|
+
@data[:contract] : Models::Contract.from_ib_ruby(@data[:contract])
|
293
|
+
|
294
|
+
[super,
|
295
|
+
contract.serialize,
|
296
|
+
contract.include_expired,
|
297
|
+
@data[:end_date_time],
|
298
|
+
@data[:bar_size],
|
299
|
+
@data[:duration],
|
300
|
+
@data[:use_rth],
|
301
|
+
@data[:what_to_show].to_s.upcase,
|
302
|
+
@data[:format_date],
|
303
|
+
contract.serialize_combo_legs]
|
304
|
+
end
|
305
|
+
end # RequestHistoricalData
|
306
|
+
|
307
|
+
# data = { :id => ticker_id (int),
|
308
|
+
# :contract => Contract ,
|
309
|
+
# :bar_size => int/Symbol? Currently only 5 second bars (2?) are supported,
|
310
|
+
# if any other value is used, an exception will be thrown.,
|
311
|
+
# :what_to_show => Symbol: one of :trades, :midpoint, :bid, or :ask -
|
312
|
+
# converts to "TRADES," "MIDPOINT," "BID," or "ASK."
|
313
|
+
# :use_rth => int: 0 - all data available during the time span requested
|
314
|
+
# is returned, even data bars covering time intervals where the
|
315
|
+
# market in question was illiquid. 1 - only data within the
|
316
|
+
# "Regular Trading Hours" of the product in question is returned,
|
317
|
+
# even if the time span requested falls partially or completely
|
318
|
+
# outside of them.
|
319
|
+
class RequestRealTimeBars < AbstractMessage
|
320
|
+
@message_id = 50
|
321
|
+
|
322
|
+
def encode
|
323
|
+
if @data.has_key?(:what_to_show) && @data[:what_to_show].is_a?(String)
|
324
|
+
@data[:what_to_show] = @data[:what_to_show].downcase.to_sym
|
325
|
+
end
|
326
|
+
|
327
|
+
raise ArgumentError(":what_to_show must be one of #{DATA_TYPES}.") unless DATA_TYPES.include?(@data[:what_to_show])
|
328
|
+
raise ArgumentError(":bar_size must be one of #{BAR_SIZES}.") unless BAR_SIZES.include?(@data[:bar_size])
|
329
|
+
|
330
|
+
contract = @data[:contract].is_a?(Models::Contract) ?
|
331
|
+
@data[:contract] : Models::Contract.from_ib_ruby(@data[:contract])
|
332
|
+
|
333
|
+
[super,
|
334
|
+
contract.serialize,
|
335
|
+
@data[:bar_size],
|
336
|
+
@data[:what_to_show].to_s.upcase,
|
337
|
+
@data[:use_rth]]
|
338
|
+
end
|
339
|
+
end # RequestRealTimeBars
|
340
|
+
|
341
|
+
# data => { :id => request_id (int), :contract => Contract }
|
342
|
+
class RequestContractData < AbstractMessage
|
343
|
+
@message_id = 9
|
344
|
+
@version = 6
|
345
|
+
|
346
|
+
def encode
|
347
|
+
[super,
|
348
|
+
@data[:contract].con_id, # part of serialize?
|
349
|
+
@data[:contract].serialize(:short),
|
350
|
+
@data[:contract].include_expired,
|
351
|
+
@data[:contract].sec_id_type,
|
352
|
+
@data[:contract].sec_id]
|
353
|
+
end
|
354
|
+
end # RequestContractData
|
355
|
+
RequestContractDetails = RequestContractData # alias
|
356
|
+
|
357
|
+
# data = { :id => ticker_id (int), :contract => Contract, :num_rows => int }
|
358
|
+
class RequestMarketDepth < AbstractMessage
|
359
|
+
@message_id = 10
|
360
|
+
@version = 3
|
361
|
+
|
362
|
+
def encode
|
363
|
+
[super,
|
364
|
+
@data[:contract].serialize(:short),
|
365
|
+
@data[:num_rows]]
|
366
|
+
end
|
367
|
+
end # RequestMarketDepth
|
368
|
+
|
369
|
+
# data = { :id => ticker_id (int),
|
370
|
+
# :contract => Contract,
|
371
|
+
# :exercise_action => int,
|
372
|
+
# :exercise_quantity => int,
|
373
|
+
# :account => string,
|
374
|
+
# :override => int } ## override? override what?
|
375
|
+
class ExerciseOptions < AbstractMessage
|
376
|
+
@message_id = 21
|
377
|
+
|
378
|
+
def encode
|
379
|
+
[super,
|
380
|
+
@data[:contract].serialize(:short),
|
381
|
+
@data[:exercise_action],
|
382
|
+
@data[:exercise_quantity],
|
383
|
+
@data[:account],
|
384
|
+
@data[:override]]
|
385
|
+
end
|
386
|
+
end # ExerciseOptions
|
387
|
+
|
388
|
+
# Data format is { :id => order_id (int), :contract => Contract, :order => Order }
|
389
|
+
class PlaceOrder < AbstractMessage
|
390
|
+
@message_id = 3
|
391
|
+
@version = 31
|
392
|
+
# int VERSION = (m_serverVersion < MIN_SERVER_VER_NOT_HELD) ? 27 : 31;
|
393
|
+
|
394
|
+
def encode
|
395
|
+
[super,
|
396
|
+
@data[:contract].serialize,
|
397
|
+
@data[:contract].sec_id_type, # Unimplemented?
|
398
|
+
@data[:contract].sec_id, # Unimplemented?
|
399
|
+
@data[:order].action, # send main order fields
|
400
|
+
@data[:order].total_quantity,
|
401
|
+
@data[:order].order_type,
|
402
|
+
@data[:order].limit_price,
|
403
|
+
@data[:order].aux_price,
|
404
|
+
@data[:order].tif, # send extended order fields
|
405
|
+
@data[:order].oca_group,
|
406
|
+
@data[:order].account,
|
407
|
+
@data[:order].open_close,
|
408
|
+
@data[:order].origin,
|
409
|
+
@data[:order].order_ref,
|
410
|
+
@data[:order].transmit,
|
411
|
+
@data[:order].parent_id,
|
412
|
+
@data[:order].block_order,
|
413
|
+
@data[:order].sweep_to_fill,
|
414
|
+
@data[:order].display_size,
|
415
|
+
@data[:order].trigger_method,
|
416
|
+
@data[:order].outside_rth, # was: ignore_rth
|
417
|
+
@data[:order].hidden,
|
418
|
+
@data[:contract].serialize_combo_legs(:long),
|
419
|
+
'', # send deprecated shares_allocation field
|
420
|
+
@data[:order].discretionary_amount,
|
421
|
+
@data[:order].good_after_time,
|
422
|
+
@data[:order].good_till_date,
|
423
|
+
@data[:order].fa_group,
|
424
|
+
@data[:order].fa_method,
|
425
|
+
@data[:order].fa_percentage,
|
426
|
+
@data[:order].fa_profile,
|
427
|
+
# Institutional short sale slot fields:
|
428
|
+
@data[:order].short_sale_slot, # 0 only for retail, 1 or 2 for institution
|
429
|
+
@data[:order].designated_location, # only populate when short_sale_slot == 2
|
430
|
+
@data[:order].oca_type,
|
431
|
+
@data[:order].rule_80a,
|
432
|
+
@data[:order].settling_firm,
|
433
|
+
@data[:order].all_or_none,
|
434
|
+
@data[:order].min_quantity || EOL,
|
435
|
+
@data[:order].percent_offset || EOL,
|
436
|
+
@data[:order].etrade_only,
|
437
|
+
@data[:order].firm_quote_only,
|
438
|
+
@data[:order].nbbo_price_cap || EOL,
|
439
|
+
@data[:order].auction_strategy || EOL,
|
440
|
+
@data[:order].starting_price || EOL,
|
441
|
+
@data[:order].stock_ref_price || EOL,
|
442
|
+
@data[:order].delta || EOL,
|
443
|
+
@data[:order].stock_range_lower || EOL,
|
444
|
+
@data[:order].stock_range_upper || EOL,
|
445
|
+
@data[:order].override_percentage_constraints,
|
446
|
+
@data[:order].volatility || EOL, # Volatility orders
|
447
|
+
@data[:order].volatility_type || EOL, # Volatility orders
|
448
|
+
@data[:order].delta_neutral_order_type, # Volatility orders
|
449
|
+
@data[:order].delta_neutral_aux_price || EOL, # Volatility orders
|
450
|
+
@data[:order].continuous_update, # Volatility orders
|
451
|
+
@data[:order].reference_price_type || EOL, # Volatility orders
|
452
|
+
@data[:order].trail_stop_price || EOL, # TRAIL_STOP_LIMIT stop price
|
453
|
+
@data[:order].scale_init_level_size || EOL, # Scale Orders
|
454
|
+
@data[:order].scale_subs_level_size || EOL, # Scale Orders
|
455
|
+
@data[:order].scale_price_increment || EOL, # Scale Orders
|
456
|
+
@data[:order].clearing_account,
|
457
|
+
@data[:order].clearing_intent,
|
458
|
+
@data[:order].not_held,
|
459
|
+
@data[:contract].serialize_under_comp,
|
460
|
+
@data[:contract].serialize_algo,
|
461
|
+
@data[:order].what_if]
|
462
|
+
end
|
463
|
+
end # PlaceOrder
|
464
|
+
|
465
|
+
# data = { :filter => ExecutionFilter ]
|
466
|
+
class RequestExecutions < AbstractMessage
|
467
|
+
@message_id = 7
|
468
|
+
@version = 3
|
469
|
+
|
470
|
+
def encode
|
471
|
+
[super,
|
472
|
+
@data[:filter].client_id,
|
473
|
+
@data[:filter].acct_code,
|
474
|
+
@data[:filter].time, # Valid format for time is "yyyymmdd-hh:mm:ss"
|
475
|
+
@data[:filter].symbol,
|
476
|
+
@data[:filter].sec_type,
|
477
|
+
@data[:filter].exchange,
|
478
|
+
@data[:filter].side]
|
479
|
+
end # encode
|
480
|
+
end # RequestExecutions
|
481
|
+
|
482
|
+
# data = { :request_id => int, :contract => Contract, :report_type => String }
|
483
|
+
class RequestFundamentalData < AbstractMessage
|
484
|
+
@message_id = 52
|
485
|
+
|
486
|
+
def encode
|
487
|
+
[super,
|
488
|
+
@data[:request_id],
|
489
|
+
@data[:contract].symbol, # Yet another Contract serialization!
|
490
|
+
@data[:contract].sec_type,
|
491
|
+
@data[:contract].exchange,
|
492
|
+
@data[:contract].primary_exchange,
|
493
|
+
@data[:contract].currency,
|
494
|
+
@data[:contract].local_symbol,
|
495
|
+
@data[:report_type]]
|
496
|
+
end
|
497
|
+
end # RequestFundamentalData
|
498
|
+
|
499
|
+
# data = { :request_id => int, :contract => Contract,
|
500
|
+
# :option_price => double, :under_price => double }
|
501
|
+
class RequestImpliedVolatility < AbstractMessage
|
502
|
+
@message_id = 54
|
503
|
+
|
504
|
+
def encode
|
505
|
+
[super,
|
506
|
+
@data[:request_id],
|
507
|
+
@data[:contract].con_id, # part of serialize?
|
508
|
+
@data[:contract].serialize,
|
509
|
+
@data[:option_price],
|
510
|
+
@data[:under_price]]
|
511
|
+
end
|
512
|
+
end # RequestImpliedVolatility
|
513
|
+
CalculateImpliedVolatility = RequestImpliedVolatility
|
514
|
+
RequestCalculateImpliedVolatility = RequestImpliedVolatility
|
515
|
+
|
516
|
+
# data = { :request_id => int, :contract => Contract,
|
517
|
+
# :volatility => double, :under_price => double }
|
518
|
+
class RequestOptionPrice < AbstractMessage
|
519
|
+
@message_id = 55
|
520
|
+
|
521
|
+
def encode
|
522
|
+
[super,
|
523
|
+
@data[:request_id],
|
524
|
+
@data[:contract].con_id, # part of serialize?
|
525
|
+
@data[:contract].serialize,
|
526
|
+
@data[:volatility],
|
527
|
+
@data[:under_price]]
|
528
|
+
end
|
529
|
+
end # RequestOptionPrice
|
530
|
+
CalculateOptionPrice = RequestOptionPrice
|
531
|
+
RequestCalculateOptionPrice = RequestOptionPrice
|
532
|
+
|
533
|
+
end # module Outgoing
|
534
|
+
end # module Messages
|
535
|
+
end # module IB
|
536
|
+
|
537
|
+
__END__
|
538
|
+
// outgoing msg id's
|
539
|
+
private static final int REQ_MKT_DATA = 1;
|
540
|
+
private static final int CANCEL_MKT_DATA = 2;
|
541
|
+
private static final int PLACE_ORDER = 3;
|
542
|
+
private static final int CANCEL_ORDER = 4;
|
543
|
+
private static final int REQ_OPEN_ORDERS = 5;
|
544
|
+
private static final int REQ_ACCOUNT_DATA = 6;
|
545
|
+
private static final int REQ_EXECUTIONS = 7;
|
546
|
+
private static final int REQ_IDS = 8;
|
547
|
+
private static final int REQ_CONTRACT_DATA = 9;
|
548
|
+
private static final int REQ_MKT_DEPTH = 10;
|
549
|
+
private static final int CANCEL_MKT_DEPTH = 11;
|
550
|
+
private static final int REQ_NEWS_BULLETINS = 12;
|
551
|
+
private static final int CANCEL_NEWS_BULLETINS = 13;
|
552
|
+
private static final int SET_SERVER_LOGLEVEL = 14;
|
553
|
+
private static final int REQ_AUTO_OPEN_ORDERS = 15;
|
554
|
+
private static final int REQ_ALL_OPEN_ORDERS = 16;
|
555
|
+
private static final int REQ_MANAGED_ACCTS = 17;
|
556
|
+
private static final int REQ_FA = 18;
|
557
|
+
private static final int REPLACE_FA = 19;
|
558
|
+
private static final int REQ_HISTORICAL_DATA = 20;
|
559
|
+
private static final int EXERCISE_OPTIONS = 21;
|
560
|
+
private static final int REQ_SCANNER_SUBSCRIPTION = 22;
|
561
|
+
private static final int CANCEL_SCANNER_SUBSCRIPTION = 23;
|
562
|
+
private static final int REQ_SCANNER_PARAMETERS = 24;
|
563
|
+
private static final int CANCEL_HISTORICAL_DATA = 25;
|
564
|
+
private static final int REQ_CURRENT_TIME = 49;
|
565
|
+
private static final int REQ_REAL_TIME_BARS = 50;
|
566
|
+
private static final int CANCEL_REAL_TIME_BARS = 51;
|
567
|
+
private static final int REQ_FUNDAMENTAL_DATA = 52;
|
568
|
+
private static final int CANCEL_FUNDAMENTAL_DATA = 53;
|
569
|
+
private static final int REQ_CALC_IMPLIED_VOLAT = 54;
|
570
|
+
private static final int REQ_CALC_OPTION_PRICE = 55;
|
571
|
+
private static final int CANCEL_CALC_IMPLIED_VOLAT = 56;
|
572
|
+
private static final int CANCEL_CALC_OPTION_PRICE = 57;
|
573
|
+
private static final int REQ_GLOBAL_CANCEL = 58;
|