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/models/model.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
module IB
|
2
|
-
module Models
|
3
|
-
|
4
|
-
# Base class for tableless IB data Models extends ActiveModel API
|
5
|
-
class Model
|
6
|
-
extend ActiveModel::Naming
|
7
|
-
extend ActiveModel::Callbacks
|
8
|
-
include ActiveModel::Validations
|
9
|
-
include ActiveModel::Serialization
|
10
|
-
include ActiveModel::Serializers::Xml
|
11
|
-
include ActiveModel::Serializers::JSON
|
12
|
-
|
13
|
-
# IB Models can be either database-backed, or not
|
14
|
-
# require 'ib-ruby/db' # to make all IB models database-backed
|
15
|
-
# If you plan to persist only specific Models, select those subclasses here:
|
16
|
-
def self.for subclass
|
17
|
-
if DB # && [:contract, :order, :order_state].include? subclass
|
18
|
-
ActiveRecord::Base
|
19
|
-
else
|
20
|
-
Model
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
#attr_accessor :attributes
|
25
|
-
|
26
|
-
# If a opts hash is given, keys are taken as attribute names, values as data.
|
27
|
-
# The model instance fields are then set automatically from the opts Hash.
|
28
|
-
def initialize attributes={}, opts={}
|
29
|
-
run_callbacks :initialize do
|
30
|
-
error "Argument must be a Hash", :args unless attributes.is_a?(Hash)
|
31
|
-
|
32
|
-
self.attributes = default_attributes.merge(attributes)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# ActiveModel API (for serialization)
|
37
|
-
|
38
|
-
def attributes
|
39
|
-
@attributes ||= HashWithIndifferentAccess.new
|
40
|
-
end
|
41
|
-
|
42
|
-
def attributes= attrs
|
43
|
-
attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
|
44
|
-
end
|
45
|
-
|
46
|
-
# ActiveModel-style read/write_attribute accessors
|
47
|
-
def [] key
|
48
|
-
attributes[key.to_sym]
|
49
|
-
end
|
50
|
-
|
51
|
-
def []= key, val
|
52
|
-
# p key, val
|
53
|
-
attributes[key.to_sym] = val
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_model
|
57
|
-
self
|
58
|
-
end
|
59
|
-
|
60
|
-
def new_record?
|
61
|
-
true
|
62
|
-
end
|
63
|
-
|
64
|
-
def save
|
65
|
-
valid?
|
66
|
-
end
|
67
|
-
|
68
|
-
alias save! save
|
69
|
-
|
70
|
-
### ActiveRecord::Base association API mocks
|
71
|
-
|
72
|
-
def self.belongs_to model, *args
|
73
|
-
attr_accessor model
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.has_one model, *args
|
77
|
-
attr_accessor model
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.has_many models, *args
|
81
|
-
attr_accessor models
|
82
|
-
|
83
|
-
define_method(models) do
|
84
|
-
self.instance_variable_get("@#{models}") ||
|
85
|
-
self.instance_variable_set("@#{models}", [])
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def self.find *args
|
90
|
-
[]
|
91
|
-
end
|
92
|
-
|
93
|
-
### ActiveRecord::Base callback API mocks
|
94
|
-
|
95
|
-
define_model_callbacks :initialize, :only => :after
|
96
|
-
|
97
|
-
### ActiveRecord::Base misc
|
98
|
-
|
99
|
-
def self.serialize *properties
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
end # Model
|
104
|
-
end # module Models
|
105
|
-
end # module IB
|
@@ -1,146 +0,0 @@
|
|
1
|
-
require 'active_model'
|
2
|
-
require 'active_support/concern'
|
3
|
-
require 'active_support/hash_with_indifferent_access'
|
4
|
-
|
5
|
-
module IB
|
6
|
-
module Models
|
7
|
-
|
8
|
-
# Module adds prop Macro and
|
9
|
-
module ModelProperties
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
|
-
def default_attributes
|
13
|
-
{:created_at => Time.now,
|
14
|
-
:updated_at => Time.now,
|
15
|
-
}
|
16
|
-
end
|
17
|
-
|
18
|
-
### Instance methods
|
19
|
-
|
20
|
-
# Default presentation
|
21
|
-
def to_human
|
22
|
-
"<#{self.class.to_s.demodulize}: " + attributes.map do |attr, value|
|
23
|
-
"#{attr}: #{value}" unless value.nil?
|
24
|
-
end.compact.sort.join(' ') + ">"
|
25
|
-
end
|
26
|
-
|
27
|
-
# Comparison support
|
28
|
-
def content_attributes
|
29
|
-
HashWithIndifferentAccess[attributes.reject do |(attr, _)|
|
30
|
-
attr.to_s =~ /(_count)$/ ||
|
31
|
-
[:created_at, :updated_at, :type,
|
32
|
-
:id, :order_id, :contract_id].include?(attr.to_sym)
|
33
|
-
end]
|
34
|
-
end
|
35
|
-
|
36
|
-
# Update nil attributes from given Hash or model
|
37
|
-
def update_missing attrs
|
38
|
-
attrs = attrs.content_attributes unless attrs.kind_of?(Hash)
|
39
|
-
|
40
|
-
attrs.each { |attr, val| send "#{attr}=", val if send(attr).blank? }
|
41
|
-
self # for chaining
|
42
|
-
end
|
43
|
-
|
44
|
-
# Default Model comparison
|
45
|
-
def == other
|
46
|
-
content_attributes.inject(true) { |res, (attr, value)| res && other.send(attr) == value } &&
|
47
|
-
other.content_attributes.inject(true) { |res, (attr, value)| res && send(attr) == value }
|
48
|
-
end
|
49
|
-
|
50
|
-
included do
|
51
|
-
|
52
|
-
### Class macros
|
53
|
-
|
54
|
-
def self.prop *properties
|
55
|
-
prop_hash = properties.last.is_a?(Hash) ? properties.pop : {}
|
56
|
-
|
57
|
-
properties.each { |names| define_property names, nil }
|
58
|
-
prop_hash.each { |names, type| define_property names, type }
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.define_property names, body
|
62
|
-
aliases = [names].flatten
|
63
|
-
name = aliases.shift
|
64
|
-
instance_eval do
|
65
|
-
|
66
|
-
define_property_methods name, body
|
67
|
-
|
68
|
-
aliases.each do |ali|
|
69
|
-
alias_method "#{ali}", name
|
70
|
-
alias_method "#{ali}=", "#{name}="
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.define_property_methods name, body={}
|
76
|
-
#p name, body
|
77
|
-
case body
|
78
|
-
when '' # default getter and setter
|
79
|
-
define_property_methods name
|
80
|
-
|
81
|
-
when Array # [setter, getter, validators]
|
82
|
-
define_property_methods name,
|
83
|
-
:get => body[0],
|
84
|
-
:set => body[1],
|
85
|
-
:validate => body[2]
|
86
|
-
|
87
|
-
when Hash # recursion base case
|
88
|
-
getter = case # Define getter
|
89
|
-
when body[:get].respond_to?(:call)
|
90
|
-
body[:get]
|
91
|
-
when body[:get]
|
92
|
-
proc { self[name].send "to_#{body[:get]}" }
|
93
|
-
when VALUES[name] # property is encoded
|
94
|
-
proc { VALUES[name][self[name]] }
|
95
|
-
#when respond_to?(:column_names) && column_names.include?(name.to_s)
|
96
|
-
# # noop, ActiveRecord will take care of it...
|
97
|
-
# p "#{name} => get noop"
|
98
|
-
# p respond_to?(:column_names) && column_names
|
99
|
-
else
|
100
|
-
proc { self[name] }
|
101
|
-
end
|
102
|
-
define_method name, &getter if getter
|
103
|
-
|
104
|
-
setter = case # Define setter
|
105
|
-
when body[:set].respond_to?(:call)
|
106
|
-
body[:set]
|
107
|
-
when body[:set]
|
108
|
-
proc { |value| self[name] = value.send "to_#{body[:set]}" }
|
109
|
-
when CODES[name] # property is encoded
|
110
|
-
proc { |value| self[name] = CODES[name][value] || value }
|
111
|
-
else
|
112
|
-
proc { |value| self[name] = value } # p name, value;
|
113
|
-
end
|
114
|
-
define_method "#{name}=", &setter if setter
|
115
|
-
|
116
|
-
# Define validator(s)
|
117
|
-
[body[:validate]].flatten.compact.each do |validator|
|
118
|
-
case validator
|
119
|
-
when Proc
|
120
|
-
validates_each name, &validator
|
121
|
-
when Hash
|
122
|
-
validates name, validator.dup
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# TODO define self[:name] accessors for :virtual and :flag properties
|
127
|
-
|
128
|
-
else # setter given
|
129
|
-
define_property_methods name, :set => body, :get => body
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# Extending AR-backed Model class with attribute defaults
|
134
|
-
if defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
|
135
|
-
def initialize attributes={}, opts={}
|
136
|
-
super default_attributes.merge(attributes), opts
|
137
|
-
end
|
138
|
-
else
|
139
|
-
# Timestamps
|
140
|
-
prop :created_at, :updated_at
|
141
|
-
end
|
142
|
-
|
143
|
-
end # included
|
144
|
-
end # module ModelProperties
|
145
|
-
end # module Models
|
146
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'ib-ruby/models/contract'
|
2
|
-
|
3
|
-
module IB
|
4
|
-
module Models
|
5
|
-
class Option < Contract
|
6
|
-
|
7
|
-
validates_numericality_of :strike, :greater_than => 0
|
8
|
-
validates_format_of :sec_type, :with => /^option$/,
|
9
|
-
:message => "should be an option"
|
10
|
-
validates_format_of :local_symbol, :with => /^\w+\s*\d{6}[pcPC]\d{8}$|^$/,
|
11
|
-
:message => "invalid OSI code"
|
12
|
-
validates_format_of :right, :with => /^put$|^call$/,
|
13
|
-
:message => "should be put or call"
|
14
|
-
|
15
|
-
# For Options, this is contract's OSI (Option Symbology Initiative) name/code
|
16
|
-
alias osi local_symbol
|
17
|
-
|
18
|
-
def osi= value
|
19
|
-
# Normalize to 21 char
|
20
|
-
self.local_symbol = value.sub(/ /, ' '*(22-value.size))
|
21
|
-
end
|
22
|
-
|
23
|
-
# Make valid IB Contract definition from OSI (Option Symbology Initiative) code.
|
24
|
-
# NB: Simply making a new Contract with *local_symbol* (osi) property set to a
|
25
|
-
# valid OSI code works just as well, just do NOT set *expiry*, *right* or
|
26
|
-
# *strike* properties in this case.
|
27
|
-
# This class method provided as a backup and shows how to analyse OSI codes.
|
28
|
-
def self.from_osi osi
|
29
|
-
|
30
|
-
# Parse contract's OSI (OCC Option Symbology Initiative) code
|
31
|
-
args = osi.match(/(\w+)\s?(\d\d)(\d\d)(\d\d)([pcPC])(\d+)/).to_a.drop(1)
|
32
|
-
symbol = args.shift
|
33
|
-
year = 2000 + args.shift.to_i
|
34
|
-
month = args.shift.to_i
|
35
|
-
day = args.shift.to_i
|
36
|
-
right = args.shift.upcase
|
37
|
-
strike = args.shift.to_i/1000.0
|
38
|
-
|
39
|
-
# Set correct expiry date - IB expiry date differs from OSI if expiry date
|
40
|
-
# falls on Saturday (see https://github.com/arvicco/option_mower/issues/4)
|
41
|
-
expiry_date = Time.utc(year, month, day)
|
42
|
-
expiry_date = Time.utc(year, month, day-1) if expiry_date.wday == 6
|
43
|
-
|
44
|
-
new :symbol => symbol,
|
45
|
-
:exchange => "SMART",
|
46
|
-
:expiry => expiry_date.to_ib[2..7], # YYMMDD
|
47
|
-
:right => right,
|
48
|
-
:strike => strike
|
49
|
-
end
|
50
|
-
|
51
|
-
def default_attributes
|
52
|
-
super.merge :sec_type => :option
|
53
|
-
#self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_human
|
57
|
-
"<Option: " + [symbol, expiry, right, strike, exchange, currency].join(" ") + ">"
|
58
|
-
end
|
59
|
-
|
60
|
-
end # class Option
|
61
|
-
end # module Models
|
62
|
-
end # module IB
|