Class: IB::Contract

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

Overview

puts Contract.ancestors IB.send(:remove_const, ‘Contract’)

Direct Known Subclasses

Bag, Forex, Future, Index, Option, Stock

Constant Summary collapse

Subclasses =
Hash.new(Contract)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BaseProperties

#as_table, #content_attributes, #invariant_attributes, #set_attribute_defaults, #update_missing

Instance Attribute Details

#descriptionObject

NB: local to ib, not part of TWS.



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

def description
  @description
end

Class Method Details

.build(opts = {}) ⇒ Object

This builds an appropriate Contract subclass based on its type

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



478
479
480
481
# File 'lib/models/ib/contract.rb', line 478

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

Instance Method Details

#==(other) ⇒ Object

Contract comparison



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/models/ib/contract.rb', line 282

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)


354
355
356
# File 'lib/models/ib/contract.rb', line 354

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

#bond?Boolean

:nodoc:

Returns:

  • (Boolean)


358
359
360
361
# File 'lib/models/ib/contract.rb', line 358

def bond?  #  :nodoc:

  self[:sec_type] == 'BOND'
end

#default_attributesObject

:nodoc:



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

def default_attributes  # :nodoc:
  super.merge :con_id => 0,
    :strike => "",
    :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.



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

def  essential

	the_attributes = [ :sec_type, :symbol , :con_id,   :exchange, :right, 
							  :currency, :expiry,  :strike,   :local_symbol, :last_trading_day,
						:multiplier,  :primary_exchange, :trading_class, :description ]
	new_contract= self.class.new invariant_attributes.select{|k,_| the_attributes.include? k }.compact
    new_contract[:description] = if @description.present? 
                                   @description 
                                 elsif contract_detail.present?
                                   contract_detail.long_name
                                 else 
                                   ""
                                 end
    new_contract # return contract
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



401
402
403
404
405
406
407
# File 'lib/models/ib/contract.rb', line 401

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

#index?Boolean

:nodoc:

Returns:

  • (Boolean)


373
374
375
376
# File 'lib/models/ib/contract.rb', line 373

def index?  #  :nodoc:

  self[:sec_type] == 'IND'
end

#merge(**new_attributes) ⇒ Object

┌────────┬────────┬───────────┬──────────┬──────────┬────────────┬───────────────┬───────┬────────┬──────────┐ │ │ symbol │ con_id │ exchange │ expiry │ multiplier │ trading-class │ right │ strike │ currency │ ╞════════╪════════╪═══════════╪══════════╪══════════╪════════════╪═══════════════╪═══════╪════════╪══════════╡ │ Future │ ES │ 428520022 │ GLOBEX │ 20210917 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 446091461 │ GLOBEX │ 20211217 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 461318816 │ GLOBEX │ 20220318 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 477836957 │ GLOBEX │ 20220617 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512551 │ GLOBEX │ 20221216 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512552 │ GLOBEX │ 20231215 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512557 │ GLOBEX │ 20241220 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512563 │ GLOBEX │ 20251219 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512566 │ GLOBEX │ 20220916 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512569 │ GLOBEX │ 20230616 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 495512572 │ GLOBEX │ 20230317 │ 50 │ ES │ │ │ USD │ │ Future │ ES │ 497222760 │ GLOBEX │ 20230915 │ 50 │ ES │ │ │ USD │ └────────┴────────┴───────────┴──────────┴──────────┴────────────┴───────────────┴───────┴────────┴──────────┘



272
273
274
275
276
277
278
# File 'lib/models/ib/contract.rb', line 272

def merge **new_attributes

    resetted_attributes = [:con_id, :local_symbol, :contract_detail]
    ## last_trading_day / expiry needs special treatment
    resetted_attributes << :last_trading_day if  new_attributes.keys.include? :expiry
    self.class.new attributes.reject{|k,_| resetted_attributes.include? k}.merge(new_attributes)
end

#option?Boolean

:nodoc:

Returns:

  • (Boolean)


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

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



411
412
413
# File 'lib/models/ib/contract.rb', line 411

def order_requirements
	Hash.new
end

#serialize(*fields) ⇒ Object

18/1/18: serialise always includes conid



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

def serialize *fields  # :nodoc:
  print_default = ->(field, default="") { field.blank? ? 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], 
			##  a Zero-Strike-Option  has to be defined with  «strike: -1 »
 strike.present? && ( strike.is_a?(Numeric) && !strike.zero? && strike > 0 )  ?  strike : strike<0 ?  0 : "",
 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:


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

def serialize_ib_ruby
  serialize_long.join(":")
end

#serialize_legs(*fields) ⇒ Object

Defined in Contract, not BAG subclass to keep code DRY



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

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



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

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



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

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

#serialize_supershort(*fields) ⇒ Object

used by RequestMarketDepth



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

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

#serialize_under_comp(*args) ⇒ Object

Serialize under_comp parameters: EClientSocket.java, line 471



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

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

#stock?Boolean

:nodoc:

Returns:

  • (Boolean)


363
364
365
366
# File 'lib/models/ib/contract.rb', line 363

def stock? #  :nodoc:

  self[:sec_type] == 'STK'
end

#table_header(&b) ⇒ Object



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

def table_header( &b )
  if block_given?
  [ yield(self) , 'symbol',  'con_id', 'exchange', 'expiry','multiplier', 'trading-class' , 'right', 'strike', 'currency' ]
  else
  [ '', 'symbol',  'con_id', 'exchange', 'expiry','multiplier', 'trading-class' , 'right', 'strike', 'currency' ]
  end
end

#table_rowObject



424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/models/ib/contract.rb', line 424

def table_row
  [ self.class.to_s.demodulize, symbol, 
    { value: con_id.zero? ? '' : con_id , alignment: :right}, 
     { value: exchange, alignment: :center}, 
     expiry, 
     { value: multiplier.zero??  "" : multiplier, alignment: :center}, 
     { value: trading_class, alignment: :center},
     {value: right == :none ? "": right, alignment: :center }, 
     { value: strike.zero? ? "": strike, alignment: :right}, 
     { value: currency, alignment: :center} ]

end

#to_humanObject



331
332
333
334
335
336
337
338
339
340
341
# File 'lib/models/ib/contract.rb', line 331

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



324
325
326
327
328
329
# File 'lib/models/ib/contract.rb', line 324

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



343
344
345
346
347
348
349
350
351
# File 'lib/models/ib/contract.rb', line 343

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:



379
380
381
# File 'lib/models/ib/contract.rb', line 379

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