ib-ruby 0.8.1 → 0.8.3
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.
- 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
|