ib-ruby 0.7.4 → 0.7.6
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/.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
|