ib-ruby 0.7.6 → 0.7.8

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 (61) hide show
  1. data/HISTORY +8 -0
  2. data/Rakefile +8 -0
  3. data/VERSION +1 -1
  4. data/bin/fundamental_data +6 -9
  5. data/lib/ib-ruby/connection.rb +16 -19
  6. data/lib/ib-ruby/constants.rb +3 -1
  7. data/lib/ib-ruby/extensions.rb +5 -0
  8. data/lib/ib-ruby/messages/incoming/contract_data.rb +46 -45
  9. data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +8 -5
  10. data/lib/ib-ruby/messages/incoming/execution_data.rb +2 -2
  11. data/lib/ib-ruby/messages/incoming/next_valid_id.rb +18 -0
  12. data/lib/ib-ruby/messages/incoming/open_order.rb +23 -16
  13. data/lib/ib-ruby/messages/incoming/order_status.rb +5 -3
  14. data/lib/ib-ruby/messages/incoming/scanner_data.rb +15 -11
  15. data/lib/ib-ruby/messages/incoming.rb +1 -5
  16. data/lib/ib-ruby/messages/outgoing/abstract_message.rb +2 -1
  17. data/lib/ib-ruby/messages/outgoing/place_order.rb +1 -1
  18. data/lib/ib-ruby/messages/outgoing.rb +1 -1
  19. data/lib/ib-ruby/models/bag.rb +59 -0
  20. data/lib/ib-ruby/models/combo_leg.rb +10 -6
  21. data/lib/ib-ruby/models/contract.rb +278 -0
  22. data/lib/ib-ruby/models/contract_detail.rb +70 -0
  23. data/lib/ib-ruby/models/execution.rb +22 -16
  24. data/lib/ib-ruby/models/model.rb +75 -17
  25. data/lib/ib-ruby/models/model_properties.rb +40 -26
  26. data/lib/ib-ruby/models/option.rb +62 -0
  27. data/lib/ib-ruby/models/order.rb +122 -86
  28. data/lib/ib-ruby/models/order_state.rb +11 -12
  29. data/lib/ib-ruby/models/underlying.rb +36 -0
  30. data/lib/ib-ruby/models.rb +1 -4
  31. data/spec/account_helper.rb +2 -1
  32. data/spec/db.rb +1 -1
  33. data/spec/db_helper.rb +105 -0
  34. data/spec/ib-ruby/connection_spec.rb +3 -3
  35. data/spec/ib-ruby/messages/incoming/open_order_spec.rb +5 -5
  36. data/spec/ib-ruby/messages/incoming/order_status_spec.rb +3 -3
  37. data/spec/ib-ruby/models/bag_spec.rb +15 -23
  38. data/spec/ib-ruby/models/bar_spec.rb +0 -5
  39. data/spec/ib-ruby/models/combo_leg_spec.rb +18 -25
  40. data/spec/ib-ruby/models/contract_detail_spec.rb +54 -0
  41. data/spec/ib-ruby/models/contract_spec.rb +25 -37
  42. data/spec/ib-ruby/models/execution_spec.rb +64 -19
  43. data/spec/ib-ruby/models/option_spec.rb +12 -34
  44. data/spec/ib-ruby/models/order_spec.rb +107 -45
  45. data/spec/ib-ruby/models/order_state_spec.rb +12 -12
  46. data/spec/ib-ruby/models/underlying_spec.rb +36 -0
  47. data/spec/integration/contract_info_spec.rb +65 -55
  48. data/spec/integration/fundamental_data_spec.rb +2 -2
  49. data/spec/integration/orders/attached_spec.rb +3 -3
  50. data/spec/integration/orders/combo_spec.rb +3 -3
  51. data/spec/integration/orders/placement_spec.rb +8 -8
  52. data/spec/integration/orders/{execution_spec.rb → trades_spec.rb} +8 -12
  53. data/spec/integration/orders/valid_ids_spec.rb +3 -3
  54. data/spec/message_helper.rb +1 -1
  55. data/spec/model_helper.rb +150 -85
  56. data/spec/order_helper.rb +35 -18
  57. metadata +18 -10
  58. data/lib/ib-ruby/models/contracts/bag.rb +0 -62
  59. data/lib/ib-ruby/models/contracts/contract.rb +0 -320
  60. data/lib/ib-ruby/models/contracts/option.rb +0 -66
  61. data/lib/ib-ruby/models/contracts.rb +0 -27
@@ -1,320 +0,0 @@
1
- module IB
2
- module Models
3
- module Contracts
4
- class Contract < Model.for(:contract)
5
- include ModelProperties
6
-
7
- # This returns a Contract initialized from the serialize_ib_ruby format string.
8
- def self.build opts = {}
9
- Contracts::TYPES[VALUES[:sec_type][opts[:sec_type]]].new opts
10
- end
11
-
12
- # This returns a Contract initialized from the serialize_ib_ruby format string.
13
- def self.from_ib_ruby string
14
- keys = [:symbol, :sec_type, :expiry, :strike, :right, :multiplier,
15
- :exchange, :primary_exchange, :currency, :local_symbol]
16
- props = Hash[keys.zip(string.split(":"))]
17
- props.delete_if { |k, v| v.nil? || v.empty? }
18
- Contract.new props
19
- end
20
-
21
- # Fields are Strings unless noted otherwise
22
- prop :con_id, # int: The unique contract identifier.
23
- :sec_type,
24
- :strike, # double: The strike price.
25
- :currency, # Only needed if there is an ambiguity, e.g. when SMART exchange
26
- # and IBM is being requested (IBM can trade in GBP or USD).
27
-
28
- :include_expired, # When true, contract details requests and historical
29
- # data queries can be performed pertaining to expired contracts.
30
- # Note: Historical data queries on expired contracts are
31
- # limited to the last year of the contracts life, and are
32
- # only supported for expired futures contracts.
33
- # This field can NOT be set to true for orders.
34
-
35
- :sec_id_type, # Security identifier, when querying contract details or
36
- # when placing orders. Supported identifiers are:
37
- # - ISIN (Example: Apple: US0378331005)
38
- # - CUSIP (Example: Apple: 037833100)
39
- # - SEDOL (6-AN + check digit. Example: BAE: 0263494)
40
- # - RIC (exchange-independent RIC Root and exchange-
41
- # identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
42
- :sec_id, # Unique identifier of the given secIdType.
43
-
44
- :legs_description, # received in OpenOrder for all combos
45
-
46
- :symbol => :s, # This is the symbol of the underlying asset.
47
-
48
- :local_symbol => :s, # Local exchange symbol of the underlying asset
49
-
50
- # Future/option contract multiplier (only needed when multiple possibilities exist)
51
- :multiplier => :i,
52
-
53
- :expiry => :s, # The expiration date. Use the format YYYYMM or YYYYMMDD
54
- :exchange => :sup, # The order destination, such as Smart.
55
- :primary_exchange => :sup, # Non-SMART exchange where the contract trades.
56
-
57
- # Specifies a Put or Call. Valid input values are: P, PUT, C, CALL
58
- :right =>
59
- {:set => proc { |val|
60
- self[:right] =
61
- case val.to_s.upcase
62
- when 'NONE', '', '0', '?'
63
- ''
64
- when 'PUT', 'P'
65
- 'P'
66
- when 'CALL', 'C'
67
- 'C'
68
- else
69
- val
70
- end },
71
- :validate => {:format => {:with => /^put$|^call$|^none$/,
72
- :message => "should be put, call or none"}}
73
- }
74
-
75
- # Security type. Valid values are: SECURITY_TYPES
76
-
77
- # ContractDetails fields are bundled into Contract proper, as it should be
78
- # All fields Strings, unless specified otherwise:
79
- prop :market_name, # The market name for this contract.
80
- :trading_class, # The trading class name for this contract.
81
- :min_tick, # double: The minimum price tick.
82
- :price_magnifier, # int: Allows execution and strike prices to be
83
- # reported consistently with market data, historical data and the
84
- # order price: Z on LIFFE is reported in index points, not GBP.
85
-
86
- :order_types, # The list of valid order types for this contract.
87
- :valid_exchanges, # The list of exchanges this contract is traded on.
88
- :under_con_id, # int: The underlying contract ID.
89
- :long_name, # Descriptive name of the asset.
90
- :contract_month, # The contract month of the underlying for a futures contract.
91
-
92
- # The industry classification of the underlying/product:
93
- :industry, # Wide industry. For example, Financial.
94
- :category, # Industry category. For example, InvestmentSvc.
95
- :subcategory, # Subcategory. For example, Brokerage.
96
- :time_zone, # Time zone for the trading hours of the product. For example, EST.
97
- :trading_hours, # The trading hours of the product. For example:
98
- # 20090507:0700-1830,1830-2330;20090508:CLOSED.
99
- :liquid_hours, # The liquid trading hours of the product. For example,
100
- # 20090507:0930-1600;20090508:CLOSED.
101
-
102
- # Bond values:
103
- :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
104
- :ratings, # Credit rating of the issuer. Higher rating is less risky investment.
105
- # Bond ratings are from Moody's and S&P respectively.
106
- :desc_append, # Additional descriptive information about the bond.
107
- :bond_type, # The type of bond, such as "CORP."
108
- :coupon_type, # The type of bond coupon.
109
- :coupon, # double: The interest rate used to calculate the amount you
110
- # will receive in interest payments over the year. default 0
111
- :maturity, # The date on which the issuer must repay bond face value
112
- :issue_date, # The date the bond was issued.
113
- :next_option_date, # only if bond has embedded options.
114
- :next_option_type, # only if bond has embedded options.
115
- :notes, # Additional notes, if populated for the bond in IB's database
116
- :callable => :bool, # Can be called by the issuer under certain conditions.
117
- :puttable => :bool, # Can be sold back to the issuer under certain conditions
118
- :convertible => :bool, # Can be converted to stock under certain conditions.
119
- :next_option_partial => :bool # # only if bond has embedded options.
120
-
121
- # Used for Delta-Neutral Combo contracts only!
122
- # UnderComp fields are bundled into Contract proper, as it should be.
123
- prop :under_comp, # if not nil, attributes below are sent to server
124
- #:under_con_id is is already defined in ContractDetails section
125
- :under_delta, # double: The underlying stock or future delta.
126
- :under_price # double: The price of the underlying.
127
-
128
- # Legs arriving via OpenOrder message, need to define them here
129
- attr_accessor :legs # leg definitions for this contract.
130
- alias combo_legs legs
131
- alias combo_legs= legs=
132
- alias combo_legs_description legs_description
133
- alias combo_legs_description= legs_description=
134
-
135
- attr_accessor :description # NB: local to ib-ruby, not part of TWS.
136
-
137
- # Extra validations
138
- validates_inclusion_of :sec_type, :in => CODES[:sec_type].keys,
139
- :message => "should be valid security type"
140
-
141
- validates_format_of :expiry, :with => /^\d{6}$|^\d{8}$|^$/,
142
- :message => "should be YYYYMM or YYYYMMDD"
143
-
144
- validates_format_of :primary_exchange, :without => /SMART/,
145
- :message => "should not be SMART"
146
-
147
- DEFAULT_PROPS = {:con_id => 0,
148
- :strike => 0.0,
149
- :right => :none, # Not an option
150
- :exchange => 'SMART',
151
- :under_con_id => 0,
152
- :min_tick => 0,
153
- :coupon => 0,
154
- :callable => false,
155
- :puttable => false,
156
- :convertible => false,
157
- :include_expired => false,
158
- :next_option_partial => false, }
159
-
160
- # NB: ContractDetails reference - to self!
161
- def summary
162
- self
163
- end
164
-
165
- # This returns an Array of data from the given contract.
166
- # Different messages serialize contracts differently. Go figure.
167
- # Note that it does NOT include the combo legs.
168
- def serialize *fields
169
- [(fields.include?(:con_id) ? [con_id] : []),
170
- symbol,
171
- self[:sec_type],
172
- (fields.include?(:option) ?
173
- [expiry,
174
- strike,
175
- self[:right],
176
- multiplier] : []),
177
- exchange,
178
- (fields.include?(:primary_exchange) ? [primary_exchange] : []),
179
- currency,
180
- local_symbol,
181
- (fields.include?(:sec_id) ? [sec_id_type, sec_id] : []),
182
- (fields.include?(:include_expired) ? [include_expired] : []),
183
- ].flatten
184
- end
185
-
186
- def serialize_long *fields
187
- serialize :option, :primary_exchange, *fields
188
- end
189
-
190
- def serialize_short *fields
191
- serialize :option, *fields
192
- end
193
-
194
- # Serialize under_comp parameters
195
- def serialize_under_comp *args
196
- # EClientSocket.java, line 471:
197
- if under_comp
198
- [true,
199
- under_con_id,
200
- under_delta,
201
- under_price]
202
- else
203
- [false]
204
- end
205
- end
206
-
207
- # Defined in Contract, not BAG subclass to keep code DRY
208
- def serialize_legs *fields
209
- case
210
- when !bag?
211
- []
212
- when legs.empty?
213
- [0]
214
- else
215
- [legs.size, legs.map { |leg| leg.serialize *fields }].flatten
216
- end
217
- end
218
-
219
- # This produces a string uniquely identifying this contract, in the format used
220
- # for command line arguments in the IB-Ruby examples. The format is:
221
- #
222
- # symbol:security_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
223
- #
224
- # Fields not needed for a particular security should be left blank
225
- # (e.g. strike and right are only relevant for options.)
226
- #
227
- # For example, to query the British pound futures contract trading on Globex
228
- # expiring in September, 2008, the string is:
229
- #
230
- # GBP:FUT:200809:::62500:GLOBEX::USD:
231
- def serialize_ib_ruby
232
- serialize_long.join(":")
233
- end
234
-
235
- # Contract comparison
236
- def == other
237
- return false unless other.is_a?(self.class)
238
-
239
- # Different sec_id_type
240
- return false if sec_id_type && other.sec_id_type && sec_id_type != other.sec_id_type
241
-
242
- # Different sec_id
243
- return false if sec_id && other.sec_id && sec_id != other.sec_id
244
-
245
- # Different under_comp
246
- return false if under_comp && other.under_comp && under_comp != other.under_comp
247
-
248
- # Different symbols
249
- return false if symbol && other.symbol && symbol != other.symbol
250
-
251
- # Different currency
252
- return false if currency && other.currency && currency != other.currency
253
-
254
- # Same con_id for all Bags, but unknown for new Contracts...
255
- # 0 or nil con_id matches any
256
- return false if con_id != 0 && other.con_id != 0 &&
257
- con_id && other.con_id && con_id != other.con_id
258
-
259
- # SMART or nil exchange matches any
260
- return false if exchange != 'SMART' && other.exchange != 'SMART' &&
261
- exchange && other.exchange && exchange != other.exchange
262
-
263
- # Comparison for Bonds and Options
264
- if bond? || option?
265
- return false if right != other.right || strike != other.strike
266
- return false if multiplier && other.multiplier && multiplier != other.multiplier
267
- return false if expiry && expiry[0..5] != other.expiry[0..5]
268
- return false unless expiry && (expiry[6..7] == other.expiry[6..7] ||
269
- expiry[6..7].empty? || other.expiry[6..7].empty?)
270
- end
271
-
272
- # All else being equal...
273
- sec_type == other.sec_type
274
- end
275
-
276
- def to_s
277
- "<Contract: " + instance_variables.map do |key|
278
- value = send(key[1..-1])
279
- " #{key}=#{value}" unless value.nil? || value == '' || value == 0
280
- end.compact.join(',') + " >"
281
- end
282
-
283
- def to_human
284
- "<Contract: " +
285
- [symbol,
286
- sec_type,
287
- (expiry == '' ? nil : expiry),
288
- (right == :none ? nil : right),
289
- (strike == 0 ? nil : strike),
290
- exchange,
291
- currency
292
- ].compact.join(" ") + ">"
293
- end
294
-
295
- def to_short
296
- "#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
297
- end
298
-
299
- # Testing for type of contract:
300
-
301
- def bag?
302
- self[:sec_type] == 'BAG'
303
- end
304
-
305
- def bond?
306
- self[:sec_type] == 'BOND'
307
- end
308
-
309
- def stock?
310
- self[:sec_type] == 'STK'
311
- end
312
-
313
- def option?
314
- self[:sec_type] == 'OPT'
315
- end
316
-
317
- end # class Contract
318
- end # module Contracts
319
- end # module Models
320
- end # module IB
@@ -1,66 +0,0 @@
1
- require 'ib-ruby/models/contracts/contract'
2
-
3
- module IB
4
- module Models
5
- module Contracts
6
- class Option < Contract
7
-
8
- validates_numericality_of :strike, :greater_than => 0
9
- validates_format_of :sec_type, :with => /^option$/,
10
- :message => "should be an option"
11
- validates_format_of :local_symbol, :with => /^\w+\s*\d{15}$|^$/,
12
- :message => "invalid OSI code"
13
- validates_format_of :right, :with => /^put$|^call$/,
14
- :message => "should be put or call"
15
-
16
- # For Options, this is contract's OSI (Option Symbology Initiative) name/code
17
- alias osi local_symbol
18
-
19
- def osi= value
20
- # Normalize to 21 char
21
- self.local_symbol = value.sub(/ /, ' '*(22-value.size))
22
- end
23
-
24
- # Make valid IB Contract definition from OSI (Option Symbology Initiative) code.
25
- # NB: Simply making a new Contract with *local_symbol* (osi) property set to a
26
- # valid OSI code works just as well, just do NOT set *expiry*, *right* or
27
- # *strike* properties in this case.
28
- # This class method provided as a backup and shows how to analyse OSI codes.
29
- def self.from_osi osi
30
-
31
- # Parse contract's OSI (OCC Option Symbology Initiative) code
32
- args = osi.match(/(\w+)\s?(\d\d)(\d\d)(\d\d)([pcPC])(\d+)/).to_a.drop(1)
33
- symbol = args.shift
34
- year = 2000 + args.shift.to_i
35
- month = args.shift.to_i
36
- day = args.shift.to_i
37
- right = args.shift.upcase
38
- strike = args.shift.to_i/1000.0
39
- #p symbol, year, month, day, right, strike
40
-
41
- # Set correct expiry date - IB expiry date differs from OSI if expiry date
42
- # falls on Saturday (see https://github.com/arvicco/option_mower/issues/4)
43
- expiry_date = Time.utc(year, month, day)
44
- expiry_date = Time.utc(year, month, day-1) if expiry_date.wday == 6
45
-
46
- new :symbol => symbol,
47
- :exchange => "SMART",
48
- :expiry => expiry_date.to_ib[2..7], # YYMMDD
49
- :right => right,
50
- :strike => strike
51
- end
52
-
53
- def initialize opts = {}
54
- super opts
55
- self.sec_type = 'OPT'
56
- self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
57
- end
58
-
59
- def to_human
60
- "<Option: " + [symbol, expiry, right, strike, exchange, currency].join(" ") + ">"
61
- end
62
-
63
- end # class Option
64
- end # class Contract
65
- end # module Models
66
- end # module IB
@@ -1,27 +0,0 @@
1
- module IB
2
- module Models
3
- module Contracts
4
- end
5
- end
6
- end
7
-
8
- require 'ib-ruby/models/contracts/contract'
9
- require 'ib-ruby/models/contracts/option'
10
- require 'ib-ruby/models/contracts/bag'
11
-
12
- module IB
13
- module Models
14
- # This module contains Contract subclasses
15
- module Contracts
16
- # Specialized Contract subclasses representing different security types
17
- TYPES = Hash.new(Contract)
18
- TYPES[:bag] = Bag
19
- TYPES[:option] = Option
20
-
21
- # Returns concrete subclass for this sec_type, or default Contract
22
- def [] sec_type
23
- TYPES[sec_type]
24
- end
25
- end
26
- end
27
- end