ib-ruby 0.7.4 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/HISTORY +8 -0
- data/README.md +2 -2
- data/Rakefile +15 -0
- data/TODO +7 -2
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +1 -1
- data/bin/contract_details +1 -1
- data/bin/depth_of_market +1 -1
- data/bin/fa_accounts +1 -1
- data/bin/fundamental_data +42 -0
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +1 -1
- data/bin/list_orders +1 -2
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +1 -1
- data/bin/place_order +1 -1
- data/bin/template +1 -4
- data/bin/tick_data +2 -2
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +4 -0
- data/lib/ib-ruby/connection.rb +50 -34
- data/lib/ib-ruby/constants.rb +232 -37
- data/lib/ib-ruby/db.rb +25 -0
- data/lib/ib-ruby/extensions.rb +51 -1
- data/lib/ib-ruby/messages/abstract_message.rb +0 -8
- data/lib/ib-ruby/messages/incoming.rb +18 -493
- data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
- data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
- data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
- data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
- data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
- data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
- data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
- data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
- data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
- data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
- data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
- data/lib/ib-ruby/messages/outgoing.rb +25 -223
- data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
- data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
- data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
- data/lib/ib-ruby/models.rb +4 -0
- data/lib/ib-ruby/models/bar.rb +31 -14
- data/lib/ib-ruby/models/combo_leg.rb +48 -23
- data/lib/ib-ruby/models/contracts.rb +2 -2
- data/lib/ib-ruby/models/contracts/bag.rb +11 -7
- data/lib/ib-ruby/models/contracts/contract.rb +90 -66
- data/lib/ib-ruby/models/contracts/option.rb +16 -7
- data/lib/ib-ruby/models/execution.rb +34 -18
- data/lib/ib-ruby/models/model.rb +15 -7
- data/lib/ib-ruby/models/model_properties.rb +101 -44
- data/lib/ib-ruby/models/order.rb +176 -187
- data/lib/ib-ruby/models/order_state.rb +99 -0
- data/lib/ib-ruby/symbols/forex.rb +10 -10
- data/lib/ib-ruby/symbols/futures.rb +6 -6
- data/lib/ib-ruby/symbols/stocks.rb +3 -3
- data/spec/account_helper.rb +4 -5
- data/spec/combo_helper.rb +4 -4
- data/spec/db.rb +18 -0
- data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
- data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
- data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
- data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
- data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
- data/spec/ib-ruby/models/bag_spec.rb +97 -0
- data/spec/ib-ruby/models/bar_spec.rb +45 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
- data/spec/ib-ruby/models/contract_spec.rb +134 -170
- data/spec/ib-ruby/models/execution_spec.rb +35 -50
- data/spec/ib-ruby/models/option_spec.rb +127 -0
- data/spec/ib-ruby/models/order_spec.rb +89 -68
- data/spec/ib-ruby/models/order_state_spec.rb +55 -0
- data/spec/integration/contract_info_spec.rb +4 -6
- data/spec/integration/fundamental_data_spec.rb +41 -0
- data/spec/integration/historic_data_spec.rb +4 -4
- data/spec/integration/market_data_spec.rb +1 -3
- data/spec/integration/orders/attached_spec.rb +8 -10
- data/spec/integration/orders/combo_spec.rb +2 -2
- data/spec/integration/orders/execution_spec.rb +0 -1
- data/spec/integration/orders/placement_spec.rb +1 -3
- data/spec/integration/orders/valid_ids_spec.rb +1 -2
- data/spec/message_helper.rb +1 -1
- data/spec/model_helper.rb +211 -0
- data/spec/order_helper.rb +44 -37
- data/spec/spec_helper.rb +36 -23
- data/spec/v.rb +7 -0
- data/tasks/doc.rake +1 -1
- metadata +116 -12
- data/spec/integration/orders/open_order +0 -98
data/lib/ib-ruby/constants.rb
CHANGED
@@ -5,41 +5,32 @@ module IB
|
|
5
5
|
|
6
6
|
# Enumeration of bar size types for convenience.
|
7
7
|
# Bar sizes less than 30 seconds do not work for some securities.
|
8
|
-
BAR_SIZES = {
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
BAR_SIZES = {'1 sec' => :sec1,
|
9
|
+
'5 secs' => :sec5,
|
10
|
+
'15 secs' =>:sec15,
|
11
|
+
'30 secs' =>:sec30,
|
12
|
+
'1 min' => :min1,
|
13
|
+
'2 mins' => :min2,
|
14
|
+
'3 mins' => :min3,
|
15
|
+
'5 mins' => :min5,
|
16
|
+
'15 mins' =>:min15,
|
17
|
+
'30 mins' =>:min30,
|
18
|
+
'1 hour' =>:hour1,
|
19
|
+
'1 day' => :day1
|
20
|
+
}.freeze
|
20
21
|
|
21
22
|
# Enumeration of data types.
|
22
23
|
# Determines the nature of data being extracted. Valid values:
|
23
|
-
DATA_TYPES = {
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
}
|
33
|
-
|
34
|
-
# Valid security types (sec_type attribute of IB::Contract)
|
35
|
-
SECURITY_TYPES = {:stock => "STK",
|
36
|
-
:option => "OPT",
|
37
|
-
:future => "FUT",
|
38
|
-
:index => "IND",
|
39
|
-
:futures_option => "FOP",
|
40
|
-
:forex => "CASH",
|
41
|
-
:bond => "BOND",
|
42
|
-
:bag => "BAG"}
|
24
|
+
DATA_TYPES = {'TRADES' => :trades,
|
25
|
+
'MIDPOINT' => :midpoint,
|
26
|
+
'BID' => :bid,
|
27
|
+
'ASK' => :ask,
|
28
|
+
'BID_ASK' => :bid_ask,
|
29
|
+
'HISTORICAL_VOLATILITY' => :historical_volatility,
|
30
|
+
'OPTION_IMPLIED_VOLATILITY' => :option_implied_volatility,
|
31
|
+
'OPTION_VOLUME' => :option_volume,
|
32
|
+
'OPTION_OPEN_INTEREST' => :option_open_interest
|
33
|
+
}.freeze
|
43
34
|
|
44
35
|
### These values are typically received from TWS in incoming messages
|
45
36
|
|
@@ -117,9 +108,17 @@ module IB
|
|
117
108
|
}
|
118
109
|
|
119
110
|
# Financial Advisor types (FaMsgTypeName)
|
120
|
-
FA_TYPES = {
|
121
|
-
|
122
|
-
|
111
|
+
FA_TYPES = {
|
112
|
+
1 => :groups,
|
113
|
+
2 => :profiles,
|
114
|
+
3 => :aliases}.freeze
|
115
|
+
|
116
|
+
# Received in new MarketDataType (58 incoming) message
|
117
|
+
MARKET_DATA_TYPES = {
|
118
|
+
0 => :unknown,
|
119
|
+
1 => :real_time,
|
120
|
+
2 => :frozen,
|
121
|
+
}
|
123
122
|
|
124
123
|
# Market depth messages contain these "operation" codes to tell you what to do with the data.
|
125
124
|
# See also http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/updatemktdepth.htm
|
@@ -127,10 +126,206 @@ module IB
|
|
127
126
|
0 => :insert, # New order, insert into the row identified by :position
|
128
127
|
1 => :update, # Update the existing order at the row identified by :position
|
129
128
|
2 => :delete # Delete the existing order at the row identified by :position
|
130
|
-
}
|
129
|
+
}.freeze
|
131
130
|
|
132
131
|
MARKET_DEPTH_SIDES = {
|
133
132
|
0 => :ask,
|
134
133
|
1 => :bid
|
135
|
-
}
|
134
|
+
}.freeze
|
135
|
+
|
136
|
+
ORDER_TYPES =
|
137
|
+
{'LMT' => :limit, # Limit Order
|
138
|
+
'LIT' => :limit_if_touched, # Limit if Touched
|
139
|
+
'LOC' => :limit_on_close, # Limit-on-Close LMTCLS ?
|
140
|
+
'LOO' => :limit_on_open, # Limit-on-Open
|
141
|
+
'MKT' => :market, # Market
|
142
|
+
'MIT' => :market_if_touched, # Market-if-Touched
|
143
|
+
'MOC' => :market_on_close, # Market-on-Close MKTCLSL ?
|
144
|
+
'MOO' => :market_on_open, # Market-on-Open
|
145
|
+
'MTL' => :market_to_limit, # Market-to-Limit
|
146
|
+
'MKTPRT' => :market_protected, # Market with Protection
|
147
|
+
'QUOTE' => :request_for_quote, # Request for Quote
|
148
|
+
'STP' => :stop, # Stop
|
149
|
+
'STPLMT' => :stop_limit, # Stop Limit
|
150
|
+
'TRAIL' => :trailing_stop, # Trailing Stop
|
151
|
+
'TRAIL LIMIT' => :trailing_limit, # Trailing Stop Limit
|
152
|
+
'TRAIL LIT' => :trailing_limit_if_touched, # Trailing Limit if Touched
|
153
|
+
'TRAIL MIT' => :trailing_market_if_touched, # Trailing Market If Touched
|
154
|
+
'PEG MKT' => :pegged_to_market, # Pegged-to-Market
|
155
|
+
'REL' => :relative, # Relative
|
156
|
+
'BOX TOP' => :box_top, # Box Top
|
157
|
+
'PEG MID' => :pegged_to_midpoint, # Pegged-to-Midpoint
|
158
|
+
'VWAP' => :vwap, # VWAP-Guaranteed
|
159
|
+
'OCA' => :one_cancels_all, # One-Cancels-All
|
160
|
+
'VOL' => :volatility, # Volatility
|
161
|
+
'SCALE' => :scale, # Scale
|
162
|
+
'NONE' => :no_order # Used to indicate no hedge in :delta_neutral_order_type
|
163
|
+
}.freeze
|
164
|
+
|
165
|
+
# Valid security types (sec_type attribute of IB::Contract)
|
166
|
+
SECURITY_TYPES =
|
167
|
+
{'STK' => :stock,
|
168
|
+
'OPT' => :option,
|
169
|
+
'FUT' => :future,
|
170
|
+
'IND' => :index,
|
171
|
+
'FOP' => :futures_option,
|
172
|
+
'CASH' => :forex,
|
173
|
+
'BOND' => :bond,
|
174
|
+
'BAG' => :bag}.freeze
|
175
|
+
|
176
|
+
# Obtain symbolic value from given property code:
|
177
|
+
# VALUES[:side]['B'] -> :buy
|
178
|
+
VALUES = {
|
179
|
+
:sec_type => SECURITY_TYPES,
|
180
|
+
:order_type => ORDER_TYPES,
|
181
|
+
:delta_neutral_order_type => ORDER_TYPES,
|
182
|
+
|
183
|
+
:origin => {0 => :customer, 1 => :firm},
|
184
|
+
:volatility_type => {1 => :daily, 2 => :annual},
|
185
|
+
:reference_price_type => {1 => :average, 2 => :bid_or_ask},
|
186
|
+
|
187
|
+
# This property encodes differently for ComboLeg and Order objects,
|
188
|
+
# we use ComboLeg codes and transcode for Order codes as needed
|
189
|
+
:open_close =>
|
190
|
+
{0 => :same, # Default for Legs, same as the parent (combo) security.
|
191
|
+
1 => :open, # Open. For Legs, this value is only used by institutions.
|
192
|
+
2 => :close, # Close. For Legs, this value is only used by institutions.
|
193
|
+
3 => :unknown}, # WTF
|
194
|
+
|
195
|
+
:right =>
|
196
|
+
{'' => :none, # Not an option
|
197
|
+
'P' => :put,
|
198
|
+
'C' => :call},
|
199
|
+
|
200
|
+
:side => # AKA action
|
201
|
+
{'B' => :buy, # or BOT
|
202
|
+
'S' => :sell, # or SLD
|
203
|
+
'T' => :short, # short
|
204
|
+
'X' => :short_exempt # Short Sale Exempt action. This allows some orders
|
205
|
+
# to be exempt from the SEC recent changes to Regulation SHO, which
|
206
|
+
# eliminated the old uptick rule and replaced it with a new "circuit breaker"
|
207
|
+
# rule, and allows some orders to be exempt from the new rule.
|
208
|
+
},
|
209
|
+
|
210
|
+
:short_sale_slot =>
|
211
|
+
{0 => :default, # The only valid option for retail customers
|
212
|
+
1 => :broker, # Shares are at your clearing broker, institutions
|
213
|
+
2 => :third_party}, # Shares will be delivered from elsewhere, institutions
|
214
|
+
|
215
|
+
:oca_type =>
|
216
|
+
{0 => :none, # Not a member of OCA group
|
217
|
+
1 => :cancel_with_block, # Cancel all remaining orders with block
|
218
|
+
2 => :reduce_with_block, # Remaining orders are reduced in size with block
|
219
|
+
3 => :reduce_no_block}, # Remaining orders are reduced in size with no block
|
220
|
+
|
221
|
+
:auction_strategy =>
|
222
|
+
{0 => :none, # Not a BOX order
|
223
|
+
1 => :match,
|
224
|
+
2 => :improvement,
|
225
|
+
3 => :transparent},
|
226
|
+
|
227
|
+
:trigger_method =>
|
228
|
+
{0 => :default, # "double bid/ask" used for OTC/US options, "last" otherswise.
|
229
|
+
1 => :double_bid_ask, # stops are triggered by 2 consecutive bid or ask prices.
|
230
|
+
2 => :last, # stops are triggered based on the last price.
|
231
|
+
3 => :double_last,
|
232
|
+
4 => :bid_ask, # bid >= trigger price for buy orders, ask <= trigger for sell orders
|
233
|
+
7 => :last_or_bid_ask, # bid OR last price >= trigger price for buy orders
|
234
|
+
8 => :mid_point}, # midpoint >= trigger price for buy orders and the
|
235
|
+
# spread between the bid and ask must be less than 0.1% of the midpoint
|
236
|
+
|
237
|
+
:hedge_type =>
|
238
|
+
{'D' => :delta, # parent order is an option and the child order is a stock
|
239
|
+
'B' => :beta, # offset market risk by entering into a position with
|
240
|
+
# another contract based on the system or user-defined beta
|
241
|
+
'F' => :forex, # offset risk with currency different from your base currency
|
242
|
+
'P' => :pair}, # trade a mis-valued pair of contracts and provide the
|
243
|
+
# ratio between the parent and hedging child order
|
244
|
+
|
245
|
+
:clearing_intent =>
|
246
|
+
{'' => :none,
|
247
|
+
'IB' => :ib,
|
248
|
+
'AWAY' => :away,
|
249
|
+
'PTA' => :post_trade_allocation},
|
250
|
+
|
251
|
+
:delta_neutral_clearing_intent =>
|
252
|
+
{'' => :none,
|
253
|
+
'IB' => :ib,
|
254
|
+
'AWAY' => :away,
|
255
|
+
'PTA' => :post_trade_allocation},
|
256
|
+
|
257
|
+
:tif =>
|
258
|
+
{'DAY' => :day,
|
259
|
+
'GAT' => :good_after_time,
|
260
|
+
'GTD' => :good_till_date,
|
261
|
+
'GTC' => :good_till_cancelled,
|
262
|
+
'IOC' => :immediate_or_cancel},
|
263
|
+
|
264
|
+
:rule_80a =>
|
265
|
+
{'I' => :individual,
|
266
|
+
'A' => :agency,
|
267
|
+
'W' => :agent_other_member,
|
268
|
+
'J' => :individual_ptia,
|
269
|
+
'U' => :agency_ptia,
|
270
|
+
'M' => :agent_other_member_ptia,
|
271
|
+
'K' => :individual_pt,
|
272
|
+
'Y' => :agency_pt,
|
273
|
+
'N' => :agent_other_member_pt},
|
274
|
+
|
275
|
+
:opt? => # TODO: unknown Order property, like OPT_BROKER_DEALER... in Order.java
|
276
|
+
{'?' => :unknown,
|
277
|
+
'b' => :broker_dealer,
|
278
|
+
'c' => :customer,
|
279
|
+
'f' => :firm,
|
280
|
+
'm' => :isemm,
|
281
|
+
'n' => :farmm,
|
282
|
+
'y' => :specialist},
|
283
|
+
|
284
|
+
}.freeze
|
285
|
+
|
286
|
+
# Obtain property code from given symbolic value:
|
287
|
+
# CODES[:side][:buy] -> 'B'
|
288
|
+
CODES = Hash[VALUES.map { |property, hash| [property, hash.invert] }]
|
289
|
+
|
290
|
+
# Most common property processors
|
291
|
+
PROPS = {:side =>
|
292
|
+
{:set => proc { |val| # BUY(BOT)/SELL(SLD)/SSHORT/SSHORTX
|
293
|
+
self[:side] = case val.to_s.upcase
|
294
|
+
when /SHORT.*X|^X$/
|
295
|
+
'X'
|
296
|
+
when /SHORT|^T$/
|
297
|
+
'T'
|
298
|
+
when /^B/
|
299
|
+
'B'
|
300
|
+
when /^S/
|
301
|
+
'S'
|
302
|
+
end },
|
303
|
+
:validate =>
|
304
|
+
{:format =>
|
305
|
+
{:with => /^buy$|^sell$|^short$|^short_exempt$/,
|
306
|
+
:message => "should be buy/sell/short"}
|
307
|
+
}
|
308
|
+
},
|
309
|
+
|
310
|
+
:open_close =>
|
311
|
+
{:set => proc { |val|
|
312
|
+
self[:open_close] = case val.to_s.upcase[0..0]
|
313
|
+
when 'S', '0' # SAME
|
314
|
+
0
|
315
|
+
when 'O', '1' # OPEN
|
316
|
+
1
|
317
|
+
when 'C', '2' # CLOSE
|
318
|
+
2
|
319
|
+
when 'U', '3' # Unknown
|
320
|
+
3
|
321
|
+
end
|
322
|
+
},
|
323
|
+
:validate =>
|
324
|
+
{:format =>
|
325
|
+
{:with => /^same$|^open$|^close$|^unknown$/,
|
326
|
+
:message => "should be same/open/close/unknown"}
|
327
|
+
},
|
328
|
+
}
|
329
|
+
}.freeze
|
330
|
+
|
136
331
|
end # module IB
|
data/lib/ib-ruby/db.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# By requiring this file, we make all IB:Models database-backed ActiveRecord subclasses
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module IB
|
6
|
+
module DB
|
7
|
+
|
8
|
+
def self.logger= logger
|
9
|
+
ActiveRecord::Base.logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
# Establish DB connection and do other plumbing here
|
13
|
+
def self.connect config
|
14
|
+
#log.warn "Starting Database connection"
|
15
|
+
ActiveRecord::Base.establish_connection(config)
|
16
|
+
#ActiveRecord.colorize_logging = false
|
17
|
+
|
18
|
+
# Get rid of nasty conversion issues
|
19
|
+
ActiveRecord::Base.default_timezone = :utc
|
20
|
+
Time.zone = 'UTC'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Load ActiveRecord::Schema ? where from ?
|
24
|
+
end # module DB
|
25
|
+
end
|
data/lib/ib-ruby/extensions.rb
CHANGED
@@ -1,11 +1,61 @@
|
|
1
|
-
# Add method to_ib to render datetime in IB format (zero padded "yyyymmdd HH:mm:ss")
|
2
1
|
class Time
|
2
|
+
# Render datetime in IB format (zero padded "yyyymmdd HH:mm:ss")
|
3
3
|
def to_ib
|
4
4
|
"#{year}#{sprintf("%02d", month)}#{sprintf("%02d", day)} " +
|
5
5
|
"#{sprintf("%02d", hour)}:#{sprintf("%02d", min)}:#{sprintf("%02d", sec)}"
|
6
6
|
end
|
7
7
|
end # Time
|
8
8
|
|
9
|
+
class Numeric
|
10
|
+
# Conversion 0/1 into true/false
|
11
|
+
def to_bool
|
12
|
+
self == 0 ? false : true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TrueClass
|
17
|
+
def to_bool
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class FalseClass
|
23
|
+
def to_bool
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class String
|
29
|
+
def to_bool
|
30
|
+
case self.chomp.upcase
|
31
|
+
when 'TRUE', 'T'
|
32
|
+
true
|
33
|
+
when 'FALSE', 'F', ''
|
34
|
+
false
|
35
|
+
else
|
36
|
+
error "Unable to convert #{self} to bool"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class NilClass
|
42
|
+
def to_bool
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Symbol
|
48
|
+
def to_f
|
49
|
+
0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Object
|
54
|
+
def to_sup
|
55
|
+
self.to_s.upcase
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
9
59
|
### Patching Object#error in ib-ruby/errors
|
10
60
|
# def error message, type=:standard
|
11
61
|
|
@@ -1,11 +1,3 @@
|
|
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
|
-
# TODO: realize Message#fire method that raises EWrapper events
|
8
|
-
|
9
1
|
module IB
|
10
2
|
module Messages
|
11
3
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'ib-ruby/messages/abstract_message'
|
1
|
+
require 'ib-ruby/messages/incoming/abstract_message'
|
2
2
|
|
3
3
|
# EClientSocket.java uses sendMax() rather than send() for a number of these.
|
4
4
|
# It sends an EOL rather than a number if the value == Integer.MAX_VALUE (or Double.MAX_VALUE).
|
@@ -15,144 +15,7 @@ module IB
|
|
15
15
|
module Incoming
|
16
16
|
extend Messages # def_message macros
|
17
17
|
|
18
|
-
|
19
|
-
Classes = {}
|
20
|
-
|
21
|
-
class AbstractMessage < IB::Messages::AbstractMessage
|
22
|
-
|
23
|
-
def version # Per message, received messages may have the different versions
|
24
|
-
@data[:version]
|
25
|
-
end
|
26
|
-
|
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
|
35
|
-
@created_at = Time.now
|
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
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def socket
|
52
|
-
@server[:socket]
|
53
|
-
end
|
54
|
-
|
55
|
-
# Every message loads received message version first
|
56
|
-
# Override the load method in your subclass to do actual reading into @data.
|
57
|
-
def load
|
58
|
-
@data[:version] = socket.read_int
|
59
|
-
|
60
|
-
check_version @data[:version], self.class.version
|
61
|
-
|
62
|
-
load_map *self.class.data_map
|
63
|
-
end
|
64
|
-
|
65
|
-
# Load @data from the socket according to the given data map.
|
66
|
-
#
|
67
|
-
# map is a series of Arrays in the format of
|
68
|
-
# [ :name, :type ], [ :group, :name, :type]
|
69
|
-
# type identifiers must have a corresponding read_type method on socket (read_int, etc.).
|
70
|
-
# group is used to lump together aggregates, such as Contract or Order fields
|
71
|
-
def load_map(*map)
|
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}"
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# class AbstractMessage
|
110
|
-
|
111
|
-
### Actual message classes (short definitions):
|
112
|
-
|
113
|
-
# :status - String: Displays the order status. Possible values include:
|
114
|
-
# � PendingSubmit - indicates that you have transmitted the order, but
|
115
|
-
# have not yet received confirmation that it has been accepted by the
|
116
|
-
# order destination. NOTE: This order status is NOT sent back by TWS
|
117
|
-
# and should be explicitly set by YOU when an order is submitted.
|
118
|
-
# � PendingCancel - indicates that you have sent a request to cancel
|
119
|
-
# the order but have not yet received cancel confirmation from the
|
120
|
-
# order destination. At this point, your order cancel is not confirmed.
|
121
|
-
# You may still receive an execution while your cancellation request
|
122
|
-
# is pending. NOTE: This order status is not sent back by TWS and
|
123
|
-
# should be explicitly set by YOU when an order is canceled.
|
124
|
-
# � PreSubmitted - indicates that a simulated order type has been
|
125
|
-
# accepted by the IB system and that this order has yet to be elected.
|
126
|
-
# The order is held in the IB system until the election criteria are
|
127
|
-
# met. At that time the order is transmitted to the order destination
|
128
|
-
# as specified.
|
129
|
-
# � Submitted - indicates that your order has been accepted at the order
|
130
|
-
# destination and is working.
|
131
|
-
# � Cancelled - indicates that the balance of your order has been
|
132
|
-
# confirmed canceled by the IB system. This could occur unexpectedly
|
133
|
-
# when IB or the destination has rejected your order.
|
134
|
-
# � Filled - indicates that the order has been completely filled.
|
135
|
-
# � Inactive - indicates that the order has been accepted by the system
|
136
|
-
# (simulated orders) or an exchange (native orders) but that currently
|
137
|
-
# the order is inactive due to system, exchange or other issues.
|
138
|
-
# :why_held - This field is used to identify an order held when TWS is trying to
|
139
|
-
# locate shares for a short sell. The value used to indicate this is 'locate'.
|
140
|
-
OrderStatus = def_message [3, 6], [:order_id, :int],
|
141
|
-
[:status, :string],
|
142
|
-
[:filled, :int],
|
143
|
-
[:remaining, :int],
|
144
|
-
[:average_fill_price, :decimal],
|
145
|
-
[:perm_id, :int],
|
146
|
-
[:parent_id, :int],
|
147
|
-
[:last_fill_price, :decimal],
|
148
|
-
[:client_id, :int],
|
149
|
-
[:why_held, :string] do
|
150
|
-
"<OrderStatus: #{status} filled: #{filled}/#{remaining + filled}" +
|
151
|
-
" @ last/avg: #{last_fill_price}/#{average_fill_price}" +
|
152
|
-
(parent_id > 0 ? " parent_id: #{parent_id}" : "") +
|
153
|
-
(why_held != "" ? " why_held: #{why_held}" : "") +
|
154
|
-
" id/perm: #{order_id}/#{perm_id}>"
|
155
|
-
end
|
18
|
+
### Define short message classes in-line:
|
156
19
|
|
157
20
|
AccountValue = def_message([6, 2], [:key, :string],
|
158
21
|
[:value, :string],
|
@@ -184,9 +47,7 @@ module IB
|
|
184
47
|
ReceiveFA =
|
185
48
|
def_message 16, [:type, :int], # type of Financial Advisor configuration data
|
186
49
|
# being received from TWS. Valid values include:
|
187
|
-
#
|
188
|
-
# 2 = PROFILE
|
189
|
-
# 3 = ACCOUNT ALIASES
|
50
|
+
# 1 = GROUPS, 2 = PROFILE, 3 = ACCOUNT ALIASES
|
190
51
|
[:xml, :string] # XML string with requested FA configuration information.
|
191
52
|
|
192
53
|
# Receives an XML document that describes the valid parameters that a scanner
|
@@ -198,7 +59,7 @@ module IB
|
|
198
59
|
|
199
60
|
# Receive Reuters global fundamental market data. There must be a subscription to
|
200
61
|
# Reuters Fundamental set up in Account Management before you can receive this data.
|
201
|
-
FundamentalData = def_message
|
62
|
+
FundamentalData = def_message 51, [:request_id, :int], [:data, :string]
|
202
63
|
|
203
64
|
ContractDataEnd = def_message 52, [:request_id, :int]
|
204
65
|
|
@@ -218,361 +79,25 @@ module IB
|
|
218
79
|
[:yield, :decimal],
|
219
80
|
[:yield_redemption_date, :int]
|
220
81
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
def operation
|
237
|
-
@data[:operation] == 0 ? :insert : @data[:operation] == 1 ? :update : :delete
|
238
|
-
end
|
239
|
-
|
240
|
-
def to_human
|
241
|
-
"<#{self.message_type}: #{operation} #{side} @ "+
|
242
|
-
"#{position} = #{price} x #{size}>"
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
MarketDepthL2 =
|
247
|
-
def_message 13, MarketDepth, # Fields descriptions - see above
|
248
|
-
[:request_id, :int],
|
249
|
-
[:position, :int],
|
250
|
-
[:market_maker, :string], # The exchange hosting this order.
|
251
|
-
[:operation, :int],
|
252
|
-
[:side, :int],
|
253
|
-
[:price, :decimal],
|
254
|
-
[:size, :int]
|
255
|
-
|
256
|
-
# Called Error in Java code, but in fact this type of messages also
|
257
|
-
# deliver system alerts and additional (non-error) info from TWS.
|
258
|
-
ErrorMessage = Error = Alert = def_message([4, 2],
|
259
|
-
[:error_id, :int],
|
260
|
-
[:code, :int],
|
261
|
-
[:message, :string])
|
262
|
-
class Alert
|
263
|
-
# Is it an Error message?
|
264
|
-
def error?
|
265
|
-
code < 1000
|
266
|
-
end
|
267
|
-
|
268
|
-
# Is it a System message?
|
269
|
-
def system?
|
270
|
-
code > 1000 && code < 2000
|
271
|
-
end
|
272
|
-
|
273
|
-
# Is it a Warning message?
|
274
|
-
def warning?
|
275
|
-
code > 2000
|
276
|
-
end
|
277
|
-
|
278
|
-
def to_human
|
279
|
-
"TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'} #{code}: #{message}"
|
280
|
-
end
|
281
|
-
end # class Alert
|
282
|
-
|
283
|
-
PortfolioValue = def_message [7, 7],
|
284
|
-
[:contract, :con_id, :int],
|
285
|
-
[:contract, :symbol, :string],
|
286
|
-
[:contract, :sec_type, :string],
|
287
|
-
[:contract, :expiry, :string],
|
288
|
-
[:contract, :strike, :decimal],
|
289
|
-
[:contract, :right, :string],
|
290
|
-
[:contract, :multiplier, :string],
|
291
|
-
[:contract, :primary_exchange, :string],
|
292
|
-
[:contract, :currency, :string],
|
293
|
-
[:contract, :local_symbol, :string],
|
294
|
-
[:position, :int],
|
295
|
-
[:market_price, :decimal],
|
296
|
-
[:market_value, :decimal],
|
297
|
-
[:average_cost, :decimal],
|
298
|
-
[:unrealized_pnl, :decimal_max], # May be nil!
|
299
|
-
[:realized_pnl, :decimal_max], # May be nil!
|
300
|
-
[:account_name, :string]
|
301
|
-
class PortfolioValue
|
302
|
-
|
303
|
-
def load
|
304
|
-
super
|
305
|
-
@contract = IB::Contract.build @data[:contract]
|
306
|
-
end
|
307
|
-
|
308
|
-
def to_human
|
309
|
-
"<PortfolioValue: #{contract.to_human} (#{position}): Market #{market_price}" +
|
310
|
-
" price #{market_value} value; PnL: #{unrealized_pnl} unrealized," +
|
311
|
-
" #{realized_pnl} realized; account #{account_name}>"
|
312
|
-
end
|
313
|
-
end # PortfolioValue
|
314
|
-
|
315
|
-
ContractDetails = ContractData =
|
316
|
-
def_message([10, 6],
|
317
|
-
[:request_id, :int], # request id
|
318
|
-
[:contract, :symbol, :string],
|
319
|
-
[:contract, :sec_type, :string],
|
320
|
-
[:contract, :expiry, :string],
|
321
|
-
[:contract, :strike, :decimal],
|
322
|
-
[:contract, :right, :string],
|
323
|
-
[:contract, :exchange, :string],
|
324
|
-
[:contract, :currency, :string],
|
325
|
-
[:contract, :local_symbol, :string],
|
326
|
-
|
327
|
-
[:contract, :market_name, :string], # extended
|
328
|
-
[:contract, :trading_class, :string],
|
329
|
-
[:contract, :con_id, :int],
|
330
|
-
[:contract, :min_tick, :decimal],
|
331
|
-
[:contract, :multiplier, :string],
|
332
|
-
[:contract, :order_types, :string],
|
333
|
-
[:contract, :valid_exchanges, :string],
|
334
|
-
[:contract, :price_magnifier, :int],
|
335
|
-
[:contract, :under_con_id, :int],
|
336
|
-
[:contract, :long_name, :string],
|
337
|
-
[:contract, :primary_exchange, :string],
|
338
|
-
[:contract, :contract_month, :string],
|
339
|
-
[:contract, :industry, :string],
|
340
|
-
[:contract, :category, :string],
|
341
|
-
[:contract, :subcategory, :string],
|
342
|
-
[:contract, :time_zone, :string],
|
343
|
-
[:contract, :trading_hours, :string],
|
344
|
-
[:contract, :liquid_hours, :string])
|
345
|
-
|
346
|
-
class ContractData
|
347
|
-
def load
|
348
|
-
super
|
349
|
-
@contract = IB::Contract.build @data[:contract]
|
350
|
-
end
|
351
|
-
end # ContractData
|
352
|
-
|
353
|
-
ExecutionData =
|
354
|
-
def_message [11, 8],
|
355
|
-
# The reqID that was specified previously in the call to reqExecution()
|
356
|
-
[:request_id, :int],
|
357
|
-
[:execution, :order_id, :int],
|
358
|
-
[:contract, :con_id, :int],
|
359
|
-
[:contract, :symbol, :string],
|
360
|
-
[:contract, :sec_type, :string],
|
361
|
-
[:contract, :expiry, :string],
|
362
|
-
[:contract, :strike, :decimal],
|
363
|
-
[:contract, :right, :string],
|
364
|
-
[:contract, :exchange, :string],
|
365
|
-
[:contract, :currency, :string],
|
366
|
-
[:contract, :local_symbol, :string],
|
367
|
-
|
368
|
-
[:execution, :exec_id, :string], # Weird format
|
369
|
-
[:execution, :time, :string],
|
370
|
-
[:execution, :account_name, :string],
|
371
|
-
[:execution, :exchange, :string],
|
372
|
-
[:execution, :side, :string],
|
373
|
-
[:execution, :shares, :int],
|
374
|
-
[:execution, :price, :decimal],
|
375
|
-
[:execution, :perm_id, :int],
|
376
|
-
[:execution, :client_id, :int],
|
377
|
-
[:execution, :liquidation, :int],
|
378
|
-
[:execution, :cumulative_quantity, :int],
|
379
|
-
[:execution, :average_price, :decimal]
|
380
|
-
|
381
|
-
class ExecutionData
|
382
|
-
def load
|
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
|
-
]
|
389
|
-
@contract = IB::Contract.build @data[:contract]
|
390
|
-
@execution = IB::Execution.new @data[:execution]
|
391
|
-
end
|
392
|
-
|
393
|
-
def to_human
|
394
|
-
"<ExecutionData #{request_id}: #{contract.to_human}, #{execution}>"
|
395
|
-
end
|
396
|
-
|
397
|
-
end # ExecutionData
|
398
|
-
|
399
|
-
BondContractData =
|
400
|
-
def_message [18, 4],
|
401
|
-
[:request_id, :int],
|
402
|
-
[:contract, :symbol, :string],
|
403
|
-
[:contract, :sec_type, :string],
|
404
|
-
[:contract, :cusip, :string],
|
405
|
-
[:contract, :coupon, :decimal],
|
406
|
-
[:contract, :maturity, :string],
|
407
|
-
[:contract, :issue_date, :string],
|
408
|
-
[:contract, :ratings, :string],
|
409
|
-
[:contract, :bond_type, :string],
|
410
|
-
[:contract, :coupon_type, :string],
|
411
|
-
[:contract, :convertible, :boolean],
|
412
|
-
[:contract, :callable, :boolean],
|
413
|
-
[:contract, :puttable, :boolean],
|
414
|
-
[:contract, :desc_append, :string],
|
415
|
-
[:contract, :exchange, :string],
|
416
|
-
[:contract, :currency, :string],
|
417
|
-
[:contract, :market_name, :string], # extended
|
418
|
-
[:contract, :trading_class, :string],
|
419
|
-
[:contract, :con_id, :int],
|
420
|
-
[:contract, :min_tick, :decimal],
|
421
|
-
[:contract, :order_types, :string],
|
422
|
-
[:contract, :valid_exchanges, :string],
|
423
|
-
[:contract, :valid_next_option_date, :string],
|
424
|
-
[:contract, :valid_next_option_type, :string],
|
425
|
-
[:contract, :valid_next_option_partial, :string],
|
426
|
-
[:contract, :notes, :string],
|
427
|
-
[:contract, :long_name, :string]
|
428
|
-
|
429
|
-
class BondContractData
|
430
|
-
def load
|
431
|
-
super
|
432
|
-
@contract = IB::Contract.build @data[:contract]
|
433
|
-
end
|
434
|
-
end # BondContractData
|
435
|
-
|
436
|
-
# The server sends this message upon accepting a Delta-Neutral DN RFQ
|
437
|
-
# - see API Reference p. 26
|
438
|
-
DeltaNeutralValidation = def_message 56,
|
439
|
-
[:request_id, :int],
|
440
|
-
[:contract, :under_con_id, :int],
|
441
|
-
[:contract, :under_delta, :decimal],
|
442
|
-
[:contract, :under_price, :decimal]
|
443
|
-
class DeltaNeutralValidation
|
444
|
-
def load
|
445
|
-
super
|
446
|
-
@contract = IB::Contract.build @data[:contract].merge(:under_comp => true)
|
447
|
-
end
|
448
|
-
end # DeltaNeutralValidation
|
449
|
-
|
450
|
-
# RealTimeBar contains following @data:
|
451
|
-
# :request_id - The ID of the *request* to which this is responding
|
452
|
-
# :time - The date-time stamp of the start of the bar. The format is offset in
|
453
|
-
# seconds from the beginning of 1970, same format as the UNIX epoch time
|
454
|
-
# :bar - received RT Bar
|
455
|
-
RealTimeBar = def_message 50,
|
456
|
-
[:request_id, :int],
|
457
|
-
[:bar, :time, :int],
|
458
|
-
[:bar, :open, :decimal],
|
459
|
-
[:bar, :high, :decimal],
|
460
|
-
[:bar, :low, :decimal],
|
461
|
-
[:bar, :close, :decimal],
|
462
|
-
[:bar, :volume, :int],
|
463
|
-
[:bar, :wap, :decimal],
|
464
|
-
[:bar, :trades, :int]
|
465
|
-
class RealTimeBar
|
466
|
-
def load
|
467
|
-
super
|
468
|
-
@bar = IB::Bar.new @data[:bar]
|
469
|
-
end
|
470
|
-
|
471
|
-
def to_human
|
472
|
-
"<RealTimeBar: #{request_id} #{time}, #{bar}>"
|
473
|
-
end
|
474
|
-
end # RealTimeBar
|
475
|
-
|
476
|
-
### Messages with really complicated message loading logics (cycles, conditions)
|
477
|
-
|
478
|
-
# This method receives the requested market scanner data results.
|
479
|
-
# ScannerData contains following @data:
|
480
|
-
# :request_id - The ID of the request to which this row is responding
|
481
|
-
# :count - Number of data points returned (size of :results).
|
482
|
-
# :results - an Array of Hashes, each hash contains a set of
|
483
|
-
# data about one scanned Contract:
|
484
|
-
# :contract - a full description of the contract (details).
|
485
|
-
# :distance - Varies based on query.
|
486
|
-
# :benchmark - Varies based on query.
|
487
|
-
# :projection - Varies based on query.
|
488
|
-
# :legs - Describes combo legs when scan is returning EFP.
|
489
|
-
ScannerData = def_message [20, 3],
|
490
|
-
[:request_id, :int], # request id
|
491
|
-
[:count, :int]
|
492
|
-
class ScannerData
|
493
|
-
attr_accessor :results
|
494
|
-
|
495
|
-
def load
|
496
|
-
super
|
497
|
-
|
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,
|
515
|
-
}
|
516
|
-
end
|
517
|
-
end
|
518
|
-
end # ScannerData
|
519
|
-
|
520
|
-
# HistoricalData contains following @data:
|
521
|
-
# General:
|
522
|
-
# :request_id - The ID of the request to which this is responding
|
523
|
-
# :count - Number of Historical data points returned (size of :results).
|
524
|
-
# :results - an Array of Historical Data Bars
|
525
|
-
# :start_date - beginning of returned Historical data period
|
526
|
-
# :end_date - end of returned Historical data period
|
527
|
-
# Each returned Bar in @data[:results] Array contains this data:
|
528
|
-
# :date - The date-time stamp of the start of the bar. The format is
|
529
|
-
# determined by the RequestHistoricalData formatDate parameter.
|
530
|
-
# :open - The bar opening price.
|
531
|
-
# :high - The high price during the time covered by the bar.
|
532
|
-
# :low - The low price during the time covered by the bar.
|
533
|
-
# :close - The bar closing price.
|
534
|
-
# :volume - The volume during the time covered by the bar.
|
535
|
-
# :trades - When TRADES historical data is returned, represents number of trades
|
536
|
-
# that occurred during the time period the bar covers
|
537
|
-
# :wap - The weighted average price during the time covered by the bar.
|
538
|
-
# :has_gaps - Whether or not there are gaps in the data.
|
539
|
-
|
540
|
-
HistoricalData = def_message [17, 3],
|
541
|
-
[:request_id, :int],
|
542
|
-
[:start_date, :string],
|
543
|
-
[:end_date, :string],
|
544
|
-
[:count, :int]
|
545
|
-
class HistoricalData
|
546
|
-
attr_accessor :results
|
547
|
-
|
548
|
-
def load
|
549
|
-
super
|
550
|
-
|
551
|
-
@results = Array.new(@data[:count]) do |_|
|
552
|
-
IB::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
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
def to_human
|
565
|
-
"<HistoricalData: #{request_id}, #{count} items, #{start_date} to #{end_date}>"
|
566
|
-
end
|
567
|
-
end # HistoricalData
|
82
|
+
### Require standalone source files for more complex message classes:
|
83
|
+
|
84
|
+
require 'ib-ruby/messages/incoming/alert'
|
85
|
+
require 'ib-ruby/messages/incoming/contract_data'
|
86
|
+
require 'ib-ruby/messages/incoming/delta_neutral_validation'
|
87
|
+
require 'ib-ruby/messages/incoming/execution_data'
|
88
|
+
require 'ib-ruby/messages/incoming/historical_data'
|
89
|
+
require 'ib-ruby/messages/incoming/market_depths'
|
90
|
+
require 'ib-ruby/messages/incoming/open_order'
|
91
|
+
require 'ib-ruby/messages/incoming/order_status'
|
92
|
+
require 'ib-ruby/messages/incoming/portfolio_value'
|
93
|
+
require 'ib-ruby/messages/incoming/real_time_bar'
|
94
|
+
require 'ib-ruby/messages/incoming/scanner_data'
|
95
|
+
require 'ib-ruby/messages/incoming/ticks'
|
568
96
|
|
569
97
|
end # module Incoming
|
570
98
|
end # module Messages
|
571
99
|
end # module IB
|
572
100
|
|
573
|
-
# Require standalone message source files
|
574
|
-
require 'ib-ruby/messages/incoming/ticks'
|
575
|
-
require 'ib-ruby/messages/incoming/open_order'
|
576
101
|
|
577
102
|
__END__
|
578
103
|
// incoming msg id's
|