ib-ruby 0.8.1 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/HISTORY +5 -0
- data/README.md +47 -53
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/app/assets/javascripts/ib/application.js +15 -0
- data/app/assets/javascripts/ib/underlyings.js +2 -0
- data/app/assets/stylesheets/ib/application.css +13 -0
- data/app/assets/stylesheets/ib/underlyings.css +4 -0
- data/app/assets/stylesheets/scaffold.css +56 -0
- data/app/controllers/ib/application_controller.rb +5 -0
- data/app/controllers/ib/underlyings_controller.rb +87 -0
- data/app/helpers/ib/application_helper.rb +4 -0
- data/app/helpers/ib/underlyings_helper.rb +4 -0
- data/app/models/ib/underlying.rb +5 -0
- data/app/views/ib/underlyings/_form.html.erb +33 -0
- data/app/views/ib/underlyings/edit.html.erb +6 -0
- data/app/views/ib/underlyings/index.html.erb +29 -0
- data/app/views/ib/underlyings/new.html.erb +5 -0
- data/app/views/ib/underlyings/show.html.erb +25 -0
- data/app/views/layouts/ib/application.html.erb +14 -0
- data/config/routes.rb +6 -0
- data/db/config.yml +19 -0
- data/db/migrate/{101_add_executions.rb → 101_add_ib_executions.rb} +2 -2
- data/db/migrate/{111_add_bars.rb → 111_add_ib_bars.rb} +2 -2
- data/db/migrate/{121_add_order_states.rb → 121_add_ib_order_states.rb} +2 -2
- data/db/migrate/{131_add_orders.rb → 131_add_ib_orders.rb} +2 -2
- data/db/migrate/{141_add_combo_legs.rb → 141_add_ib_combo_legs.rb} +2 -2
- data/db/migrate/{151_add_underlyings.rb → 151_add_ib_underlyings.rb} +2 -2
- data/db/migrate/{161_add_contract_details.rb → 161_add_ib_contract_details.rb} +2 -2
- data/db/migrate/{171_add_contracts.rb → 171_add_ib_contracts.rb} +2 -2
- data/db/schema.rb +245 -0
- data/lib/ib/base.rb +97 -0
- data/lib/ib/base_properties.rb +140 -0
- data/lib/{ib-ruby → ib}/connection.rb +2 -2
- data/lib/{ib-ruby → ib}/constants.rb +0 -0
- data/lib/{ib-ruby → ib}/db.rb +9 -5
- data/lib/ib/engine.rb +35 -0
- data/lib/{ib-ruby → ib}/errors.rb +0 -0
- data/lib/{ib-ruby → ib}/extensions.rb +2 -2
- data/lib/{ib-ruby → ib}/logger.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/abstract_message.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/abstract_message.rb +1 -1
- data/lib/{ib-ruby → ib}/messages/incoming/alert.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/contract_data.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/delta_neutral_validation.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/execution_data.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/historical_data.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/market_depths.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/next_valid_id.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/open_order.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/order_status.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/portfolio_value.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/real_time_bar.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/scanner_data.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming/ticks.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/incoming.rb +14 -14
- data/lib/{ib-ruby → ib}/messages/outgoing/abstract_message.rb +1 -1
- data/lib/{ib-ruby → ib}/messages/outgoing/bar_requests.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/outgoing/place_order.rb +0 -0
- data/lib/{ib-ruby → ib}/messages/outgoing.rb +5 -5
- data/lib/ib/messages.rb +8 -0
- data/lib/ib/model.rb +8 -0
- data/lib/ib/models.rb +10 -0
- data/lib/ib/requires.rb +9 -0
- data/lib/{ib-ruby → ib}/socket.rb +0 -0
- data/lib/{ib-ruby → ib}/symbols/forex.rb +1 -1
- data/lib/{ib-ruby → ib}/symbols/futures.rb +2 -2
- data/lib/{ib-ruby → ib}/symbols/options.rb +1 -1
- data/lib/{ib-ruby → ib}/symbols/stocks.rb +1 -1
- data/lib/ib/symbols.rb +9 -0
- data/lib/{ib-ruby → ib}/version.rb +0 -0
- data/lib/ib-ruby.rb +2 -24
- data/lib/ib.rb +23 -0
- data/lib/models/ib/bag.rb +51 -0
- data/lib/models/ib/bar.rb +41 -0
- data/lib/models/ib/combo_leg.rb +102 -0
- data/lib/models/ib/contract.rb +287 -0
- data/lib/models/ib/contract_detail.rb +68 -0
- data/lib/models/ib/execution.rb +62 -0
- data/lib/models/ib/option.rb +60 -0
- data/lib/models/ib/order.rb +389 -0
- data/lib/models/ib/order_state.rb +126 -0
- data/lib/models/ib/underlying.rb +35 -0
- data/spec/README.md +34 -2
- data/spec/TODO +5 -1
- data/spec/comb.rb +13 -0
- data/spec/db.rb +1 -1
- data/spec/db_helper.rb +3 -3
- data/spec/dummy.rb +13 -0
- data/spec/gw.rb +4 -0
- data/spec/{ib-ruby → ib}/connection_spec.rb +0 -0
- data/spec/{ib-ruby → ib}/messages/incoming/alert_spec.rb +0 -0
- data/spec/{ib-ruby → ib}/messages/incoming/open_order_spec.rb +0 -0
- data/spec/{ib-ruby → ib}/messages/incoming/order_status_spec.rb +16 -17
- data/spec/{ib-ruby → ib}/messages/outgoing/account_data_spec.rb +0 -0
- data/spec/{ib-ruby → ib}/messages/outgoing/market_data_type_spec.rb +0 -0
- data/spec/integration/historic_data_spec.rb +3 -3
- data/spec/integration/orders/trades_spec.rb +1 -1
- data/spec/{ib-ruby/models → models/ib}/bag_spec.rb +2 -7
- data/spec/{ib-ruby/models → models/ib}/bar_spec.rb +1 -6
- data/spec/{ib-ruby/models → models/ib}/combo_leg_spec.rb +2 -12
- data/spec/{ib-ruby/models → models/ib}/contract_detail_spec.rb +3 -8
- data/spec/{ib-ruby/models → models/ib}/contract_spec.rb +4 -12
- data/spec/{ib-ruby/models → models/ib}/execution_spec.rb +2 -7
- data/spec/{ib-ruby/models → models/ib}/option_spec.rb +1 -6
- data/spec/{ib-ruby/models → models/ib}/order_spec.rb +5 -10
- data/spec/{ib-ruby/models → models/ib}/order_state_spec.rb +2 -7
- data/spec/{ib-ruby/models → models/ib}/underlying_spec.rb +3 -7
- data/spec/my.rb +5 -0
- data/spec/spec_helper.rb +62 -36
- metadata +417 -544
- data/lib/ib-ruby/messages.rb +0 -8
- data/lib/ib-ruby/models/bag.rb +0 -54
- data/lib/ib-ruby/models/bar.rb +0 -43
- data/lib/ib-ruby/models/combo_leg.rb +0 -104
- data/lib/ib-ruby/models/contract.rb +0 -287
- data/lib/ib-ruby/models/contract_detail.rb +0 -70
- data/lib/ib-ruby/models/execution.rb +0 -64
- data/lib/ib-ruby/models/model.rb +0 -105
- data/lib/ib-ruby/models/model_properties.rb +0 -146
- data/lib/ib-ruby/models/option.rb +0 -62
- data/lib/ib-ruby/models/order.rb +0 -389
- data/lib/ib-ruby/models/order_state.rb +0 -128
- data/lib/ib-ruby/models/underlying.rb +0 -36
- data/lib/ib-ruby/models.rb +0 -15
- data/lib/ib-ruby/symbols.rb +0 -9
- data/spec/test.rb +0 -61
data/lib/ib-ruby/messages.rb
DELETED
data/lib/ib-ruby/models/bag.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'ib-ruby/models/contract'
|
2
|
-
|
3
|
-
module IB
|
4
|
-
module Models
|
5
|
-
|
6
|
-
# "BAG" is not really a contract, but a combination (combo) of securities.
|
7
|
-
# AKA basket or bag of securities. Individual securities in combo are represented
|
8
|
-
# by ComboLeg objects.
|
9
|
-
class Bag < Contract
|
10
|
-
# General Notes:
|
11
|
-
# 1. :exchange for the leg definition must match that of the combination order.
|
12
|
-
# The exception is for a STK legs, which must specify the SMART exchange.
|
13
|
-
# 2. :symbol => "USD" For combo Contract, this is an arbitrary value (like "USD")
|
14
|
-
|
15
|
-
validates_format_of :sec_type, :with => /^bag$/, :message => "should be a bag"
|
16
|
-
validates_format_of :right, :with => /^none$/, :message => "should be none"
|
17
|
-
validates_format_of :expiry, :with => /^$/, :message => "should be blank"
|
18
|
-
|
19
|
-
def default_attributes
|
20
|
-
super.merge :sec_type => :bag #,:legs => Array.new,
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def description
|
25
|
-
self[:description] || to_human
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_human
|
29
|
-
"<Bag: #{[symbol, exchange, currency].join(' ')} legs: #{legs_description} >"
|
30
|
-
end
|
31
|
-
|
32
|
-
### Leg-related methods
|
33
|
-
|
34
|
-
# TODO: Rewrite with legs and legs_description being strictly in sync...
|
35
|
-
# TODO: Find a way to serialize legs without references...
|
36
|
-
# IB-equivalent leg description.
|
37
|
-
def legs_description
|
38
|
-
self[:legs_description] || legs.map { |leg| "#{leg.con_id}|#{leg.weight}" }.join(',')
|
39
|
-
end
|
40
|
-
|
41
|
-
# Check if two Contracts have same legs (maybe in different order)
|
42
|
-
def same_legs? other
|
43
|
-
legs == other.legs ||
|
44
|
-
legs_description.split(',').sort == other.legs_description.split(',').sort
|
45
|
-
end
|
46
|
-
|
47
|
-
# Contract comparison
|
48
|
-
def == other
|
49
|
-
super && same_legs?(other)
|
50
|
-
end
|
51
|
-
|
52
|
-
end # class Bag
|
53
|
-
end # Models
|
54
|
-
end # IB
|
data/lib/ib-ruby/models/bar.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module IB
|
2
|
-
module Models
|
3
|
-
# This is a single data point delivered by HistoricData or RealTimeBar messages.
|
4
|
-
# Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
|
5
|
-
class Bar < Model.for(:bar)
|
6
|
-
include ModelProperties
|
7
|
-
|
8
|
-
prop :open, # The bar opening price.
|
9
|
-
:high, # The high price during the time covered by the bar.
|
10
|
-
:low, # The low price during the time covered by the bar.
|
11
|
-
:close, # The bar closing price.
|
12
|
-
:volume, # Volume
|
13
|
-
:wap, # Weighted average price during the time covered by the bar.
|
14
|
-
:trades, # int: When TRADES data history is returned, represents number
|
15
|
-
# of trades that occurred during the time period the bar covers
|
16
|
-
:time, # TODO: convert into Time object?
|
17
|
-
# The date-time stamp of the start of the bar. The format is
|
18
|
-
# determined by the reqHistoricalData() formatDate parameter.
|
19
|
-
:has_gaps => :bool # Whether or not there are gaps in the data.
|
20
|
-
|
21
|
-
validates_numericality_of :open, :high, :low, :close, :volume
|
22
|
-
|
23
|
-
# Order comparison
|
24
|
-
def == other
|
25
|
-
time == other.time &&
|
26
|
-
open == other.open &&
|
27
|
-
high == other.high &&
|
28
|
-
low == other.low &&
|
29
|
-
close == other.close &&
|
30
|
-
wap == other.wap &&
|
31
|
-
trades == other.trades &&
|
32
|
-
volume == other.volume
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_human
|
36
|
-
"<Bar: #{time} wap #{wap} OHLC #{open} #{high} #{low} #{close} " +
|
37
|
-
(trades ? "trades #{trades}" : "") + " vol #{volume} gaps #{has_gaps}>"
|
38
|
-
end
|
39
|
-
|
40
|
-
alias to_s to_human
|
41
|
-
end # class Bar
|
42
|
-
end # module Models
|
43
|
-
end # module IB
|
@@ -1,104 +0,0 @@
|
|
1
|
-
module IB
|
2
|
-
module Models
|
3
|
-
|
4
|
-
# ComboLeg is essentially a join Model between Combo (BAG) Contract and
|
5
|
-
# individual Contracts (securities) that this BAG contains.
|
6
|
-
class ComboLeg < Model.for(:combo_leg)
|
7
|
-
include ModelProperties
|
8
|
-
|
9
|
-
# BAG Combo Contract that contains this Leg
|
10
|
-
belongs_to :combo, :class_name => 'Contract'
|
11
|
-
# Contract that constitutes this Leg
|
12
|
-
belongs_to :leg_contract, :class_name => 'Contract', :foreign_key => :leg_contract_id
|
13
|
-
|
14
|
-
# General Notes:
|
15
|
-
# 1. The exchange for the leg definition must match that of the combination order.
|
16
|
-
# The exception is for a STK leg definition, which must specify the SMART exchange.
|
17
|
-
|
18
|
-
prop :con_id, # int: The unique contract identifier specifying the security.
|
19
|
-
:ratio, # int: Select the relative number of contracts for the leg you
|
20
|
-
# are constructing. To help determine the ratio for a
|
21
|
-
# specific combination order, refer to the Interactive
|
22
|
-
# Analytics section of the User's Guide.
|
23
|
-
|
24
|
-
:exchange, # String: exchange to which the complete combo order will be routed.
|
25
|
-
# For institutional customers only! For stock legs when doing short sale
|
26
|
-
:short_sale_slot, # int: 0 - retail(default), 1 = clearing broker, 2 = third party
|
27
|
-
:designated_location, # String: Only for shortSaleSlot == 2.
|
28
|
-
# Otherwise leave blank or orders will be rejected.
|
29
|
-
:exempt_code, # int: ?
|
30
|
-
[:side, :action] => PROPS[:side], # String: Action/side: BUY/SELL/SSHORT/SSHORTX
|
31
|
-
:open_close => PROPS[:open_close]
|
32
|
-
# int: Whether the order is an open or close order. Values:
|
33
|
-
# SAME = 0 Same as the parent security. The only option for retail customers.
|
34
|
-
# OPEN = 1 Open. This value is only valid for institutional customers.
|
35
|
-
# CLOSE = 2 Close. This value is only valid for institutional customers.
|
36
|
-
# UNKNOWN = 3
|
37
|
-
|
38
|
-
# Extra validations
|
39
|
-
validates_numericality_of :ratio, :con_id
|
40
|
-
validates_format_of :designated_location, :with => /^$/,
|
41
|
-
:message => "should be blank or orders will be rejected"
|
42
|
-
|
43
|
-
def default_attributes
|
44
|
-
super.merge :con_id => 0,
|
45
|
-
:ratio => 1,
|
46
|
-
:side => :buy,
|
47
|
-
:open_close => :same, # The only option for retail customers.
|
48
|
-
:short_sale_slot => :default,
|
49
|
-
:designated_location => '',
|
50
|
-
:exchange => 'SMART', # Unless SMART, Order modification fails
|
51
|
-
:exempt_code => -1
|
52
|
-
end
|
53
|
-
|
54
|
-
# Leg's weight is a combination of action and ratio
|
55
|
-
def weight
|
56
|
-
side == :buy ? ratio : -ratio
|
57
|
-
end
|
58
|
-
|
59
|
-
def weight= value
|
60
|
-
value = value.to_i
|
61
|
-
if value > 0
|
62
|
-
self.side = :buy
|
63
|
-
self.ratio = value
|
64
|
-
else
|
65
|
-
self.side = :sell
|
66
|
-
self.ratio = -value
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Some messages include open_close, some don't. wtf.
|
71
|
-
def serialize *fields
|
72
|
-
[con_id,
|
73
|
-
ratio,
|
74
|
-
side.to_sup,
|
75
|
-
exchange,
|
76
|
-
(fields.include?(:extended) ?
|
77
|
-
[self[:open_close],
|
78
|
-
self[:short_sale_slot],
|
79
|
-
designated_location,
|
80
|
-
exempt_code] :
|
81
|
-
[])
|
82
|
-
].flatten
|
83
|
-
end
|
84
|
-
|
85
|
-
def to_human
|
86
|
-
"<ComboLeg: #{side} #{ratio} con_id #{con_id} at #{exchange}>"
|
87
|
-
end
|
88
|
-
|
89
|
-
# Order comparison
|
90
|
-
def == other
|
91
|
-
other && other.is_a?(ComboLeg) &&
|
92
|
-
con_id == other.con_id &&
|
93
|
-
ratio == other.ratio &&
|
94
|
-
open_close == other.open_close &&
|
95
|
-
short_sale_slot == other.short_sale_slot&&
|
96
|
-
exempt_code == other.exempt_code &&
|
97
|
-
side == other.side &&
|
98
|
-
exchange == other.exchange &&
|
99
|
-
designated_location == other.designated_location
|
100
|
-
end
|
101
|
-
|
102
|
-
end # ComboLeg
|
103
|
-
end # module Models
|
104
|
-
end # module IB
|
@@ -1,287 +0,0 @@
|
|
1
|
-
require 'ib-ruby/models/contract_detail'
|
2
|
-
require 'ib-ruby/models/underlying'
|
3
|
-
|
4
|
-
module IB
|
5
|
-
module Models
|
6
|
-
class Contract < Model.for(:contract)
|
7
|
-
include ModelProperties
|
8
|
-
|
9
|
-
# Fields are Strings unless noted otherwise
|
10
|
-
prop :con_id, # int: The unique contract identifier.
|
11
|
-
:currency, # Only needed if there is an ambiguity, e.g. when SMART exchange
|
12
|
-
# and IBM is being requested (IBM can trade in GBP or USD).
|
13
|
-
|
14
|
-
:legs_description, # received in OpenOrder for all combos
|
15
|
-
|
16
|
-
:sec_type, # Security type. Valid values are: SECURITY_TYPES
|
17
|
-
|
18
|
-
:sec_id, # Unique identifier of the given secIdType.
|
19
|
-
|
20
|
-
:sec_id_type => :sup, # Security identifier, when querying contract details or
|
21
|
-
# when placing orders. Supported identifiers are:
|
22
|
-
# - ISIN (Example: Apple: US0378331005)
|
23
|
-
# - CUSIP (Example: Apple: 037833100)
|
24
|
-
# - SEDOL (6-AN + check digit. Example: BAE: 0263494)
|
25
|
-
# - RIC (exchange-independent RIC Root and exchange-
|
26
|
-
# identifying suffix. Ex: AAPL.O for Apple on NASDAQ.)
|
27
|
-
|
28
|
-
:symbol => :s, # This is the symbol of the underlying asset.
|
29
|
-
|
30
|
-
:local_symbol => :s, # Local exchange symbol of the underlying asset
|
31
|
-
|
32
|
-
# Future/option contract multiplier (only needed when multiple possibilities exist)
|
33
|
-
:multiplier => {:set => :i},
|
34
|
-
|
35
|
-
:strike => :f, # double: The strike price.
|
36
|
-
:expiry => :s, # The expiration date. Use the format YYYYMM or YYYYMMDD
|
37
|
-
:exchange => :sup, # The order destination, such as Smart.
|
38
|
-
:primary_exchange => :sup, # Non-SMART exchange where the contract trades.
|
39
|
-
:include_expired => :bool, # When true, contract details requests and historical
|
40
|
-
# data queries can be performed pertaining to expired contracts.
|
41
|
-
# Note: Historical data queries on expired contracts are
|
42
|
-
# limited to the last year of the contracts life, and are
|
43
|
-
# only supported for expired futures contracts.
|
44
|
-
# This field can NOT be set to true for orders.
|
45
|
-
|
46
|
-
|
47
|
-
# Specifies a Put or Call. Valid input values are: P, PUT, C, CALL
|
48
|
-
:right =>
|
49
|
-
{:set => proc { |val|
|
50
|
-
self[:right] =
|
51
|
-
case val.to_s.upcase
|
52
|
-
when 'NONE', '', '0', '?'
|
53
|
-
''
|
54
|
-
when 'PUT', 'P'
|
55
|
-
'P'
|
56
|
-
when 'CALL', 'C'
|
57
|
-
'C'
|
58
|
-
else
|
59
|
-
val
|
60
|
-
end },
|
61
|
-
:validate => {:format => {:with => /^put$|^call$|^none$/,
|
62
|
-
:message => "should be put, call or none"}}
|
63
|
-
}
|
64
|
-
|
65
|
-
attr_accessor :description # NB: local to ib-ruby, not part of TWS.
|
66
|
-
|
67
|
-
### Associations
|
68
|
-
|
69
|
-
has_many :orders # Placed for this Contract
|
70
|
-
|
71
|
-
has_one :contract_detail # Volatile info about this Contract
|
72
|
-
|
73
|
-
# For Contracts that are part of BAG
|
74
|
-
has_one :leg, :class_name => 'ComboLeg', :foreign_key => :leg_contract_id
|
75
|
-
has_one :combo, :class_name => 'Contract', :through => :leg
|
76
|
-
|
77
|
-
# for Combo/BAG Contracts that contain ComboLegs
|
78
|
-
has_many :combo_legs, :foreign_key => :combo_id
|
79
|
-
has_many :leg_contracts, :class_name => 'Contract', :through => :combo_legs
|
80
|
-
alias legs combo_legs
|
81
|
-
alias legs= combo_legs=
|
82
|
-
alias combo_legs_description legs_description
|
83
|
-
alias combo_legs_description= legs_description=
|
84
|
-
|
85
|
-
# for Delta-Neutral Combo Contracts
|
86
|
-
has_one :underlying
|
87
|
-
alias under_comp underlying
|
88
|
-
alias under_comp= underlying=
|
89
|
-
|
90
|
-
|
91
|
-
### Extra validations
|
92
|
-
validates_inclusion_of :sec_type, :in => CODES[:sec_type].keys,
|
93
|
-
:message => "should be valid security type"
|
94
|
-
|
95
|
-
validates_format_of :expiry, :with => /^\d{6}$|^\d{8}$|^$/,
|
96
|
-
:message => "should be YYYYMM or YYYYMMDD"
|
97
|
-
|
98
|
-
validates_format_of :primary_exchange, :without => /SMART/,
|
99
|
-
:message => "should not be SMART"
|
100
|
-
|
101
|
-
validates_format_of :sec_id_type, :with => /ISIN|SEDOL|CUSIP|RIC|^$/,
|
102
|
-
:message => "should be valid security identifier"
|
103
|
-
|
104
|
-
validates_numericality_of :multiplier, :strike, :allow_nil => true
|
105
|
-
|
106
|
-
def default_attributes
|
107
|
-
super.merge :con_id => 0,
|
108
|
-
:strike => 0.0,
|
109
|
-
:right => :none, # Not an option
|
110
|
-
:exchange => 'SMART',
|
111
|
-
:include_expired => false
|
112
|
-
end
|
113
|
-
|
114
|
-
# This returns an Array of data from the given contract.
|
115
|
-
# Different messages serialize contracts differently. Go figure.
|
116
|
-
# Note that it does NOT include the combo legs.
|
117
|
-
# serialize [:option, :con_id, :include_expired, :sec_id]
|
118
|
-
def serialize *fields
|
119
|
-
[(fields.include?(:con_id) ? [con_id] : []),
|
120
|
-
symbol,
|
121
|
-
self[:sec_type],
|
122
|
-
(fields.include?(:option) ?
|
123
|
-
[expiry,
|
124
|
-
strike,
|
125
|
-
self[:right],
|
126
|
-
multiplier] : []),
|
127
|
-
exchange,
|
128
|
-
(fields.include?(:primary_exchange) ? [primary_exchange] : []),
|
129
|
-
currency,
|
130
|
-
local_symbol,
|
131
|
-
(fields.include?(:sec_id) ? [sec_id_type, sec_id] : []),
|
132
|
-
(fields.include?(:include_expired) ? [include_expired] : []),
|
133
|
-
].flatten
|
134
|
-
end
|
135
|
-
|
136
|
-
def serialize_long *fields
|
137
|
-
serialize :option, :primary_exchange, *fields
|
138
|
-
end
|
139
|
-
|
140
|
-
def serialize_short *fields
|
141
|
-
serialize :option, *fields
|
142
|
-
end
|
143
|
-
|
144
|
-
# Serialize under_comp parameters: EClientSocket.java, line 471
|
145
|
-
def serialize_under_comp *args
|
146
|
-
under_comp ? under_comp.serialize : [false]
|
147
|
-
end
|
148
|
-
|
149
|
-
# Defined in Contract, not BAG subclass to keep code DRY
|
150
|
-
def serialize_legs *fields
|
151
|
-
case
|
152
|
-
when !bag?
|
153
|
-
[]
|
154
|
-
when legs.empty?
|
155
|
-
[0]
|
156
|
-
else
|
157
|
-
[legs.size, legs.map { |leg| leg.serialize *fields }].flatten
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
# This produces a string uniquely identifying this contract, in the format used
|
162
|
-
# for command line arguments in the IB-Ruby examples. The format is:
|
163
|
-
#
|
164
|
-
# symbol:sec_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
|
165
|
-
#
|
166
|
-
# Fields not needed for a particular security should be left blank
|
167
|
-
# (e.g. strike and right are only relevant for options.)
|
168
|
-
#
|
169
|
-
# For example, to query the British pound futures contract trading on Globex
|
170
|
-
# expiring in September, 2008, the string is:
|
171
|
-
#
|
172
|
-
# GBP:FUT:200809:::62500:GLOBEX::USD:
|
173
|
-
def serialize_ib_ruby
|
174
|
-
serialize_long.join(":")
|
175
|
-
end
|
176
|
-
|
177
|
-
# Contract comparison
|
178
|
-
def == other
|
179
|
-
return false unless other.is_a?(self.class)
|
180
|
-
|
181
|
-
# Different sec_id_type
|
182
|
-
return false if sec_id_type && other.sec_id_type && sec_id_type != other.sec_id_type
|
183
|
-
|
184
|
-
# Different sec_id
|
185
|
-
return false if sec_id && other.sec_id && sec_id != other.sec_id
|
186
|
-
|
187
|
-
# Different symbols
|
188
|
-
return false if symbol && other.symbol && symbol != other.symbol
|
189
|
-
|
190
|
-
# Different currency
|
191
|
-
return false if currency && other.currency && currency != other.currency
|
192
|
-
|
193
|
-
# Same con_id for all Bags, but unknown for new Contracts...
|
194
|
-
# 0 or nil con_id matches any
|
195
|
-
return false if con_id != 0 && other.con_id != 0 &&
|
196
|
-
con_id && other.con_id && con_id != other.con_id
|
197
|
-
|
198
|
-
# SMART or nil exchange matches any
|
199
|
-
return false if exchange != 'SMART' && other.exchange != 'SMART' &&
|
200
|
-
exchange && other.exchange && exchange != other.exchange
|
201
|
-
|
202
|
-
# Comparison for Bonds and Options
|
203
|
-
if bond? || option?
|
204
|
-
return false if right != other.right || strike != other.strike
|
205
|
-
return false if multiplier && other.multiplier &&
|
206
|
-
multiplier != other.multiplier
|
207
|
-
return false if expiry && expiry[0..5] != other.expiry[0..5]
|
208
|
-
return false unless expiry && (expiry[6..7] == other.expiry[6..7] ||
|
209
|
-
expiry[6..7].empty? || other.expiry[6..7].empty?)
|
210
|
-
end
|
211
|
-
|
212
|
-
# All else being equal...
|
213
|
-
sec_type == other.sec_type
|
214
|
-
end
|
215
|
-
|
216
|
-
def to_s
|
217
|
-
"<Contract: " + instance_variables.map do |key|
|
218
|
-
value = send(key[1..-1])
|
219
|
-
" #{key}=#{value}" unless value.nil? || value == '' || value == 0
|
220
|
-
end.compact.join(',') + " >"
|
221
|
-
end
|
222
|
-
|
223
|
-
def to_human
|
224
|
-
"<Contract: " +
|
225
|
-
[symbol,
|
226
|
-
sec_type,
|
227
|
-
(expiry == '' ? nil : expiry),
|
228
|
-
(right == :none ? nil : right),
|
229
|
-
(strike == 0 ? nil : strike),
|
230
|
-
exchange,
|
231
|
-
currency
|
232
|
-
].compact.join(" ") + ">"
|
233
|
-
end
|
234
|
-
|
235
|
-
def to_short
|
236
|
-
"#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
|
237
|
-
end
|
238
|
-
|
239
|
-
# Testing for type of contract:
|
240
|
-
|
241
|
-
def bag?
|
242
|
-
self[:sec_type] == 'BAG'
|
243
|
-
end
|
244
|
-
|
245
|
-
def bond?
|
246
|
-
self[:sec_type] == 'BOND'
|
247
|
-
end
|
248
|
-
|
249
|
-
def stock?
|
250
|
-
self[:sec_type] == 'STK'
|
251
|
-
end
|
252
|
-
|
253
|
-
def option?
|
254
|
-
self[:sec_type] == 'OPT'
|
255
|
-
end
|
256
|
-
|
257
|
-
end # class Contract
|
258
|
-
|
259
|
-
|
260
|
-
### Now let's deal with Contract subclasses
|
261
|
-
|
262
|
-
require 'ib-ruby/models/option'
|
263
|
-
require 'ib-ruby/models/bag'
|
264
|
-
|
265
|
-
class Contract
|
266
|
-
# Specialized Contract subclasses representing different security types
|
267
|
-
Subclasses = Hash.new(Contract)
|
268
|
-
Subclasses[:bag] = IB::Models::Bag
|
269
|
-
Subclasses[:option] = IB::Models::Option
|
270
|
-
|
271
|
-
# This returns a Contract initialized from the serialize_ib_ruby format string.
|
272
|
-
def self.build opts = {}
|
273
|
-
subclass = VALUES[:sec_type][opts[:sec_type]] || opts[:sec_type].to_sym
|
274
|
-
Contract::Subclasses[subclass].new opts
|
275
|
-
end
|
276
|
-
|
277
|
-
# This returns a Contract initialized from the serialize_ib_ruby format string.
|
278
|
-
def self.from_ib_ruby string
|
279
|
-
keys = [:symbol, :sec_type, :expiry, :strike, :right, :multiplier,
|
280
|
-
:exchange, :primary_exchange, :currency, :local_symbol]
|
281
|
-
props = Hash[keys.zip(string.split(":"))]
|
282
|
-
props.delete_if { |k, v| v.nil? || v.empty? }
|
283
|
-
Contract.build props
|
284
|
-
end
|
285
|
-
end # class Contract
|
286
|
-
end # module Models
|
287
|
-
end # module IB
|
@@ -1,70 +0,0 @@
|
|
1
|
-
module IB
|
2
|
-
module Models
|
3
|
-
|
4
|
-
# Additional Contract properties (volatile, therefore extracted)
|
5
|
-
class ContractDetail < Model.for(:contract_detail)
|
6
|
-
include ModelProperties
|
7
|
-
|
8
|
-
belongs_to :contract
|
9
|
-
alias summary contract
|
10
|
-
alias summary= contract=
|
11
|
-
|
12
|
-
# All fields Strings, unless specified otherwise:
|
13
|
-
prop :market_name, # The market name for this contract.
|
14
|
-
:trading_class, # The trading class name for this contract.
|
15
|
-
:min_tick, # double: The minimum price tick.
|
16
|
-
:price_magnifier, # int: Allows execution and strike prices to be
|
17
|
-
# reported consistently with market data, historical data and the
|
18
|
-
# order price: Z on LIFFE is reported in index points, not GBP.
|
19
|
-
|
20
|
-
:order_types, # The list of valid order types for this contract.
|
21
|
-
:valid_exchanges, # The list of exchanges this contract is traded on.
|
22
|
-
:under_con_id, # int: The underlying contract ID.
|
23
|
-
:long_name, # Descriptive name of the asset.
|
24
|
-
:contract_month, # The contract month of the underlying futures contract.
|
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
|
-
# BOND values:
|
37
|
-
:cusip, # The nine-character bond CUSIP or the 12-character SEDOL.
|
38
|
-
:ratings, # Credit rating of the issuer. Higher rating is less risky investment.
|
39
|
-
# Bond ratings are from Moody's and S&P respectively.
|
40
|
-
:desc_append, # Additional descriptive information about the bond.
|
41
|
-
:bond_type, # The type of bond, such as "CORP."
|
42
|
-
:coupon_type, # The type of bond coupon.
|
43
|
-
:coupon, # double: The interest rate used to calculate the amount you
|
44
|
-
# will receive in interest payments over the year. default 0
|
45
|
-
:maturity, # The date on which the issuer must repay bond face value
|
46
|
-
:issue_date, # The date the bond was issued.
|
47
|
-
:next_option_date, # only if bond has embedded options.
|
48
|
-
:next_option_type, # only if bond has embedded options.
|
49
|
-
:notes, # Additional notes, if populated for the bond in IB's database
|
50
|
-
:callable => :bool, # Can be called by the issuer under certain conditions.
|
51
|
-
:puttable => :bool, # Can be sold back to the issuer under certain conditions
|
52
|
-
:convertible => :bool, # Can be converted to stock under certain conditions.
|
53
|
-
:next_option_partial => :bool # # only if bond has embedded options.
|
54
|
-
|
55
|
-
# Extra validations
|
56
|
-
validates_format_of :time_zone, :with => /^\w{3}$/, :message => 'should be XXX'
|
57
|
-
|
58
|
-
def default_attributes
|
59
|
-
super.merge :coupon => 0.0,
|
60
|
-
:under_con_id => 0,
|
61
|
-
:min_tick => 0,
|
62
|
-
:callable => false,
|
63
|
-
:puttable => false,
|
64
|
-
:convertible => false,
|
65
|
-
:next_option_partial => false
|
66
|
-
end
|
67
|
-
|
68
|
-
end # class ContractDetail
|
69
|
-
end # module Models
|
70
|
-
end # module IB
|
@@ -1,64 +0,0 @@
|
|
1
|
-
module IB
|
2
|
-
module Models
|
3
|
-
# This is IB Order execution report.
|
4
|
-
# Instantiate with a Hash of attributes, to be auto-set via initialize in Model.
|
5
|
-
class Execution < Model.for(:execution)
|
6
|
-
include ModelProperties
|
7
|
-
|
8
|
-
belongs_to :order
|
9
|
-
|
10
|
-
prop :local_id, # int: order id. TWS orders have a fixed order id of 0.
|
11
|
-
:client_id, # int: client id. TWS orders have a fixed client id of 0.
|
12
|
-
:perm_id, # int: TWS id used to identify orders over TWS sessions
|
13
|
-
:exec_id, # String: Unique order execution id over TWS sessions.
|
14
|
-
:time, # # TODO: convert into Time object?
|
15
|
-
# String: The order execution time.
|
16
|
-
:exchange, # String: Exchange that executed the order.
|
17
|
-
:order_ref, # int: Same order_ref as in corresponding Order
|
18
|
-
:price, # double: The order execution price.
|
19
|
-
:average_price, # double: Average price. Used in regular trades, combo
|
20
|
-
# trades and legs of the combo.
|
21
|
-
[:quantity, :shares], # int: The number of shares filled.
|
22
|
-
:cumulative_quantity, # int: Cumulative quantity. Used in regular
|
23
|
-
# trades, combo trades and legs of the 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
|
-
perm_id == other.perm_id &&
|
44
|
-
local_id == other.local_id && # ((p __LINE__)||true) &&
|
45
|
-
client_id == other.client_id &&
|
46
|
-
exec_id == other.exec_id &&
|
47
|
-
time == other.time &&
|
48
|
-
exchange == other.exchange &&
|
49
|
-
order_ref == other.order_ref &&
|
50
|
-
side == other.side
|
51
|
-
# TODO: || compare all attributes!
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_human
|
55
|
-
"<Execution: #{time} #{side} #{quantity} at #{price} on #{exchange}, " +
|
56
|
-
"cumulative #{cumulative_quantity} at #{average_price}, " +
|
57
|
-
"ids #{local_id}/#{perm_id}/#{exec_id}>"
|
58
|
-
end
|
59
|
-
|
60
|
-
alias to_s to_human
|
61
|
-
|
62
|
-
end # Execution
|
63
|
-
end # module Models
|
64
|
-
end # module IB
|