ib-ruby 0.4.3 → 0.4.20

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.
Files changed (50) hide show
  1. data/.gitignore +32 -0
  2. data/HISTORY +68 -0
  3. data/README.rdoc +9 -6
  4. data/VERSION +1 -1
  5. data/bin/account_info +29 -0
  6. data/bin/contract_details +37 -0
  7. data/bin/depth_of_market +43 -0
  8. data/bin/historic_data +62 -0
  9. data/bin/{RequestHistoricData → historic_data_cli} +46 -91
  10. data/bin/market_data +49 -0
  11. data/bin/option_data +45 -0
  12. data/bin/template +21 -0
  13. data/bin/time_and_sales +63 -0
  14. data/lib/ib-ruby/connection.rb +166 -0
  15. data/lib/ib-ruby/constants.rb +91 -0
  16. data/lib/ib-ruby/messages/incoming.rb +807 -0
  17. data/lib/ib-ruby/messages/outgoing.rb +573 -0
  18. data/lib/ib-ruby/messages.rb +8 -1445
  19. data/lib/ib-ruby/models/bar.rb +26 -0
  20. data/lib/ib-ruby/models/contract.rb +335 -0
  21. data/lib/ib-ruby/models/execution.rb +55 -0
  22. data/lib/ib-ruby/models/model.rb +20 -0
  23. data/lib/ib-ruby/models/order.rb +262 -0
  24. data/lib/ib-ruby/models.rb +11 -0
  25. data/lib/ib-ruby/socket.rb +50 -0
  26. data/lib/ib-ruby/symbols/forex.rb +32 -72
  27. data/lib/ib-ruby/symbols/futures.rb +47 -68
  28. data/lib/ib-ruby/symbols/options.rb +30 -0
  29. data/lib/ib-ruby/symbols/stocks.rb +23 -0
  30. data/lib/ib-ruby/symbols.rb +9 -0
  31. data/lib/ib-ruby.rb +7 -8
  32. data/lib/legacy/bin/account_info_old +36 -0
  33. data/lib/legacy/bin/historic_data_old +81 -0
  34. data/lib/legacy/bin/market_data_old +68 -0
  35. data/lib/legacy/datatypes.rb +485 -0
  36. data/lib/legacy/ib-ruby.rb +10 -0
  37. data/lib/legacy/ib.rb +226 -0
  38. data/lib/legacy/messages.rb +1458 -0
  39. data/lib/version.rb +2 -3
  40. data/spec/ib-ruby/models/contract_spec.rb +261 -0
  41. data/spec/ib-ruby/models/order_spec.rb +64 -0
  42. data/spec/ib-ruby_spec.rb +0 -131
  43. metadata +106 -76
  44. data/bin/AccountInfo +0 -67
  45. data/bin/HistoricToCSV +0 -111
  46. data/bin/RequestMarketData +0 -78
  47. data/bin/SimpleTimeAndSales +0 -98
  48. data/bin/ib-ruby +0 -8
  49. data/lib/ib-ruby/datatypes.rb +0 -400
  50. data/lib/ib-ruby/ib.rb +0 -242
@@ -0,0 +1,26 @@
1
+ require 'ib-ruby/models/model'
2
+
3
+ module IB
4
+ module Models
5
+ # This is a single data point delivered by HistoricData messages.
6
+ # Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
7
+ class Bar < Model
8
+ attr_accessor :date, # The date-time stamp of the start of the bar. The format is
9
+ # determined by the reqHistoricalData() formatDate parameter.
10
+ :open, # The bar opening price.
11
+ :high, # The high price during the time covered by the bar.
12
+ :low, # The low price during the time covered by the bar.
13
+ :close, # The bar closing price.
14
+ :volume, # The bar opening price.
15
+ :wap, # Weighted average price during the time covered by the bar.
16
+ :has_gaps, # Whether or not there are gaps in the data.
17
+ :trades # int: When TRADES data history is returned, represents number
18
+ # of trades that occurred during the time period the bar covers
19
+
20
+ def to_s
21
+ "<Bar #{@date}: wap: #{@wap}, OHLC: #{@open}, #{@high}, #{@low}, #{@close}, " +
22
+ (@trades ? "trades: #{@trades}," : "") + " vol: #{@volume}, gaps? #{@has_gaps}>"
23
+ end
24
+ end # Bar
25
+ end # module Models
26
+ end # module IB
@@ -0,0 +1,335 @@
1
+ require 'ib-ruby/models/model'
2
+
3
+ # TODO: Implement equals() according to the criteria in IB's Java client.
4
+
5
+ module IB
6
+ module Models
7
+ class Contract < Model
8
+
9
+ # Valid security types (sec_type attribute)
10
+ SECURITY_TYPES = {:stock => "STK",
11
+ :option => "OPT",
12
+ :future => "FUT",
13
+ :index => "IND",
14
+ :futures_option => "FOP",
15
+ :forex => "CASH",
16
+ :bag => "BAG"}
17
+
18
+ BAG_SEC_TYPE = "BAG"
19
+
20
+ # Fields are Strings unless noted otherwise
21
+ attr_accessor :con_id, # int: The unique contract identifier.
22
+ :symbol, # This is the symbol of the underlying asset.
23
+ :sec_type, # Security type. Valid values are: SECURITY_TYPES
24
+ :expiry, # The expiration date. Use the format YYYYMM.
25
+ :strike, # double: The strike price.
26
+ :right, # Specifies a Put or Call. Valid values are: P, PUT, C, CALL
27
+ :multiplier, # Specifies a future or option contract multiplier
28
+ # String? (only necessary when multiple possibilities exist)
29
+
30
+ :exchange, # The order destination, such as Smart.
31
+ :currency, # Ambiguities MAY require that currency field be specified,
32
+ # for example, when SMART is the exchange and IBM is being
33
+ # requested (IBM can trade in GBP or USD).
34
+
35
+ :local_symbol, # Local exchange symbol of the underlying asset
36
+ :primary_exchange, # pick a non-aggregate (ie not the SMART) exchange
37
+ # that the contract trades on. DO NOT SET TO SMART.
38
+
39
+ :include_expired, # When true, contract details requests and historical
40
+ # data queries can be performed pertaining to expired contracts.
41
+ # Note: Historical data queries on expired contracts are
42
+ # limited to the last year of the contracts life, and are
43
+ # only supported for expired futures contracts.
44
+ # This field can NOT be set to true for orders.
45
+
46
+ :sec_id_type, # Security identifier, when querying contract details or
47
+ # when placing orders. Supported identifiers are:
48
+ # - ISIN (Example: Apple: US0378331005)
49
+ # - CUSIP (Example: Apple: 037833100)
50
+ # - SEDOL (6-AN + check digit. Example: BAE: 0263494)
51
+ # - RIC (exchange-independent RIC Root and exchange-
52
+ # identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
53
+ :sec_id, # Unique identifier of the given secIdType.
54
+
55
+ # COMBOS
56
+ :combo_legs_description, # received in open order for all combos
57
+ :combo_legs # Dynamic memory structure used to store the leg
58
+ # definitions for this contract.
59
+
60
+ # ContractDetails fields are bundled into Contract proper, as it should be
61
+ # All fields Strings, unless specified otherwise:
62
+ attr_accessor :summary, # NB: ContractDetails reference - to self!
63
+ :market_name, # The market name for this contract.
64
+ :trading_class, # The trading class name for this contract.
65
+ :min_tick, # double: The minimum price tick.
66
+ :price_magnifier, # int: Allows execution and strike prices to be
67
+ # reported consistently with market data, historical data and the
68
+ # order price: Z on LIFFE is reported in index points, not GBP.
69
+
70
+ :order_types, # The list of valid order types for this contract.
71
+ :valid_exchanges, # The list of exchanges this contract is traded on.
72
+ :under_con_id, # int: The underlying contract ID.
73
+ :long_name, # Descriptive name of the asset.
74
+ :contract_month, # Typically the contract month of the underlying for
75
+ # a futures contract.
76
+
77
+ # The industry classification of the underlying/product:
78
+ :industry, # Wide industry. For example, Financial.
79
+ :category, # Industry category. For example, InvestmentSvc.
80
+ :subcategory, # Subcategory. For example, Brokerage.
81
+ :time_zone, # The ID of the time zone for the trading hours of the
82
+ # product. For example, EST.
83
+ :trading_hours, # The trading hours of the product. For example:
84
+ # 20090507:0700-1830,1830-2330;20090508:CLOSED.
85
+ :liquid_hours, # The liquid trading hours of the product. For example,
86
+ # 20090507:0930-1600;20090508:CLOSED.
87
+
88
+ # Bond values:
89
+ :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
90
+ :ratings, # Credit rating of the issuer. Higher credit rating generally
91
+ # indicates a less risky investment. Bond ratings are from
92
+ # Moody's and S&P respectively.
93
+ :desc_append, # Additional descriptive information about the bond.
94
+ :bond_type, # The type of bond, such as "CORP."
95
+ :coupon_type, # The type of bond coupon.
96
+ :callable, # bool: Can be called by the issuer under certain conditions.
97
+ :puttable, # bool: Can be sold back to the issuer under certain conditions
98
+ :coupon, # double: The interest rate used to calculate the amount you
99
+ # will receive in interest payments over the year. default 0
100
+ :convertible, # bool: Can be converted to stock under certain conditions.
101
+ :maturity, # The date on which the issuer must repay bond face value
102
+ :issue_date, # The date the bond was issued.
103
+ :next_option_date, # only if bond has embedded options.
104
+ :next_option_type, # only if bond has embedded options.
105
+ :next_option_partial, # bool: # only if bond has embedded options.
106
+ :notes # Additional notes, if populated for the bond in IB's database
107
+
108
+ # Used for Delta-Neutral Combo contracts only!
109
+ # UnderComp fields are bundled into Contract proper, as it should be.
110
+ # Already defined
111
+ attr_accessor :under_comp, # if not nil, attributes below are sent to server
112
+ #:under_con_id is is already defined in ContractDetails section
113
+ :under_delta, # double: The underlying stock or future delta.
114
+ :under_price # double: The price of the underlying.
115
+
116
+ # NB :description field is entirely local to ib-ruby, and not part of TWS.
117
+ # You can use it to store whatever arbitrary data you want.
118
+ attr_accessor :description
119
+
120
+ def initialize opts = {}
121
+ # Assign defaults to properties first!
122
+ @con_id = 0
123
+ @strike = 0
124
+ @sec_type = ''
125
+ @include_expired = false
126
+ @combo_legs = Array.new
127
+
128
+ # These properties are from ContractDetails
129
+ @summary = self
130
+ @under_con_id = 0
131
+ @min_tick = 0
132
+ @callable = false
133
+ @puttable = false
134
+ @coupon = 0
135
+ @convertible = false
136
+ @next_option_partial = false
137
+
138
+ super opts
139
+ end
140
+
141
+ # some protective filters
142
+ def primary_exchange=(x)
143
+ x.upcase! if x.is_a?(String)
144
+
145
+ # per http://chuckcaplan.com/twsapi/index.php/Class%20Contract
146
+ raise(ArgumentError.new("Don't set primary_exchange to smart")) if x == "SMART"
147
+
148
+ @primary_exchange = x
149
+ end
150
+
151
+ def right=(x)
152
+ x.upcase! if x.is_a?(String)
153
+ x = nil if !x.nil? && x.empty?
154
+ raise(ArgumentError.new("Invalid right \"#{x}\" (must be one of PUT, CALL, P, C)")) unless x.nil? || ["PUT", "CALL", "P", "C", "0"].include?(x)
155
+ @right = x
156
+ end
157
+
158
+ def expiry=(x)
159
+ x = x.to_s
160
+ if (x.nil? || !(x =~ /\d{6,8}/)) and !x.empty? then
161
+ raise ArgumentError.new("Invalid expiry \"#{x}\" (must be in format YYYYMM or YYYYMMDD)")
162
+ end
163
+ @expiry = x
164
+ end
165
+
166
+ def sec_type=(x)
167
+ x = nil if !x.nil? && x.empty?
168
+ 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)
169
+ @sec_type = x
170
+ end
171
+
172
+ def reset
173
+ @combo_legs = Array.new
174
+ @strike = 0
175
+ end
176
+
177
+ # This returns an Array of data from the given contract, in standard format.
178
+ # Different messages serialize contracts differently. Go figure.
179
+ # Note that it does not include the combo legs.
180
+ def serialize(type = :long)
181
+ [symbol,
182
+ sec_type,
183
+ expiry,
184
+ strike,
185
+ right,
186
+ multiplier,
187
+ exchange] +
188
+ (type == :long ? [primary_exchange] : []) +
189
+ [currency,
190
+ local_symbol]
191
+ end
192
+
193
+ # @Legacy
194
+ def serialize_long(version)
195
+ serialize(:long)
196
+ end
197
+
198
+ # @Legacy
199
+ def serialize_short(version)
200
+ serialize(:short)
201
+ end
202
+
203
+ # This produces a string uniquely identifying this contract, in the format used
204
+ # for command line arguments in the IB-Ruby examples. The format is:
205
+ #
206
+ # symbol:security_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
207
+ #
208
+ # Fields not needed for a particular security should be left blank
209
+ # (e.g. strike and right are only relevant for options.)
210
+ #
211
+ # For example, to query the British pound futures contract trading on Globex
212
+ # expiring in September, 2008, the string is:
213
+ #
214
+ # GBP:FUT:200809:::62500:GLOBEX::USD:
215
+ def serialize_ib_ruby(version)
216
+ serialize.join(":")
217
+ end
218
+
219
+ # This returns a Contract initialized from the serialize_ib_ruby format string.
220
+ def self.from_ib_ruby(string)
221
+ c = Contract.new
222
+ c.symbol, c.sec_type, c.expiry, c.strike, c.right, c.multiplier,
223
+ c.exchange, c.primary_exchange, c.currency, c.local_symbol = string.split(":")
224
+ c
225
+ end
226
+
227
+ # Serialize under_comp parameters
228
+ def serialize_under_comp(*args)
229
+ # EClientSocket.java, line 471:
230
+ if under_comp
231
+ [true,
232
+ under_con_id,
233
+ under_delta,
234
+ under_price]
235
+ else
236
+ [false]
237
+ end
238
+ end
239
+
240
+ def serialize_algo(*args)
241
+ raise "Unimplemented"
242
+ #if (m_serverVersion >= MIN_SERVER_VER_ALGO_ORDERS) {
243
+ # send( order.m_algoStrategy);
244
+ # if( !IsEmpty(order.m_algoStrategy)) {
245
+ # java.util.Vector algoParams = order.m_algoParams;
246
+ # int algoParamsCount = algoParams == null ? 0 : algoParams.size();
247
+ # send( algoParamsCount);
248
+ # if( algoParamsCount > 0) {
249
+ # for( int i = 0; i < algoParamsCount; ++i) {
250
+ # TagValue tagValue = (TagValue)algoParams.get(i);
251
+ # send( tagValue.m_tag);
252
+ # send( tagValue.m_value);
253
+ # }
254
+ # }
255
+ # }
256
+ #}
257
+ end
258
+
259
+ # Some messages send open_close too, some don't. WTF.
260
+ def serialize_combo_legs(type = :short)
261
+ # No idea what "BAG" means. Copied from the Java code.
262
+ return [] unless sec_type.upcase == "BAG"
263
+ return [0] if combo_legs.empty? || combo_legs.nil?
264
+ [combo_legs.size,
265
+ combo_legs.map { |leg| leg.serialize(type) }]
266
+ end
267
+
268
+ def to_human
269
+ "<Contract: " + [symbol, expiry, sec_type, strike, right, exchange, currency].join("-") + ">"
270
+ end
271
+
272
+ def to_short
273
+ "#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
274
+ end
275
+
276
+ def to_s
277
+ to_human
278
+ end
279
+
280
+ # ComboLeg is an internal class of Contract, as it should be
281
+ class ComboLeg < Model
282
+ # // open/close leg value is same as combo
283
+ # Specifies whether the order is an open or close order. Valid values are:
284
+ SAME = 0 # Same as the parent security. The only option for retail customers.
285
+ OPEN = 1 # Open. This value is only valid for institutional customers.
286
+ CLOSE = 2 # Close. This value is only valid for institutional customers.
287
+ UNKNOWN = 3
288
+
289
+
290
+ attr_accessor :con_id, # int: The unique contract identifier specifying the security.
291
+ :ratio, # int: Select the relative number of contracts for the leg you
292
+ # are constructing. To help determine the ratio for a
293
+ # specific combination order, refer to the Interactive
294
+ # Analytics section of the User's Guide.
295
+
296
+ :action, # String: BUY/SELL/SSHORT/SSHORTX
297
+ # The side (buy or sell) for the leg you are constructing.
298
+ :exchange, # String: exchange to which the complete combination
299
+ # order will be routed.
300
+ :open_close, # int: Specifies whether the order is an open or close order.
301
+ # Valid values: ComboLeg::SAME/OPEN/CLOSE/UNKNOWN
302
+
303
+ # For institutional customers only! For stock legs when doing short sale
304
+ :short_sale_slot, # int: 0 - retail, 1 = clearing broker, 2 = third party
305
+ :designated_location, # String: Only for shortSaleSlot == 2.
306
+ # Otherwise leave blank or orders will be rejected.
307
+ :exempt_code # int: ?
308
+
309
+ def initialize opts = {}
310
+ @con_id = 0
311
+ @ratio = 0
312
+ @open_close = 0
313
+ @short_sale_slot = 0
314
+ @designated_location = ''
315
+ @exempt_code = -1
316
+
317
+ super opts
318
+ end
319
+
320
+ # Some messages include open_close, some don't. wtf.
321
+ def serialize(type = :short)
322
+ [con_id,
323
+ ratio,
324
+ action,
325
+ exchange] +
326
+ type == :short ? [] : [open_close,
327
+ short_sale_slot,
328
+ designated_location,
329
+ exempt_code]
330
+ end
331
+ end # ComboLeg
332
+
333
+ end # class Contract
334
+ end # module Models
335
+ end # module IB
@@ -0,0 +1,55 @@
1
+ require 'ib-ruby/models/model'
2
+
3
+ module IB
4
+ module Models
5
+ # This is IB Order execution report.
6
+ # Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
7
+ class Execution < Model
8
+ attr_accessor :order_id, # int: order id. TWS orders have a fixed order id of 0.
9
+ :client_id, # int: id of the client that placed the order.
10
+ # TWS orders have a fixed client id of 0.
11
+ :exec_id, # String: Unique order execution id.
12
+ :time, # String: The order execution time.
13
+ :account_number, #String: The customer account number.
14
+ :exchange, # String: Exchange that executed the order.
15
+ :side, # String: Was the transaction a buy or a sale: BOT|SLD
16
+ :shares, # int: The number of shares filled.
17
+ :price, # double: The order execution price.
18
+ :perm_id, # int: TWS id used to identify orders, remains
19
+ # the same over TWS sessions.
20
+ :liquidation, # int: Identifies the position as one to be liquidated
21
+ # last should the need arise.
22
+ :cumulative_quantity, # int: Cumulative quantity. Used in regular
23
+ # trades, combo trades and legs of the combo
24
+ :average_price # double: Average price. Used in regular trades, combo
25
+ # trades and legs of the combo.
26
+
27
+ def side= value
28
+ @side = case value
29
+ when 'BOT'
30
+ :bought
31
+ when 'SLD'
32
+ :sold
33
+ else
34
+ value
35
+ end
36
+ end
37
+
38
+ def initialize opts = {}
39
+ @order_id = 0
40
+ @client_id = 0
41
+ @shares = 0
42
+ @price = 0
43
+ @perm_id = 0
44
+ @liquidation = 0
45
+
46
+ super opts
47
+ end
48
+
49
+ def to_s
50
+ "<Execution #{@time}: #{@side} #{@shares} shares @ #{@price} on #{@exchange}, " +
51
+ "IDs: #{@order_id} order, #{@exec_id} exec, #{@perm_id} perm>"
52
+ end
53
+ end # Execution
54
+ end # module Models
55
+ end # module IB
@@ -0,0 +1,20 @@
1
+ module IB
2
+ module Models
3
+
4
+ # Base IB data Model class, in future it will be developed into ActiveModel
5
+ class Model
6
+ attr_reader :created_at
7
+
8
+ # If a opts hash is given, keys are taken as attribute names, values as data.
9
+ # The model instance fields are then set automatically from the opts Hash.
10
+ #
11
+ def initialize(opts={})
12
+ raise ArgumentError.new("Argument must be a Hash") unless opts.is_a?(Hash)
13
+ @created_at = Time.now
14
+ opts.keys.each do |key|
15
+ self.send((key.to_s + "=").to_sym, opts[key])
16
+ end
17
+ end
18
+ end # Model
19
+ end # module Models
20
+ end # module IB