ib-ruby 0.4.20 → 0.4.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This script downloads historic data for specific symbol from IB
4
- #
5
- # TODO: Fix the Historical command line client
6
-
7
- require 'pathname'
8
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
9
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
10
-
11
- require 'rubygems'
12
- require 'bundler/setup'
13
- require 'ib-ruby'
14
-
15
- ### Configurable Options
16
- Quiet = false # if Quiet == false, status data will be printed to STDERR
17
- Timeout = 10 # How long to wait when no messages are received from TWS before exiting, in seconds
18
- SymbolToRequest = IB::Symbols::Forex[:gbpusd]
19
-
20
- # Definition of what we want market data for. We have to keep track
21
- # of what ticker id corresponds to what symbol ourselves, because the
22
- # ticks don't include any other identifying information.
23
- #
24
- # The choice of ticker ids is, as far as I can tell, arbitrary.
25
- #
26
- # Note that as of 4/07 there is no historical data available for forex spot.
27
- #
28
- @market = {123 => SymbolToRequest}
29
-
30
- # To determine when the timeout has passed.
31
- @last_msg_time = Time.now.to_i + 2
32
-
33
- # Connect to IB TWS.
34
- ib = IB::IB.new
35
-
36
- # Uncomment this for verbose debug messages:
37
- # IB::IBLogger.level = Logger::Severity::DEBUG
38
-
39
- # Now, subscribe to HistoricalData incoming events. The code passed in the block
40
- # will be executed when a message of that type is received, with the received
41
- # message as its argument. In this case, we just print out the data.
42
- #
43
- # Note that we have to look the ticker id of each incoming message
44
- # up in local memory to figure out what it's for.
45
- #
46
- # (N.B. The description field is not from IB TWS. It is defined
47
- # locally in forex.rb, and is just arbitrary text.)
48
-
49
- ib.subscribe(IB::IncomingMessages::HistoricalData, lambda { |msg|
50
-
51
- STDERR.puts @market[msg.data[:req_id]].description + ": " + msg.data[:item_count].to_s("F") + " items:" unless Quiet
52
-
53
- msg.data[:history].each { |datum|
54
-
55
- @last_msg_time = Time.now.to_i
56
-
57
- STDERR.puts " " + datum.to_s("F") unless Quiet
58
- STDOUT.puts "#{datum.date},#{datum.open.to_s("F")},#{datum.high.to_s("F")},#{datum.low.to_s("F")},#{datum.close.to_s("F")},#{datum.volume}"
59
- }
60
- })
61
-
62
- # Now we actually request historical data for the symbols we're
63
- # interested in. TWS will respond with a HistoricalData message,
64
- # which will be received by the code above.
65
-
66
- @market.each_pair do |id, contract|
67
- msg = IB::OutgoingMessages::RequestHistoricalData.new(:ticker_id => id,
68
- :contract => contract,
69
- :end_date_time => Time.now.to_ib,
70
- :duration => (360).to_s, # how long before end_date_time to request in seconds - this means 1 day
71
- :bar_size => IB::OutgoingMessages::RequestHistoricalData::BarSizes.index(:hour),
72
- :what_to_show => :trades,
73
- :use_RTH => 0,
74
- :format_date => 2)
75
- ib.dispatch(msg)
76
- end
77
-
78
- while true
79
- exit(0) if Time.now.to_i > @last_msg_time + Timeout
80
- sleep 1
81
- end
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #
3
- # This script connects to IB API, subscribes to market data for specific symbols
4
-
5
- require 'rubygems'
6
- require 'pathname'
7
- require 'bundler/setup'
8
-
9
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
10
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
11
-
12
- require 'ib-ruby'
13
-
14
- # Definition of what we want market data for. We have to keep track
15
- # of what ticker id corresponds to what symbol ourselves, because the
16
- # ticks don't include any other identifying information.
17
- #
18
- # The choice of ticker ids is, as far as I can tell, arbitrary.
19
- #
20
- @market = {123 => IB::Symbols::Forex[:gbpusd],
21
- 456 => IB::Symbols::Forex[:eurusd],
22
- 789 => IB::Symbols::Forex[:usdcad]}
23
-
24
- # First, connect to IB TWS.
25
- ib = IB::IB.new
26
-
27
- # Now, subscribe to TickerPrice and TickerSize events. The code
28
- # passed in the block will be executed when a message of that type is
29
- # received, with the received message as its argument. In this case,
30
- # we just print out the tick.
31
- #
32
- # Note that we have to look the ticker id of each incoming message
33
- # up in local memory to figure out what it's for.
34
- #
35
- # (N.B. The description field is not from IB TWS. It is defined
36
- # locally in forex.rb, and is just arbitrary text.)
37
-
38
- ib.subscribe(IB::IncomingMessages::TickPrice, lambda { |msg|
39
- puts @market[msg.data[:ticker_id]].description + ": " + msg.to_human
40
- })
41
-
42
- ib.subscribe(IB::IncomingMessages::TickSize, lambda { |msg|
43
- puts @market[msg.data[:ticker_id]].description + ": " + msg.to_human
44
- })
45
-
46
-
47
- # Now we actually request market data for the symbols we're interested in.
48
-
49
- @market.each_pair { |id, contract|
50
- msg = IB::OutgoingMessages::RequestMarketData.new({
51
- :ticker_id => id,
52
- :contract => contract
53
- })
54
- ib.dispatch(msg)
55
- }
56
-
57
- puts "\nSubscribed to market data"
58
- puts "\n******** Press <Enter> to cancel... *********\n\n"
59
- gets
60
- puts "Cancelling market data subscription.."
61
-
62
- @market.each_pair { |id, contract|
63
- msg = IB::OutgoingMessages::CancelMarketData.new({
64
- :ticker_id => id,
65
- :contract => contract
66
- })
67
- ib.dispatch(msg)
68
- }
@@ -1,485 +0,0 @@
1
- #
2
- # Copyright (C) 2006 Blue Voodoo Magic LLC.
3
- #
4
- # This library is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU Lesser General Public License as
6
- # published by the Free Software Foundation; either version 2.1 of the
7
- # License, or (at your option) any later version.
8
- #
9
- # This library is distributed in the hope that it will be useful, but
10
- # WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
- # Lesser General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU Lesser General Public
15
- # License along with this library; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
- # 02110-1301 USA
18
- #
19
-
20
- #
21
- # TODO: Implement equals() according to the criteria in IB's Java client.
22
- #
23
-
24
- module IB
25
-
26
- module Datatypes
27
- attr_reader :created_at
28
-
29
- class AbstractDatum
30
-
31
- def init
32
- @created_at = Time.now
33
- end
34
-
35
- # If a hash is given, keys are taken as attribute names, values as data.
36
- # The attrs of the instance are set automatically from the attributeHash.
37
- #
38
- # If no hash is given, #init is called in the instance. #init
39
- # should set the datum up in a generic state.
40
- #
41
- def initialize(attributeHash=nil)
42
- if attributeHash.nil?
43
- init
44
- else
45
- raise ArgumentError.new("Argument must be a Hash") unless attributeHash.is_a?(Hash)
46
- attributeHash.keys.each { |key|
47
- self.send((key.to_s + "=").to_sym, attributeHash[key])
48
- }
49
- end
50
- end
51
- end # AbstractDatum
52
-
53
-
54
- # This is used within HistoricData messages.
55
- # Instantiate with a Hash of attributes, to be auto-set via initialize in AbstractDatum.
56
- class Bar < AbstractDatum
57
- attr_accessor :date, :open, :high, :low, :close, :volume, :wap, :has_gaps
58
- # :bar_count => @socket.read_int
59
-
60
- def to_s
61
- "<Bar: #{@date}; OHLC: #{@open.to_s}, #{@high.to_s}, #{@low.to_s}, #{@close.to_s}; volume: #{@volume}; wap: #{@wap.to_s}; has_gaps: #{@has_gaps}>"
62
- end
63
- end # Bar
64
-
65
-
66
- class Order < AbstractDatum
67
- # Constants used in Order objects. Drawn from Order.java
68
- Origin_Customer = 0
69
- Origin_Firm = 1
70
-
71
- Opt_Unknown = '?'
72
- Opt_Broker_Dealer = 'b'
73
- Opt_Customer = 'c'
74
- Opt_Firm = 'f'
75
- Opt_Isemm = 'm'
76
- Opt_Farmm = 'n'
77
- Opt_Specialist = 'y'
78
-
79
- OCA_Cancel_with_block = 1
80
- OCA_Reduce_with_block = 2
81
- OCA_Reduce_non_block = 3
82
-
83
- # Box orders consts:
84
- Box_Auction_Match = 1
85
- Box_Auction_Improvement = 2
86
- Box_Auction_Transparent = 3
87
-
88
- # Volatility orders consts:
89
- Volatility_Type_Daily = 1
90
- Volatility_Type_Annual = 2
91
- Volatility_Ref_Price_Average = 1
92
- Volatility_Ref_Price_BidOrAsk = 2
93
-
94
- # No idea why IB uses a large number as the default for some fields
95
- Max_Value = 99999999
96
-
97
- # Main order fields
98
- attr_accessor :id, # int m_orderId; ?
99
- :client_id, # int
100
- :perm_id, # int
101
- :action, # String
102
- :total_quantity, # int
103
- :order_type, # String
104
- :limit_price, # double
105
- :aux_price, # double
106
- #:shares_allocation, # deprecated sharesAllocation field
107
-
108
- # Extended order fields
109
- :tif, # String: Time in Force - DAY, GTC, etc.
110
- :oca_group, # String: one cancels all group name
111
- :oca_type, # 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK
112
- :order_ref, # String
113
- :transmit, # bool:if false, order will be created but not transmitted.
114
- :parent_id, # int: Parent order id, to associate auto STP or TRAIL orders with the original order.
115
- :block_order, # bool
116
- :sweep_to_fill, # bool
117
- :display_size, # int
118
- :trigger_method, # 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last,
119
- # 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point
120
- :outside_rth, # bool: WAS ignore_rth
121
- :hidden, # bool
122
- :good_after_time, # FORMAT: 20060505 08:00:00 {time zone}
123
- :good_till_date, # FORMAT: 20060505 08:00:00 {time zone}
124
- :override_percentage_constraints, # bool
125
- :rule_80a, # Individual = 'I', Agency = 'A', AgentOtherMember = 'W',
126
- # IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M',
127
- # IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N'
128
- :all_or_none, # bool
129
- :min_quantity, # int
130
- :percent_offset, # double: REL orders only
131
- :trail_stop_price, # double: for TRAILLIMIT orders only
132
-
133
- # Financial advisors only, all Strings
134
- :fa_group, :fa_profile, :fa_method, :fa_percentage,
135
-
136
- # Institutional orders only
137
- :open_close, # String: O=Open, C=Close
138
- :origin, # int: 0=Customer, 1=Firm
139
- :short_sale_slot, # 1 - you hold the shares, 2 - they will be delivered from elsewhere. Only for Action="SSHORT
140
- :designated_location, # String: set when slot==2 only
141
- :exempt_code, # int
142
-
143
- # SMART routing only
144
- :discretionary_amount, # double
145
- :etrade_only, # bool
146
- :firm_quote_only, # bool
147
- :nbbo_price_cap, # double
148
-
149
- # BOX or VOL ORDERS ONLY
150
- :auction_strategy, # 1=AUCTION_MATCH, 2=AUCTION_IMPROVEMENT, 3=AUCTION_TRANSPARENT
151
- :starting_price, # double, BOX ORDERS ONLY
152
- :stock_ref_price, # double, BOX ORDERS ONLY
153
- :delta, # double, BOX ORDERS ONLY
154
-
155
- # Pegged to stock or VOL orders
156
- :stock_range_lower, # double
157
- :stock_range_upper, # double
158
-
159
- # VOLATILITY ORDERS ONLY
160
- :volatility, # double
161
- :volatility_type, # int: 1=daily, 2=annual
162
- :continuous_update, # int
163
- :reference_price_type, # int: 1=Average, 2 = BidOrAsk
164
- :delta_neutral_order_type, # String
165
- :delta_neutral_aux_price, # double
166
-
167
- # COMBO ORDERS ONLY
168
- :basis_points, # double: EFP orders only
169
- :basis_points_type, # double: EFP orders only
170
-
171
- # SCALE ORDERS ONLY
172
- :scale_init_level_size, # int
173
- :scale_subs_level_size, # int
174
- :scale_price_increment, # double
175
-
176
- # Clearing info
177
- :account, # String: IB account
178
- :settling_firm, # String
179
- :clearing_account, # String: True beneficiary of the order
180
- :clearing_intent, # "" (Default), "IB", "Away", "PTA" (PostTrade)
181
-
182
- # ALGO ORDERS ONLY
183
- :algo_strategy, # String
184
- :algo_params, # public Vector<TagValue> m_algoParams; ?!
185
-
186
- # WTF?!
187
- :what_if, #public boolean m_whatIf; // What-if
188
- :not_held #public boolean m_notHeld; // Not Held
189
-
190
- def init
191
- super
192
-
193
- @open_close = "0"
194
- @origin = Origin_Customer
195
- @transmit = true
196
- @primary_exchange = ''
197
- @designated_location = ''
198
- @min_quantity = Max_Value # TODO: Initialize with nil instead of Max_Value, or change
199
- # Order sending code in IB::Messages::Outgoing::PlaceOrder
200
- @percent_offset = Max_Value # -"-
201
- @nbba_price_cap = Max_Value # -"-
202
- @starting_price = Max_Value # -"-
203
- @stock_ref_price = Max_Value # -"-
204
- @delta = Max_Value
205
- @delta_neutral_order_type = ''
206
- @delta_neutral_aux_price = Max_Value # -"-
207
- @reference_price_type = Max_Value # -"-
208
- end # init
209
-
210
- end # class Order
211
-
212
-
213
- class Contract < AbstractDatum
214
-
215
- # Valid security types (sec_type attribute)
216
- SECURITY_TYPES =
217
- {
218
- :stock => "STK",
219
- :option => "OPT",
220
- :future => "FUT",
221
- :index => "IND",
222
- :futures_option => "FOP",
223
- :forex => "CASH",
224
- :bag => "BAG"
225
- }
226
-
227
- # note that the :description field is entirely local to ib-ruby, and not part of TWS.
228
- # You can use it to store whatever arbitrary data you want.
229
- attr_accessor :symbol, :strike, :multiplier, :exchange, :currency,
230
- :local_symbol, :combo_legs, :description
231
-
232
- # Bond values
233
- attr_accessor(:cusip, :ratings, :desc_append, :bond_type, :coupon_type, :callable,
234
- :puttable, :coupon, :convertible, :maturity, :issue_date)
235
-
236
- attr_reader :sec_type, :expiry, :right, :primary_exchange
237
-
238
-
239
- # some protective filters
240
- def primary_exchange=(x)
241
- x.upcase! if x.is_a?(String)
242
-
243
- # per http://chuckcaplan.com/twsapi/index.php/Class%20Contract
244
- raise(ArgumentError.new("Don't set primary_exchange to smart")) if x == "SMART"
245
-
246
- @primary_exchange = x
247
- end
248
-
249
- def right=(x)
250
- x.upcase! if x.is_a?(String)
251
- x = nil if !x.nil? && x.empty?
252
- raise(ArgumentError.new("Invalid right \"#{x}\" (must be one of PUT, CALL, P, C)")) unless x.nil? || ["PUT", "CALL", "P", "C", "0"].include?(x)
253
- @right = x
254
- end
255
-
256
- def expiry=(x)
257
- x = x.to_s
258
- if (x.nil? || !(x =~ /\d{6,8}/)) and !x.empty? then
259
- raise ArgumentError.new("Invalid expiry \"#{x}\" (must be in format YYYYMM or YYYYMMDD)")
260
- end
261
- @expiry = x
262
- end
263
-
264
- def sec_type=(x)
265
- x = nil if !x.nil? && x.empty?
266
- raise(ArgumentError.new("Invalid security type \"#{x}\" (see SECURITY_TYPES constant in Contract class for valid types)")) unless x.nil? || SECURITY_TYPES.values.include?(x)
267
- @sec_type = x
268
- end
269
-
270
- def reset
271
- @combo_legs = Array.new
272
- @strike = 0
273
- end
274
-
275
- # This returns an Array of data from the given contract, in standard format.
276
- # Different messages serialize contracts differently. Go figure.
277
- # Note that it does not include the combo legs.
278
- def serialize(type = :long)
279
- [self.symbol,
280
- self.sec_type,
281
- self.expiry,
282
- self.strike,
283
- self.right,
284
- self.multiplier,
285
- self.exchange] +
286
- (type == :long ? [self.primary_exchange] : []) +
287
- [self.currency,
288
- self.local_symbol]
289
- end
290
-
291
- # @Legacy
292
- def serialize_long(version)
293
- serialize(:long)
294
- end
295
-
296
- # @Legacy
297
- def serialize_short(version)
298
- serialize(:short)
299
- end
300
-
301
- # This produces a string uniquely identifying this contract, in the format used
302
- # for command line arguments in the IB-Ruby examples. The format is:
303
- #
304
- # symbol:security_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
305
- #
306
- # Fields not needed for a particular security should be left blank
307
- # (e.g. strike and right are only relevant for options.)
308
- #
309
- # For example, to query the British pound futures contract trading on Globex
310
- # expiring in September, 2008, the string is:
311
- #
312
- # GBP:FUT:200809:::62500:GLOBEX::USD:
313
- def serialize_ib_ruby(version)
314
- serialize.join(":")
315
- end
316
-
317
- # This returns a Contract initialized from the serialize_ib_ruby format string.
318
- def self.from_ib_ruby(string)
319
- c = Contract.new
320
- c.symbol, c.sec_type, c.expiry, c.strike, c.right, c.multiplier,
321
- c.exchange, c.primary_exchange, c.currency, c.local_symbol = string.split(":")
322
- c
323
- end
324
-
325
- def serialize_under_comp(*args)
326
- raise "Unimplemented"
327
- # EClientSocket.java, line 471:
328
- #if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) {
329
- # if (contract.m_underComp != null) {
330
- # UnderComp underComp = contract.m_underComp;
331
- # send( true);
332
- # send( underComp.m_conId);
333
- # send( underComp.m_delta);
334
- # send( underComp.m_price);
335
- # }
336
- end
337
-
338
- def serialize_algo(*args)
339
- raise "Unimplemented"
340
- #if (m_serverVersion >= MIN_SERVER_VER_ALGO_ORDERS) {
341
- # send( order.m_algoStrategy);
342
- # if( !IsEmpty(order.m_algoStrategy)) {
343
- # java.util.Vector algoParams = order.m_algoParams;
344
- # int algoParamsCount = algoParams == null ? 0 : algoParams.size();
345
- # send( algoParamsCount);
346
- # if( algoParamsCount > 0) {
347
- # for( int i = 0; i < algoParamsCount; ++i) {
348
- # TagValue tagValue = (TagValue)algoParams.get(i);
349
- # send( tagValue.m_tag);
350
- # send( tagValue.m_value);
351
- # }
352
- # }
353
- # }
354
- #}
355
- end
356
-
357
- # Some messages send open_close too, some don't. WTF.
358
- def serialize_combo_legs(include_open_close = false)
359
- if self.combo_legs.nil?
360
- [0]
361
- else
362
- [self.combo_legs.size].concat(self.combo_legs.serialize(include_open_close))
363
- end
364
- end
365
-
366
- def init
367
- super
368
-
369
- @combo_legs = Array.new
370
- @strike = 0
371
- @sec_type = ''
372
- end
373
-
374
- def to_human
375
- "<IB-Contract: " + [symbol, expiry, sec_type, strike, right, exchange, currency].join("-") + "}>"
376
- end
377
-
378
- def to_short
379
- "#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
380
- end
381
-
382
- def to_s
383
- to_human
384
- end
385
-
386
- end # class Contract
387
-
388
- class ContractDetails < AbstractDatum
389
- attr_accessor :summary, :market_name, :trading_class, :con_id, :min_tick,
390
- :multiplier, :price_magnifier, :order_types, :valid_exchanges
391
-
392
- def init
393
- super
394
-
395
- @summary = Contract.new
396
- @con_id = 0
397
- @min_tick = 0
398
- end
399
- end # class ContractDetails
400
-
401
- class Execution < AbstractDatum
402
- attr_accessor :order_id, :client_id, :exec_id, :time, :account_number, :exchange,
403
- :side, :shares, :price, :perm_id, :liquidation
404
-
405
- def init
406
- super
407
-
408
- @order_id = 0
409
- @client_id = 0
410
- @shares = 0
411
- @price = 0
412
- @perm_id = 0
413
- @liquidation =0
414
- end
415
- end # Execution
416
-
417
- # From EClientSocket.java: Note that the valid format for m_time is "yyyymmdd-hh:mm:ss"
418
- class ExecutionFilter < AbstractDatum
419
- attr_accessor :client_id, :acct_code, :time, :symbol, :sec_type, :exchange, :side
420
-
421
- def init
422
- super
423
-
424
- @client_id = 0
425
- end
426
-
427
- end # ExecutionFilter
428
-
429
-
430
- class ComboLeg < AbstractDatum
431
- attr_accessor :con_id, :ratio, :action, :exchange, :open_close
432
-
433
- def init
434
- super
435
-
436
- @con_id = 0
437
- @ratio = 0
438
- @open_close = 0
439
- end
440
-
441
- # Some messages include open_close, some don't. wtf.
442
- def serialize(include_open_close = false)
443
- self.map { |leg|
444
- [leg.con_id,
445
- leg.ratio,
446
- leg.action,
447
- leg.exchange,
448
- (include_open_close ? leg.open_close : [])]
449
- }.flatten
450
- end
451
- end # ComboLeg
452
-
453
-
454
- class ScannerSubscription < AbstractDatum
455
-
456
- attr_accessor :number_of_rows, :instrument, :location_code, :scan_code, :above_price,
457
- :below_price, :above_volume, :average_option_volume_above,
458
- :market_cap_above, :market_cap_below, :moody_rating_above,
459
- :moody_rating_below, :sp_rating_above, :sp_rating_below,
460
- :maturity_date_above, :maturity_date_below, :coupon_rate_above,
461
- :coupon_rate_below, :exclude_convertible, :scanner_setting_pairs,
462
- :stock_type_filter
463
-
464
- def init
465
- super
466
-
467
- @coupon_rate_above = @coupon_rate_below = @market_cap_below = @market_cap_above =
468
- @average_option_volume_above = @above_volume = @below_price = @above_price = nil
469
- @number_of_rows = -1 # none specified, per ScannerSubscription.java
470
- end
471
- end # ScannerSubscription
472
-
473
-
474
- # Just like a Hash, but throws an exception if you try to access a key that doesn't exist.
475
- class StringentHash < Hash
476
- def initialize(hash)
477
- super() { |hash, key| raise Exception.new("key #{key.inspect} not found!") }
478
- self.merge!(hash) unless hash.nil?
479
- end
480
- end
481
-
482
- end # module Datatypes
483
- Models = Datatypes
484
-
485
- end # module
@@ -1,10 +0,0 @@
1
- require 'version'
2
-
3
- module IbRuby
4
- end # module IbRuby
5
-
6
- require 'ib-ruby/datatypes'
7
- require 'ib-ruby/ib'
8
- require 'ib-ruby/messages'
9
- require 'ib-ruby/symbols/forex'
10
- require 'ib-ruby/symbols/futures'