ib-ruby 0.4.3 → 0.4.20

Sign up to get free protection for your applications and to get access to all the features.
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