my-ib-api 0.0.1

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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ib-api.rb +10 -0
  3. data/lib/ib/base.rb +99 -0
  4. data/lib/ib/base_properties.rb +154 -0
  5. data/lib/ib/connection.rb +327 -0
  6. data/lib/ib/constants.rb +334 -0
  7. data/lib/ib/db.rb +29 -0
  8. data/lib/ib/engine.rb +35 -0
  9. data/lib/ib/errors.rb +40 -0
  10. data/lib/ib/extensions.rb +72 -0
  11. data/lib/ib/flex.rb +106 -0
  12. data/lib/ib/logger.rb +25 -0
  13. data/lib/ib/messages.rb +88 -0
  14. data/lib/ib/messages/abstract_message.rb +89 -0
  15. data/lib/ib/messages/incoming.rb +134 -0
  16. data/lib/ib/messages/incoming/abstract_message.rb +99 -0
  17. data/lib/ib/messages/incoming/alert.rb +34 -0
  18. data/lib/ib/messages/incoming/contract_data.rb +102 -0
  19. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  20. data/lib/ib/messages/incoming/execution_data.rb +54 -0
  21. data/lib/ib/messages/incoming/historical_data.rb +55 -0
  22. data/lib/ib/messages/incoming/market_depths.rb +44 -0
  23. data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
  24. data/lib/ib/messages/incoming/open_order.rb +232 -0
  25. data/lib/ib/messages/incoming/order_status.rb +81 -0
  26. data/lib/ib/messages/incoming/portfolio_value.rb +39 -0
  27. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  28. data/lib/ib/messages/incoming/scanner_data.rb +53 -0
  29. data/lib/ib/messages/incoming/ticks.rb +131 -0
  30. data/lib/ib/messages/outgoing.rb +331 -0
  31. data/lib/ib/messages/outgoing/abstract_message.rb +73 -0
  32. data/lib/ib/messages/outgoing/bar_requests.rb +189 -0
  33. data/lib/ib/messages/outgoing/place_order.rb +141 -0
  34. data/lib/ib/model.rb +6 -0
  35. data/lib/ib/models.rb +10 -0
  36. data/lib/ib/requires.rb +9 -0
  37. data/lib/ib/socket.rb +81 -0
  38. data/lib/ib/symbols.rb +35 -0
  39. data/lib/ib/symbols/bonds.rb +28 -0
  40. data/lib/ib/symbols/forex.rb +41 -0
  41. data/lib/ib/symbols/futures.rb +117 -0
  42. data/lib/ib/symbols/options.rb +39 -0
  43. data/lib/ib/symbols/stocks.rb +37 -0
  44. data/lib/ib/version.rb +6 -0
  45. data/lib/models/ib/bag.rb +51 -0
  46. data/lib/models/ib/bar.rb +45 -0
  47. data/lib/models/ib/combo_leg.rb +103 -0
  48. data/lib/models/ib/contract.rb +292 -0
  49. data/lib/models/ib/contract_detail.rb +89 -0
  50. data/lib/models/ib/execution.rb +65 -0
  51. data/lib/models/ib/option.rb +60 -0
  52. data/lib/models/ib/order.rb +391 -0
  53. data/lib/models/ib/order_state.rb +128 -0
  54. data/lib/models/ib/underlying.rb +34 -0
  55. metadata +96 -0
@@ -0,0 +1,292 @@
1
+ require 'models/ib/contract_detail'
2
+ require 'models/ib/underlying'
3
+
4
+ module IB
5
+ class Contract < IB::Model
6
+ include BaseProperties
7
+
8
+ # Fields are Strings unless noted otherwise
9
+ prop :con_id, # int: The unique contract identifier.
10
+ :currency, # Only needed if there is an ambiguity, e.g. when SMART exchange
11
+ # and IBM is being requested (IBM can trade in GBP or USD).
12
+
13
+ :legs_description, # received in OpenOrder for all combos
14
+
15
+ :sec_type, # Security type. Valid values are: SECURITY_TYPES
16
+
17
+ :sec_id => :sup, # Unique identifier of the given secIdType.
18
+
19
+ :sec_id_type => :sup, # Security identifier, when querying contract details or
20
+ # when placing orders. Supported identifiers are:
21
+ # - ISIN (Example: Apple: US0378331005)
22
+ # - CUSIP (Example: Apple: 037833100)
23
+ # - SEDOL (6-AN + check digit. Example: BAE: 0263494)
24
+ # - RIC (exchange-independent RIC Root and exchange-
25
+ # identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
26
+
27
+ :symbol => :s, # This is the symbol of the underlying asset.
28
+
29
+ :local_symbol => :s, # Local exchange symbol of the underlying asset
30
+
31
+ # Future/option contract multiplier (only needed when multiple possibilities exist)
32
+ :multiplier => {:set => :i},
33
+
34
+ :strike => :f, # double: The strike price.
35
+ :expiry => :s, # The expiration date. Use the format YYYYMM or YYYYMMDD
36
+ :exchange => :sup, # The order destination, such as Smart.
37
+ :primary_exchange => :sup, # Non-SMART exchange where the contract trades.
38
+ :include_expired => :bool, # When true, contract details requests and historical
39
+ # data queries can be performed pertaining to expired contracts.
40
+ # Note: Historical data queries on expired contracts are
41
+ # limited to the last year of the contracts life, and are
42
+ # only supported for expired futures contracts.
43
+ # This field can NOT be set to true for orders.
44
+
45
+
46
+ # Specifies a Put or Call. Valid input values are: P, PUT, C, CALL
47
+ :right => {
48
+ :set => proc { |val|
49
+ self[:right] =
50
+ case val.to_s.upcase
51
+ when 'NONE', '', '0', '?'
52
+ ''
53
+ when 'PUT', 'P'
54
+ 'P'
55
+ when 'CALL', 'C'
56
+ 'C'
57
+ else
58
+ val
59
+ end
60
+ },
61
+ :validate => {:format => {:with => /\Aput$|^call$|^none\z/,
62
+ :message => "should be put, call or none"}}
63
+ }
64
+
65
+ attr_accessor :description # NB: local to ib, not part of TWS.
66
+
67
+ ### Associations
68
+
69
+ has_many :orders # Placed for this Contract
70
+
71
+ has_many :bars # Possibly representing trading history for this Contract
72
+
73
+ has_one :contract_detail # Volatile info about this Contract
74
+
75
+ # For Contracts that are part of BAG
76
+ has_one :leg, :class_name => 'ComboLeg', :foreign_key => :leg_contract_id
77
+ has_one :combo, :class_name => 'Contract', :through => :leg
78
+
79
+ # for Combo/BAG Contracts that contain ComboLegs
80
+ has_many :combo_legs, :foreign_key => :combo_id
81
+ has_many :leg_contracts, :class_name => 'Contract', :through => :combo_legs
82
+ alias legs combo_legs
83
+ alias legs= combo_legs=
84
+
85
+ alias combo_legs_description legs_description
86
+ alias combo_legs_description= legs_description=
87
+
88
+ # for Delta-Neutral Combo Contracts
89
+ has_one :underlying
90
+ alias under_comp underlying
91
+ alias under_comp= underlying=
92
+
93
+
94
+ ### Extra validations
95
+ validates_inclusion_of :sec_type, :in => CODES[:sec_type].keys,
96
+ :message => "should be valid security type"
97
+
98
+ validates_format_of :expiry, :with => /\A\d{6}$|^\d{8}$|\A\z/,
99
+ :message => "should be YYYYMM or YYYYMMDD"
100
+
101
+ validates_format_of :primary_exchange, :without => /SMART/,
102
+ :message => "should not be SMART"
103
+
104
+ validates_format_of :sec_id_type, :with => /ISIN|SEDOL|CUSIP|RIC|\A\z/,
105
+ :message => "should be valid security identifier"
106
+
107
+ validates_numericality_of :multiplier, :strike, :allow_nil => true
108
+
109
+ def default_attributes
110
+ super.merge :con_id => 0,
111
+ :strike => 0.0,
112
+ :right => :none, # Not an option
113
+ :exchange => 'SMART',
114
+ :include_expired => false
115
+ end
116
+
117
+ # This returns an Array of data from the given contract.
118
+ # Different messages serialize contracts differently. Go figure.
119
+ # Note that it does NOT include the combo legs.
120
+ # serialize [:option, :con_id, :include_expired, :sec_id]
121
+ def serialize *fields
122
+ [(fields.include?(:con_id) ? [con_id] : []),
123
+ symbol,
124
+ self[:sec_type],
125
+ (fields.include?(:option) ?
126
+ [expiry,
127
+ strike,
128
+ self[:right],
129
+ multiplier] : []),
130
+ exchange,
131
+ (fields.include?(:primary_exchange) ? [primary_exchange] : []),
132
+ currency,
133
+ local_symbol,
134
+ (fields.include?(:sec_id) ? [sec_id_type, sec_id] : []),
135
+ (fields.include?(:include_expired) ? [include_expired] : []),
136
+ ].flatten
137
+ end
138
+
139
+ def serialize_long *fields
140
+ serialize :option, :primary_exchange, *fields
141
+ end
142
+
143
+ def serialize_short *fields
144
+ serialize :option, *fields
145
+ end
146
+
147
+ # Serialize under_comp parameters: EClientSocket.java, line 471
148
+ def serialize_under_comp *args
149
+ under_comp ? under_comp.serialize : [false]
150
+ end
151
+
152
+ # Defined in Contract, not BAG subclass to keep code DRY
153
+ def serialize_legs *fields
154
+ case
155
+ when !bag?
156
+ []
157
+ when legs.empty?
158
+ [0]
159
+ else
160
+ [legs.size, legs.map { |leg| leg.serialize *fields }].flatten
161
+ end
162
+ end
163
+
164
+ # This produces a string uniquely identifying this contract, in the format used
165
+ # for command line arguments in the IB-Ruby examples. The format is:
166
+ #
167
+ # symbol:sec_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
168
+ #
169
+ # Fields not needed for a particular security should be left blank
170
+ # (e.g. strike and right are only relevant for options.)
171
+ #
172
+ # For example, to query the British pound futures contract trading on Globex
173
+ # expiring in September, 2008, the string is:
174
+ #
175
+ # GBP:FUT:200809:::62500:GLOBEX::USD:
176
+ def serialize_ib_ruby
177
+ serialize_long.join(":")
178
+ end
179
+
180
+ # Contract comparison
181
+ def == other
182
+ return true if super(other)
183
+
184
+ return false unless other.is_a?(self.class)
185
+
186
+ # Different sec_id_type
187
+ return false if sec_id_type && other.sec_id_type && sec_id_type != other.sec_id_type
188
+
189
+ # Different sec_id
190
+ return false if sec_id && other.sec_id && sec_id != other.sec_id
191
+
192
+ # Different symbols
193
+ return false if symbol && other.symbol && symbol != other.symbol
194
+
195
+ # Different currency
196
+ return false if currency && other.currency && currency != other.currency
197
+
198
+ # Same con_id for all Bags, but unknown for new Contracts...
199
+ # 0 or nil con_id matches any
200
+ return false if con_id != 0 && other.con_id != 0 &&
201
+ con_id && other.con_id && con_id != other.con_id
202
+
203
+ # SMART or nil exchange matches any
204
+ return false if exchange != 'SMART' && other.exchange != 'SMART' &&
205
+ exchange && other.exchange && exchange != other.exchange
206
+
207
+ # Comparison for Bonds and Options
208
+ if bond? || option?
209
+ return false if right != other.right || strike != other.strike
210
+ return false if multiplier && other.multiplier &&
211
+ multiplier != other.multiplier
212
+ return false if expiry && expiry[0..5] != other.expiry[0..5]
213
+ return false unless expiry && (expiry[6..7] == other.expiry[6..7] ||
214
+ expiry[6..7].empty? || other.expiry[6..7].empty?)
215
+ end
216
+
217
+ # All else being equal...
218
+ sec_type == other.sec_type
219
+ end
220
+
221
+ def to_s
222
+ "<Contract: " + instance_variables.map do |key|
223
+ value = send(key[1..-1])
224
+ " #{key}=#{value}" unless value.nil? || value == '' || value == 0
225
+ end.compact.join(',') + " >"
226
+ end
227
+
228
+ def to_human
229
+ "<Contract: " +
230
+ [symbol,
231
+ sec_type,
232
+ (expiry == '' ? nil : expiry),
233
+ (right == :none ? nil : right),
234
+ (strike == 0 ? nil : strike),
235
+ exchange,
236
+ currency
237
+ ].compact.join(" ") + ">"
238
+ end
239
+
240
+ def to_short
241
+ "#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
242
+ end
243
+
244
+ # Testing for type of contract:
245
+
246
+ def bag?
247
+ self[:sec_type] == 'BAG'
248
+ end
249
+
250
+ def bond?
251
+ self[:sec_type] == 'BOND'
252
+ end
253
+
254
+ def stock?
255
+ self[:sec_type] == 'STK'
256
+ end
257
+
258
+ def option?
259
+ self[:sec_type] == 'OPT'
260
+ end
261
+
262
+ end # class Contract
263
+
264
+
265
+ ### Now let's deal with Contract subclasses
266
+
267
+ require 'models/ib/option'
268
+ require 'models/ib/bag'
269
+
270
+ class Contract
271
+ # Contract subclasses representing specialized security types.
272
+ # Most security types do not have their own subclass, they use generic Contract class.
273
+ Subclasses = Hash.new(Contract)
274
+ Subclasses[:bag] = IB::Bag
275
+ Subclasses[:option] = IB::Option
276
+
277
+ # This builds an appropriate Contract subclass based on its type
278
+ def self.build opts = {}
279
+ subclass = VALUES[:sec_type][opts[:sec_type]] || opts[:sec_type].to_sym
280
+ Contract::Subclasses[subclass].new opts
281
+ end
282
+
283
+ # This returns a Contract initialized from the serialize_ib_ruby format string.
284
+ def self.from_ib_ruby string
285
+ keys = [:symbol, :sec_type, :expiry, :strike, :right, :multiplier,
286
+ :exchange, :primary_exchange, :currency, :local_symbol]
287
+ props = Hash[keys.zip(string.split(":"))]
288
+ props.delete_if { |k, v| v.nil? || v.empty? }
289
+ Contract.build props
290
+ end
291
+ end # class Contract
292
+ end # module IB
@@ -0,0 +1,89 @@
1
+ module IB
2
+
3
+ # Additional Contract properties (volatile, therefore extracted)
4
+ class ContractDetail < IB::Model
5
+ include BaseProperties
6
+
7
+ # All fields Strings, unless specified otherwise:
8
+ prop :market_name, # The market name for this contract.
9
+ :trading_class, # The trading class name for this contract.
10
+ :min_tick, # double: The minimum price tick.
11
+ :price_magnifier, # int: Allows execution and strike prices to be reported
12
+ # consistently with market data, historical data and the
13
+ # order price: Z on LIFFE is reported in index points, not GBP.
14
+
15
+ :order_types, # The list of valid order types for this contract.
16
+ :valid_exchanges, # The list of exchanges this contract is traded on.
17
+ :under_con_id, # int: The underlying contract ID.
18
+ :long_name, # Descriptive name of the asset.
19
+ :contract_month, # The contract month of the underlying futures contract.
20
+
21
+ # For Bonds only
22
+ :valid_next_option_date,
23
+ :valid_next_option_type,
24
+ :valid_next_option_partial,
25
+
26
+ # The industry classification of the underlying/product:
27
+ :industry, # Wide industry. For example, Financial.
28
+ :category, # Industry category. For example, InvestmentSvc.
29
+ :subcategory, # Subcategory. For example, Brokerage.
30
+ [:time_zone, :time_zone_id], # Time zone for the trading hours (e.g. EST)
31
+ :trading_hours, # The trading hours of the product. For example:
32
+ # 20090507:0700-1830,1830-2330;20090508:CLOSED.
33
+ :liquid_hours, # The liquid trading hours of the product. For example,
34
+ # 20090507:0930-1600;20090508:CLOSED.
35
+
36
+ # To support products in Australia which trade in non-currency units, the following
37
+ # attributes have been added to Execution and Contract Details objects:
38
+ :ev_rule, # evRule - String contains the Economic Value Rule name and optional argument,
39
+ # separated by a colon. Examle: aussieBond:YearsToExpiration=3.
40
+ # When the optional argument not present, the value will be followed by a colon.
41
+ [:ev_multiplier, :ev_multipler], # evMultiplier - double, tells you approximately
42
+ # how much the market value of a contract would change if the price were
43
+ # to change by 1. It cannot be used to get market value by multiplying
44
+ # the price by the approximate multiplier.
45
+
46
+ :sec_id_list, # Hash with multiple Security ids
47
+
48
+ # BOND values:
49
+ :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
50
+ :ratings, # Credit rating of the issuer. Higher rating is less risky investment.
51
+ # Bond ratings are from Moody's and S&P respectively.
52
+ :desc_append, # Additional descriptive information about the bond.
53
+ :bond_type, # The type of bond, such as "CORP."
54
+ :coupon_type, # The type of bond coupon.
55
+ :coupon, # double: The interest rate used to calculate the amount you
56
+ # will receive in interest payments over the year. default 0
57
+ :maturity, # The date on which the issuer must repay bond face value
58
+ :issue_date, # The date the bond was issued.
59
+ :next_option_date, # only if bond has embedded options.
60
+ :next_option_type, # only if bond has embedded options.
61
+ :notes, # Additional notes, if populated for the bond in IB's database
62
+ :callable => :bool, # Can be called by the issuer under certain conditions.
63
+ :puttable => :bool, # Can be sold back to the issuer under certain conditions
64
+ :convertible => :bool, # Can be converted to stock under certain conditions.
65
+ :next_option_partial => :bool # # only if bond has embedded options.
66
+
67
+ # Extra validations
68
+ validates_format_of :time_zone, :with => /\A\w{3}\z/, :message => 'should be XXX'
69
+
70
+ serialize :sec_id_list, HashWithIndifferentAccess
71
+
72
+ belongs_to :contract
73
+ alias summary contract
74
+ alias summary= contract=
75
+
76
+ def default_attributes
77
+ super.merge :coupon => 0.0,
78
+ :under_con_id => 0,
79
+ :min_tick => 0,
80
+ :ev_multipler => 0,
81
+ :sec_id_list => HashWithIndifferentAccess.new,
82
+ :callable => false,
83
+ :puttable => false,
84
+ :convertible => false,
85
+ :next_option_partial => false
86
+ end
87
+
88
+ end # class ContractDetail
89
+ end # module IB
@@ -0,0 +1,65 @@
1
+ module IB
2
+
3
+ # This is IB Order execution report.
4
+ class Execution < IB::Model
5
+ include BaseProperties
6
+
7
+ belongs_to :order
8
+
9
+ prop :local_id, # int: order id. TWS orders have a fixed order id of 0.
10
+ :client_id, # int: client id. TWS orders have a fixed client id of 0.
11
+ :perm_id, # int: TWS id used to identify orders over TWS sessions
12
+ :exec_id, # String: Unique order execution id over TWS sessions.
13
+ :time, # # TODO: convert into Time object?
14
+ # String: The order execution time.
15
+ :exchange, # String: Exchange that executed the order.
16
+ :order_ref, # String: Same order_ref as in corresponding Order
17
+ :price, # double: The order execution price.
18
+ :average_price, # double: Used in regular trades, combo trades and legs of the combo.
19
+ :ev_rule, # String: Australian products only
20
+ :ev_multiplier, # double: Australian products only
21
+
22
+ [:quantity, :shares], # int: The number of shares filled.
23
+ :cumulative_quantity, # int: Used in regular trades, combo trades and legs of combo
24
+ :liquidation => :bool, # This position is liquidated last should the need arise.
25
+ [:account_name, :account_number] => :s, # The customer account number.
26
+ [:side, :action] => PROPS[:side] # Was the transaction a buy or a sale: BOT|SLD
27
+
28
+ # Extra validations
29
+ validates_numericality_of :quantity, :cumulative_quantity, :price, :average_price
30
+ validates_numericality_of :local_id, :client_id, :perm_id, :only_integer => true
31
+
32
+ def default_attributes
33
+ super.merge :local_id => 0,
34
+ :client_id => 0,
35
+ :quantity => 0,
36
+ :price => 0,
37
+ :perm_id => 0,
38
+ :liquidation => false
39
+ end
40
+
41
+ # Comparison
42
+ def == other
43
+ super(other) ||
44
+ other.is_a?(self.class) &&
45
+ perm_id == other.perm_id &&
46
+ local_id == other.local_id && # ((p __LINE__)||true) &&
47
+ client_id == other.client_id &&
48
+ exec_id == other.exec_id &&
49
+ time == other.time &&
50
+ exchange == other.exchange &&
51
+ order_ref == other.order_ref &&
52
+ side == other.side
53
+ # TODO: || compare all attributes!
54
+ end
55
+
56
+ def to_human
57
+ "<Execution: #{time} #{side} #{quantity} at #{price} on #{exchange}, " +
58
+ "cumulative #{cumulative_quantity} at #{average_price}, " +
59
+ "ids #{local_id}/#{perm_id}/#{exec_id}>"
60
+ end
61
+
62
+ alias to_s to_human
63
+
64
+ end # Execution
65
+ end # module IB
@@ -0,0 +1,60 @@
1
+ require 'models/ib/contract'
2
+
3
+ module IB
4
+ class Option < Contract
5
+
6
+ validates_numericality_of :strike, :greater_than => 0
7
+ validates_format_of :sec_type, :with => /\Aoption\z/,
8
+ :message => "should be an option"
9
+ validates_format_of :local_symbol, :with => /\A\w+\s*\d{6}[pcPC]\d{8}$|\A\z/,
10
+ :message => "invalid OSI code"
11
+ validates_format_of :right, :with => /\Aput$|^call\z/,
12
+ :message => "should be put or call"
13
+
14
+ # For Options, this is contract's OSI (Option Symbology Initiative) name/code
15
+ alias osi local_symbol
16
+
17
+ def osi= value
18
+ # Normalize to 21 char
19
+ self.local_symbol = value.sub(/ /, ' '*(22-value.size))
20
+ end
21
+
22
+ # Make valid IB Contract definition from OSI (Option Symbology Initiative) code.
23
+ # NB: Simply making a new Contract with *local_symbol* (osi) property set to a
24
+ # valid OSI code works just as well, just do NOT set *expiry*, *right* or
25
+ # *strike* properties in this case.
26
+ # This class method provided as a backup and shows how to analyse OSI codes.
27
+ def self.from_osi osi
28
+
29
+ # Parse contract's OSI (OCC Option Symbology Initiative) code
30
+ args = osi.match(/(\w+)\s?(\d\d)(\d\d)(\d\d)([pcPC])(\d+)/).to_a.drop(1)
31
+ symbol = args.shift
32
+ year = 2000 + args.shift.to_i
33
+ month = args.shift.to_i
34
+ day = args.shift.to_i
35
+ right = args.shift.upcase
36
+ strike = args.shift.to_i/1000.0
37
+
38
+ # Set correct expiry date - IB expiry date differs from OSI if expiry date
39
+ # falls on Saturday (see https://github.com/arvicco/option_mower/issues/4)
40
+ expiry_date = Time.utc(year, month, day)
41
+ expiry_date = Time.utc(year, month, day-1) if expiry_date.wday == 6
42
+
43
+ new :symbol => symbol,
44
+ :exchange => "SMART",
45
+ :expiry => expiry_date.to_ib[2..7], # YYMMDD
46
+ :right => right,
47
+ :strike => strike
48
+ end
49
+
50
+ def default_attributes
51
+ super.merge :sec_type => :option
52
+ #self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
53
+ end
54
+
55
+ def to_human
56
+ "<Option: " + [symbol, expiry, right, strike, exchange, currency].join(" ") + ">"
57
+ end
58
+
59
+ end # class Option
60
+ end # module IB