Class: IB::Contract

Inherits:
Model show all
Includes:
BaseProperties
Defined in:
lib/models/ib/contract.rb,
lib/models/ib/contract.rb

Overview

IB.send(:remove_const, ‘Contract’)

Direct Known Subclasses

Bag, Forex, Future, Index, Option, Stock

Constant Summary collapse

Subclasses =

Contract subclasses representing specialized security types.

Hash.new(Contract)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BaseProperties

#content_attributes, #invariant_attributes, #set_attribute_defaults, #update_missing

Instance Attribute Details

#descriptionObject

NB: local to ib, not part of TWS.



75
76
77
# File 'lib/models/ib/contract.rb', line 75

def description
  @description
end

Class Method Details

.build(opts = {}) ⇒ Object

the method is also used to copy Contract.values to new instances



408
409
410
411
# File 'lib/models/ib/contract.rb', line 408

def self.build opts = {}
  subclass =( VALUES[:sec_type][opts[:sec_type]] || opts['sec_type'] || opts[:sec_type]).to_sym
  Contract::Subclasses[subclass].new opts
end

.from_ib_rubyObject

This returns a Contract initialized from the serialize_ib_ruby format string.



414
415
416
417
418
419
420
# File 'lib/models/ib/contract.rb', line 414

def self.from_ib_ruby 
  keys = [:con_id, :symbol, :sec_type, :expiry, :strike, :right, :multiplier,
          :exchange, :primary_exchange, :currency, :local_symbol]
  props = Hash[keys.zip(string.split(":"))]
  props.delete_if { |k, v| v.nil? || v.empty? }
  Contract.build props
end

Instance Method Details

#==(other) ⇒ Object

Contract comparison



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/models/ib/contract.rb', line 247

def == other  # :nodoc: 
      return false if !other.is_a?(Contract)
  return true if super(other)
      return true if !con_id.to_i.zero?  && con_id == other.con_id

  return false unless other.is_a?(self.class)

  # Different sec_id_type
  return false if sec_id_type && other.sec_id_type && sec_id_type != other.sec_id_type

  # Different sec_id
  return false if sec_id && other.sec_id && sec_id != other.sec_id

  # Different symbols
  return false if symbol && other.symbol && symbol != other.symbol

  # Different currency
  return false if currency && other.currency && currency != other.currency

  # Same con_id for all Bags, but unknown for new Contracts...
  # 0 or nil con_id  matches any
  return false if con_id != 0 && other.con_id != 0 &&
    con_id && other.con_id && con_id != other.con_id

  # SMART or nil exchange matches any
  return false if exchange != 'SMART' && other.exchange != 'SMART' &&
    exchange && other.exchange && exchange != other.exchange

  # Comparison for Bonds and Options
  if bond? || option?
    return false if right != other.right || strike != other.strike
    return false if multiplier && other.multiplier &&
      multiplier != other.multiplier
    return false if expiry && expiry[0..5] != other.expiry[0..5]
    return false unless expiry && (expiry[6..7] == other.expiry[6..7] ||
                                   expiry[6..7].empty? || other.expiry[6..7].empty?)
  end

  # All else being equal...
  sec_type == other.sec_type
end

#bag?Boolean

depreciated : use is_a?(IB::Stock, IB::Bond, IB::Bag etc) instead

Returns:

  • (Boolean)


319
320
321
# File 'lib/models/ib/contract.rb', line 319

def bag?  #  :nodoc:
  self[:sec_type] == 'BAG'
end

#bond?Boolean

:nodoc:

Returns:

  • (Boolean)


323
324
325
326
# File 'lib/models/ib/contract.rb', line 323

def bond?  #  :nodoc:

  self[:sec_type] == 'BOND'
end

#default_attributesObject

:nodoc:



120
121
122
123
124
125
126
# File 'lib/models/ib/contract.rb', line 120

def default_attributes  # :nodoc:
  super.merge :con_id => 0,
    :strike => 0.0,
    :right => :none, # Not an option
   # :exchange => 'SMART',
    :include_expired => false
end

#essentialObject

extracts essential attributes of the contract, and returns a new contract.

the link to contract-details is __not__ maintained.



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/models/ib/contract.rb', line 218

def  essential

  self_attributes = [ :sec_type]
  the_attributes = [ :symbol , :con_id,   :exchange, :right, 
                :currency, :expiry,  :strike,   :local_symbol, :last_trading_day,
            :multiplier,  :primary_exchange, :trading_class ]
  the_hash= the_attributes.map{|x| y= self.send(x);  [x,y] if y.present? }.compact.to_h
  the_hash[:description] = 
     if @description.present? 
        @description 
     elsif contract_detail.present?
       contract_detail.long_name
     else 
       ""
     end
  self.class.new   the_hash.merge( self_attributes.map{|x| y = self.send(x);  [x,y] unless y == :none }.compact.to_h )
end

#expiryObject

IB-ruby uses expiry to query Contracts.

The response from the TWS is stored in ‘last_trading_day’ (Contract) and ‘real_expiration_data’ (ContractDetails)

However, after querying a contract, ‘expiry’ ist overwritten by ‘last_trading_day’. The original ‘expiry’ is still available through ‘attributes



366
367
368
369
370
371
372
# File 'lib/models/ib/contract.rb', line 366

def expiry
  if self.last_trading_day.present?
    last_trading_day.gsub(/-/,'')
  else
    @attributes[:expiry]
  end
end

#index?Boolean

:nodoc:

Returns:

  • (Boolean)


338
339
340
341
# File 'lib/models/ib/contract.rb', line 338

def index?  #  :nodoc:

  self[:sec_type] == 'IND'
end

#merge(**new_attributes) ⇒ Object

creates a new Contract substituting attributes by the provided key-value pairs.

con_id is resetted



240
241
242
243
# File 'lib/models/ib/contract.rb', line 240

def merge **new_attributes
  self.con_id =  0
  self.class.new attributes.merge new_attributes
end

#option?Boolean

:nodoc:

Returns:

  • (Boolean)


333
334
335
336
# File 'lib/models/ib/contract.rb', line 333

def option?  #  :nodoc:

  self[:sec_type] == 'OPT'
end

#order_requirementsObject

is read by Account#PlaceOrder to set requirements for contract-types, as NonGuaranteed for stock-spreads



376
377
378
# File 'lib/models/ib/contract.rb', line 376

def order_requirements
  Hash.new
end

#serialize(*fields) ⇒ Object

18/1/18: serialise always includes conid



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/models/ib/contract.rb', line 137

def serialize *fields  # :nodoc:
  print_default = ->(field, default="") { field.blank? ? default : field }
  print_not_zero = ->(field, default="") { field.to_i.zero? ? default : field }
  [(con_id.present? && !con_id.is_a?(Symbol) && con_id.to_i > 0 ? con_id : ""),
   print_default[symbol],
   print_default[self[:sec_type]],
   ( fields.include?(:option) ?
   [ print_default[expiry], 
 print_not_zero[strike], 
 print_default[self[:right]], 
 print_default[multiplier]] : nil ),
   print_default[exchange],
   ( fields.include?(:primary_exchange) ? print_default[primary_exchange]   : nil ) ,
   print_default[currency],
   print_default[local_symbol],
   ( fields.include?(:trading_class) ? print_default[trading_class] : nil ),
   ( fields.include?(:include_expired) ? print_default[include_expired,0] : nil ),
   ( fields.include?(:sec_id_type) ? [print_default[sec_id_type], print_default[sec_id]] : nil )
   ].flatten.compact
end

#serialize_ib_rubyObject

This produces a string uniquely identifying this contract, in the format used for command line arguments in the IB-Ruby examples. The format is:

symbol:sec_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol

Fields not needed for a particular security should be left blank (e.g. strike and right are only relevant for options.)

For example, to query the British pound futures contract trading on Globex expiring in September, 2008, the string is:

GBP:FUT:200809:::62500:GLOBEX::USD:


210
211
212
# File 'lib/models/ib/contract.rb', line 210

def serialize_ib_ruby
  serialize_long.join(":")
end

#serialize_legs(*fields) ⇒ Object

Defined in Contract, not BAG subclass to keep code DRY



185
186
187
188
189
190
191
192
193
194
# File 'lib/models/ib/contract.rb', line 185

def serialize_legs *fields     # :nodoc:
  case
  when !bag?
   [] 
  when combo_legs.empty?
    [0]
  else
    [combo_legs.size, combo_legs.map { |the_leg| the_leg.serialize *fields }].flatten
  end
end

#serialize_long(*fields) ⇒ Object

serialize contract con_id. sec_type, expiry, strike, right, multiplier exchange, primary_exchange, currency, local_symbol, include_expired other fields on demand



161
162
163
# File 'lib/models/ib/contract.rb', line 161

def serialize_long *fields # :nodoc:
  serialize :option, :include_expired, :primary_exchange, :trading_class, *fields
end

#serialize_short(*fields) ⇒ Object

serialize contract con_id. sec_type, expiry, strike, right, multiplier, exchange, primary_exchange, currency, local_symbol other fields on demand acutal used by place_order, request_marketdata, request_market_depth, exercise_options



169
170
171
# File 'lib/models/ib/contract.rb', line 169

def serialize_short *fields  # :nodoc:
  serialize :option, :trading_class, :primary_exchange, *fields
end

#serialize_supershort(*fields) ⇒ Object

used by RequestMarketDepth



175
176
177
# File 'lib/models/ib/contract.rb', line 175

def serialize_supershort *fields  # :nodoc:
  serialize :option, :trading_class,  *fields
end

#serialize_under_comp(*args) ⇒ Object

Serialize under_comp parameters: EClientSocket.java, line 471



180
181
182
# File 'lib/models/ib/contract.rb', line 180

def serialize_under_comp *args   # :nodoc: 
  under_comp ? under_comp.serialize : [false]
end

#stock?Boolean

:nodoc:

Returns:

  • (Boolean)


328
329
330
331
# File 'lib/models/ib/contract.rb', line 328

def stock? #  :nodoc:

  self[:sec_type] == 'STK'
end

#to_humanObject



296
297
298
299
300
301
302
303
304
305
306
# File 'lib/models/ib/contract.rb', line 296

def to_human
  "<Contract: " +
    [symbol,
     sec_type,
     (expiry == '' ? nil : expiry),
     (right == :none ? nil : right),
     (strike == 0 ? nil : strike),
     exchange,
     currency
     ].compact.join(" ") + ">"
end

#to_sObject



289
290
291
292
293
294
# File 'lib/models/ib/contract.rb', line 289

def to_s
  "<Contract: " + instance_variables.map do |key|
    value = send(key[1..-1])
    " #{key}=#{value} (#{value.class}) " unless value.blank? 
  end.compact.join(',') + " >"
end

#to_shortObject



308
309
310
311
312
313
314
315
316
# File 'lib/models/ib/contract.rb', line 308

def to_short
  if expiry.blank? && last_trading_day.blank? 
  "#{symbol}# {exchange}# {currency}"
  elsif expiry.present?
  "#{symbol}(#{strike}) #{right} #{expiry} /#{exchange}/#{currency}"
      else
  "#{symbol}(#{strike}) #{right} #{last_trading_day} /#{exchange}/#{currency}"
  end
end

#verifyObject

:nodoc:



344
345
346
# File 'lib/models/ib/contract.rb', line 344

def verify  # :nodoc:
  error "verify must be overloaded. Please require at least `ib/verify` from the `ib-extenstions` gem "
end