lib/ib-ruby/models/contract.rb in ib-ruby-0.5.21 vs lib/ib-ruby/models/contract.rb in ib-ruby-0.6.1
- old
+ new
@@ -25,183 +25,158 @@
c.exchange, c.primary_exchange, c.currency, c.local_symbol = string.split(":")
c
end
# Fields are Strings unless noted otherwise
- attr_accessor :con_id, # int: The unique contract identifier.
- :symbol, # This is the symbol of the underlying asset.
- :sec_type, # Security type. Valid values are: SECURITY_TYPES
- :expiry, # The expiration date. Use the format YYYYMM.
- :strike, # double: The strike price.
- :right, # Specifies a Put or Call. Valid values are: P, PUT, C, CALL
- :multiplier, # Specifies a future or option contract multiplier
- # String? (only necessary when multiple possibilities exist)
+ prop :con_id, # int: The unique contract identifier.
+ :symbol, # This is the symbol of the underlying asset.
+ :sec_type, # Security type. Valid values are: SECURITY_TYPES
+ :strike, # double: The strike price.
+ :exchange, # The order destination, such as Smart.
+ :currency, # Only needed if there is an ambiguity, e.g. when SMART exchange
+ # and IBM is being requested (IBM can trade in GBP or USD).
- :exchange, # The order destination, such as Smart.
- :currency, # Ambiguities MAY require that currency field be specified,
- # for example, when SMART is the exchange and IBM is being
- # requested (IBM can trade in GBP or USD).
+ :local_symbol, # Local exchange symbol of the underlying asset
+ :include_expired, # When true, contract details requests and historical
+ # data queries can be performed pertaining to expired contracts.
+ # Note: Historical data queries on expired contracts are
+ # limited to the last year of the contracts life, and are
+ # only supported for expired futures contracts.
+ # This field can NOT be set to true for orders.
- :local_symbol, # Local exchange symbol of the underlying asset
- :primary_exchange, # pick a non-aggregate (ie not the SMART) exchange
- # that the contract trades on. DO NOT SET TO SMART.
+ :sec_id_type, # Security identifier, when querying contract details or
+ # when placing orders. Supported identifiers are:
+ # - ISIN (Example: Apple: US0378331005)
+ # - CUSIP (Example: Apple: 037833100)
+ # - SEDOL (6-AN + check digit. Example: BAE: 0263494)
+ # - RIC (exchange-independent RIC Root and exchange-
+ # identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
+ :sec_id, # Unique identifier of the given secIdType.
- :include_expired, # When true, contract details requests and historical
- # data queries can be performed pertaining to expired contracts.
- # Note: Historical data queries on expired contracts are
- # limited to the last year of the contracts life, and are
- # only supported for expired futures contracts.
- # This field can NOT be set to true for orders.
+ # COMBOS
+ :legs_description, # received in OpenOrder for all combos
- :sec_id_type, # Security identifier, when querying contract details or
- # when placing orders. Supported identifiers are:
- # - ISIN (Example: Apple: US0378331005)
- # - CUSIP (Example: Apple: 037833100)
- # - SEDOL (6-AN + check digit. Example: BAE: 0263494)
- # - RIC (exchange-independent RIC Root and exchange-
- # identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
- :sec_id, # Unique identifier of the given secIdType.
+ :multiplier => :i,
+ # Future/option contract multiplier (only needed when multiple possibilities exist)
- # COMBOS
- :legs_description, # received in open order for all combos
- :legs # Dynamic memory structure used to store the leg
- # definitions for this contract.
+ :primary_exchange =>
+ # non-aggregate (ie not the SMART) exchange that the contract trades on.
+ proc { |val|
+ val.upcase! if val.is_a?(String)
+ raise(ArgumentError.new("Don't set primary_exchange to smart")) if val == 'SMART'
+ self[:primary_exchange] = val
+ },
+ :right => # Specifies a Put or Call. Valid input values are: P, PUT, C, CALL
+ proc { |val|
+ self[:right] =
+ case val.to_s.upcase
+ when '', '0', '?'
+ nil
+ when 'PUT', 'P'
+ 'PUT'
+ when 'CALL', 'C'
+ 'CALL'
+ else
+ raise ArgumentError.new("Invalid right '#{val}' (must be one of PUT, CALL, P, C)")
+ end
+ },
+
+ :expiry => # The expiration date. Use the format YYYYMM.
+ proc { |val|
+ self[:expiry] =
+ case val.to_s
+ when /\d{6,8}/
+ val.to_s
+ when nil, ''
+ nil
+ else
+ raise ArgumentError.new("Invalid expiry '#{val}' (must be in format YYYYMM or YYYYMMDD)")
+ end
+ },
+
+ :sec_type => # Security type. Valid values are: SECURITY_TYPES
+ proc { |val|
+ val = nil if !val.nil? && val.empty?
+ unless val.nil? || SECURITY_TYPES.values.include?(val)
+ raise(ArgumentError.new("Invalid security type '#{val}' (must be one of #{SECURITY_TYPES.values}"))
+ end
+ self[:sec_type] = val
+ }
+
# ContractDetails fields are bundled into Contract proper, as it should be
# All fields Strings, unless specified otherwise:
- attr_accessor :summary, # NB: ContractDetails reference - to self!
- :market_name, # The market name for this contract.
- :trading_class, # The trading class name for this contract.
- :min_tick, # double: The minimum price tick.
- :price_magnifier, # int: Allows execution and strike prices to be
- # reported consistently with market data, historical data and the
- # order price: Z on LIFFE is reported in index points, not GBP.
+ prop :market_name, # The market name for this contract.
+ :trading_class, # The trading class name for this contract.
+ :min_tick, # double: The minimum price tick.
+ :price_magnifier, # int: Allows execution and strike prices to be
+ # reported consistently with market data, historical data and the
+ # order price: Z on LIFFE is reported in index points, not GBP.
- :order_types, # The list of valid order types for this contract.
- :valid_exchanges, # The list of exchanges this contract is traded on.
- :under_con_id, # int: The underlying contract ID.
- :long_name, # Descriptive name of the asset.
- :contract_month, # Typically the contract month of the underlying for
- # a futures contract.
+ :order_types, # The list of valid order types for this contract.
+ :valid_exchanges, # The list of exchanges this contract is traded on.
+ :under_con_id, # int: The underlying contract ID.
+ :long_name, # Descriptive name of the asset.
+ :contract_month, # The contract month of the underlying for a futures contract.
- # The industry classification of the underlying/product:
- :industry, # Wide industry. For example, Financial.
- :category, # Industry category. For example, InvestmentSvc.
- :subcategory, # Subcategory. For example, Brokerage.
- :time_zone, # The ID of the time zone for the trading hours of the
- # product. For example, EST.
- :trading_hours, # The trading hours of the product. For example:
- # 20090507:0700-1830,1830-2330;20090508:CLOSED.
- :liquid_hours, # The liquid trading hours of the product. For example,
- # 20090507:0930-1600;20090508:CLOSED.
+ # The industry classification of the underlying/product:
+ :industry, # Wide industry. For example, Financial.
+ :category, # Industry category. For example, InvestmentSvc.
+ :subcategory, # Subcategory. For example, Brokerage.
+ :time_zone, # Time zone for the trading hours of the product. For example, EST.
+ :trading_hours, # The trading hours of the product. For example:
+ # 20090507:0700-1830,1830-2330;20090508:CLOSED.
+ :liquid_hours, # The liquid trading hours of the product. For example,
+ # 20090507:0930-1600;20090508:CLOSED.
- # Bond values:
- :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
- :ratings, # Credit rating of the issuer. Higher credit rating generally
- # indicates a less risky investment. Bond ratings are from
- # Moody's and S&P respectively.
- :desc_append, # Additional descriptive information about the bond.
- :bond_type, # The type of bond, such as "CORP."
- :coupon_type, # The type of bond coupon.
- :callable, # bool: Can be called by the issuer under certain conditions.
- :puttable, # bool: Can be sold back to the issuer under certain conditions
- :coupon, # double: The interest rate used to calculate the amount you
- # will receive in interest payments over the year. default 0
- :convertible, # bool: Can be converted to stock under certain conditions.
- :maturity, # The date on which the issuer must repay bond face value
- :issue_date, # The date the bond was issued.
- :next_option_date, # only if bond has embedded options.
- :next_option_type, # only if bond has embedded options.
- :next_option_partial, # bool: # only if bond has embedded options.
- :notes # Additional notes, if populated for the bond in IB's database
+ # Bond values:
+ :cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
+ :ratings, # Credit rating of the issuer. Higher rating is less risky investment.
+ # Bond ratings are from Moody's and S&P respectively.
+ :desc_append, # Additional descriptive information about the bond.
+ :bond_type, # The type of bond, such as "CORP."
+ :coupon_type, # The type of bond coupon.
+ :callable, # bool: Can be called by the issuer under certain conditions.
+ :puttable, # bool: Can be sold back to the issuer under certain conditions
+ :coupon, # double: The interest rate used to calculate the amount you
+ # will receive in interest payments over the year. default 0
+ :convertible, # bool: Can be converted to stock under certain conditions.
+ :maturity, # The date on which the issuer must repay bond face value
+ :issue_date, # The date the bond was issued.
+ :next_option_date, # only if bond has embedded options.
+ :next_option_type, # only if bond has embedded options.
+ :next_option_partial, # bool: # only if bond has embedded options.
+ :notes # Additional notes, if populated for the bond in IB's database
# Used for Delta-Neutral Combo contracts only!
# UnderComp fields are bundled into Contract proper, as it should be.
- attr_accessor :under_comp, # if not nil, attributes below are sent to server
- #:under_con_id is is already defined in ContractDetails section
- :under_delta, # double: The underlying stock or future delta.
- :under_price # double: The price of the underlying.
+ prop :under_comp, # if not nil, attributes below are sent to server
+ #:under_con_id is is already defined in ContractDetails section
+ :under_delta, # double: The underlying stock or future delta.
+ :under_price # double: The price of the underlying.
attr_accessor :description # NB: local to ib-ruby, not part of TWS.
- alias combo_legs legs
- alias combo_legs= legs=
- alias combo_legs_description legs_description
- alias combo_legs_description= legs_description=
+ DEFAULT_PROPS = {:con_id => 0,
+ :strike => 0,
+ :exchange => 'SMART',
+ :include_expired => false,
- def initialize opts = {}
- # Assign defaults to properties first!
- @con_id = 0
- @strike = 0
- @sec_type = ''
- @exchange = 'SMART'
- @include_expired = false
- @legs = Array.new
+ # These properties are from ContractDetails
+ :under_con_id => 0,
+ :min_tick => 0,
+ :callable => false,
+ :puttable => false,
+ :coupon => 0,
+ :convertible => false,
+ :next_option_partial => false, }
- # These properties are from ContractDetails
- @under_con_id = 0
- @min_tick = 0
- @callable = false
- @puttable = false
- @coupon = 0
- @convertible = false
- @next_option_partial = false
-
- super opts
- end
-
- # This property is from ContractDetails
+ # NB: ContractDetails reference - to self!
def summary
self
end
- # some protective filters
- def primary_exchange= x
- x.upcase! if x.is_a?(String)
-
- # per http://chuckcaplan.com/twsapi/index.php/Class%20Contract
- raise(ArgumentError.new("Don't set primary_exchange to smart")) if x == 'SMART'
-
- @primary_exchange = x
- end
-
- def right= x
- @right =
- case x.to_s.upcase
- when '', '0', '?'
- nil
- when 'PUT', 'P'
- 'PUT'
- when 'CALL', 'C'
- 'CALL'
- else
- raise ArgumentError.new("Invalid right '#{x}' (must be one of PUT, CALL, P, C)")
- end
- end
-
- def expiry= x
- @expiry =
- case x.to_s
- when /\d{6,8}/
- x.to_s
- when ''
- nil
- else
- raise ArgumentError.new("Invalid expiry '#{x}' (must be in format YYYYMM or YYYYMMDD)")
- end
- end
-
- def sec_type= x
- x = nil if !x.nil? && x.empty?
- raise(ArgumentError.new("Invalid security type '#{x}' (must be one of #{SECURITY_TYPES.values}")) unless x.nil? || SECURITY_TYPES.values.include?(x)
- @sec_type = x
- end
-
- def multiplier= x
- @multiplier = x.to_i
- end
-
# This returns an Array of data from the given contract.
# Different messages serialize contracts differently. Go figure.
# Note that it does NOT include the combo legs.
def serialize *fields
[(fields.include?(:con_id) ? [con_id] : []),
@@ -223,26 +198,10 @@
def serialize_short *fields
serialize :option, *fields
end
- # 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:security_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:
- def serialize_ib_ruby version
- serialize.join(":")
- end
-
# Serialize under_comp parameters
def serialize_under_comp *args
# EClientSocket.java, line 471:
if under_comp
[true,
@@ -252,33 +211,31 @@
else
[false]
end
end
- ### Leg-related methods (better suited to BAG subclass?)
-
- # Some messages send open_close too, some don't. WTF.
- # "BAG" is not really a contract, but a combination (combo) of securities.
- # AKA basket or bag of securities. Individual securities in combo are represented
- # by ComboLeg objects.
+ # Redefined in BAG subclass
def serialize_legs *fields
- return [] unless sec_type.upcase == "BAG"
- return [0] if legs.empty? || legs.nil?
- [legs.size, legs.map { |leg| leg.serialize *fields }]
+ []
end
- # Check if two Contracts have same legs (maybe in different order)
- def same_legs? other
- legs == other.legs ||
- legs_description.split(',').sort == other.legs_description.split(',').sort
+ # 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:security_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:
+ def serialize_ib_ruby version
+ serialize.join(":")
end
- # IB-equivalent leg description. TODO: Rewrite with self[:legs_description]
- def legs_description
- @legs_description || legs.map { |leg| "#{leg.con_id}|#{leg.weight}" }.join(',')
- end
-
# Contract comparison
def == other
return false unless other.is_a?(self.class)
# Different sec_id_type
@@ -293,12 +250,9 @@
# Different symbols
return false if symbol && other.symbol && symbol != other.symbol
# Different currency
return false if currency && other.currency && currency != other.currency
-
- # Different legs
- return false unless same_legs? other
# 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