ib-api 972.0

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +16 -0
  7. data/Gemfile.lock +105 -0
  8. data/Guardfile +24 -0
  9. data/LICENSE +674 -0
  10. data/README.md +65 -0
  11. data/Rakefile +11 -0
  12. data/VERSION +1 -0
  13. data/api.gemspec +43 -0
  14. data/bin/console +95 -0
  15. data/bin/console.yml +3 -0
  16. data/bin/setup +8 -0
  17. data/changelog.md +7 -0
  18. data/example/README.md +76 -0
  19. data/example/account_info +54 -0
  20. data/example/account_positions +30 -0
  21. data/example/account_summary +88 -0
  22. data/example/cancel_orders +74 -0
  23. data/example/fa_accounts +25 -0
  24. data/example/fundamental_data +40 -0
  25. data/example/historic_data_cli +186 -0
  26. data/example/list_orders +45 -0
  27. data/example/portfolio_csv +81 -0
  28. data/example/scanner_data +62 -0
  29. data/example/template +19 -0
  30. data/example/tick_data +28 -0
  31. data/lib/extensions/class-extensions.rb +87 -0
  32. data/lib/ib-api.rb +7 -0
  33. data/lib/ib/base.rb +103 -0
  34. data/lib/ib/base_properties.rb +160 -0
  35. data/lib/ib/connection.rb +450 -0
  36. data/lib/ib/constants.rb +393 -0
  37. data/lib/ib/errors.rb +44 -0
  38. data/lib/ib/logger.rb +26 -0
  39. data/lib/ib/messages.rb +99 -0
  40. data/lib/ib/messages/abstract_message.rb +101 -0
  41. data/lib/ib/messages/incoming.rb +251 -0
  42. data/lib/ib/messages/incoming/abstract_message.rb +116 -0
  43. data/lib/ib/messages/incoming/account_value.rb +78 -0
  44. data/lib/ib/messages/incoming/alert.rb +34 -0
  45. data/lib/ib/messages/incoming/contract_data.rb +102 -0
  46. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  47. data/lib/ib/messages/incoming/execution_data.rb +50 -0
  48. data/lib/ib/messages/incoming/historical_data.rb +84 -0
  49. data/lib/ib/messages/incoming/market_depths.rb +44 -0
  50. data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
  51. data/lib/ib/messages/incoming/open_order.rb +277 -0
  52. data/lib/ib/messages/incoming/order_status.rb +85 -0
  53. data/lib/ib/messages/incoming/portfolio_value.rb +78 -0
  54. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  55. data/lib/ib/messages/incoming/scanner_data.rb +54 -0
  56. data/lib/ib/messages/incoming/ticks.rb +268 -0
  57. data/lib/ib/messages/outgoing.rb +437 -0
  58. data/lib/ib/messages/outgoing/abstract_message.rb +88 -0
  59. data/lib/ib/messages/outgoing/account_requests.rb +112 -0
  60. data/lib/ib/messages/outgoing/bar_requests.rb +250 -0
  61. data/lib/ib/messages/outgoing/place_order.rb +209 -0
  62. data/lib/ib/messages/outgoing/request_marketdata.rb +99 -0
  63. data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
  64. data/lib/ib/model.rb +4 -0
  65. data/lib/ib/models.rb +14 -0
  66. data/lib/ib/server_versions.rb +114 -0
  67. data/lib/ib/socket.rb +185 -0
  68. data/lib/ib/support.rb +160 -0
  69. data/lib/ib/version.rb +6 -0
  70. data/lib/models/ib/account.rb +85 -0
  71. data/lib/models/ib/account_value.rb +33 -0
  72. data/lib/models/ib/bag.rb +55 -0
  73. data/lib/models/ib/bar.rb +31 -0
  74. data/lib/models/ib/combo_leg.rb +105 -0
  75. data/lib/models/ib/condition.rb +245 -0
  76. data/lib/models/ib/contract.rb +415 -0
  77. data/lib/models/ib/contract_detail.rb +108 -0
  78. data/lib/models/ib/execution.rb +67 -0
  79. data/lib/models/ib/forex.rb +13 -0
  80. data/lib/models/ib/future.rb +15 -0
  81. data/lib/models/ib/index.rb +15 -0
  82. data/lib/models/ib/option.rb +78 -0
  83. data/lib/models/ib/option_detail.rb +55 -0
  84. data/lib/models/ib/order.rb +519 -0
  85. data/lib/models/ib/order_state.rb +152 -0
  86. data/lib/models/ib/portfolio_value.rb +64 -0
  87. data/lib/models/ib/stock.rb +16 -0
  88. data/lib/models/ib/underlying.rb +34 -0
  89. data/lib/models/ib/vertical.rb +96 -0
  90. data/lib/requires.rb +12 -0
  91. metadata +203 -0
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # This Script needs testing. remove this line after sucessfully using the scanner facility
3
+ #
4
+ # This script setups a scan request and retreives the results.
5
+
6
+ require 'rubygems'
7
+ require 'bundler/setup'
8
+ require 'ib-api'
9
+
10
+
11
+
12
+ # Connect to IB TWS.
13
+ ib = IB::Connection.new :client_id => 1112 , port: 7496 do | gw | #, :port => 7497 # TWS
14
+
15
+
16
+ # Subscribe to TWS alerts/errors
17
+ gw.subscribe(:Alert) { |msg| puts msg.to_human }
18
+
19
+
20
+ # Subscribe to ScannerData incoming events. The code passed in the block
21
+ # will be executed when a message of that type is received, with the received
22
+ # message as its argument. In this case, we just print out the data.
23
+ #
24
+ gw.subscribe(IB::Messages::Incoming::ScannerData) do |msg|
25
+ puts "ID: #{msg.request_id} : #{msg.count} items:"
26
+ msg.results.each { |entry| puts " #{entry}" }
27
+ end
28
+ end
29
+ id = 42
30
+ # Now we actually request scanner data for the type of scan we are interested.
31
+ # Some scan types can be found here: http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/tables/available_market_scanners.htm
32
+ mess = IB::Messages::Outgoing::RequestScannerSubscription.new(
33
+ :request_id => id,
34
+ :number_of_rows => 20,
35
+ :instrument => "STK",
36
+ :location_code => 'STK.US.MAJOR',
37
+ :scan_code => 'TOP_PERC_GAIN',
38
+ :above_price => 4.0,
39
+ :below_price => Float::MAX,
40
+ :above_volume => 5000,
41
+ :market_cap_above => 100000000,
42
+ :market_cap_below => Float::MAX,
43
+ :moody_rating_above => "",
44
+ :moody_rating_below => "",
45
+ :sp_rating_above => "",
46
+ :sp_rating_below => "",
47
+ :maturity_date_above => "",
48
+ :maturity_date_below => "",
49
+ :coupon_rate_above => Float::MAX,
50
+ :coupon_rate_below => Float::MAX,
51
+ :exclude_convertible => "",
52
+ :average_option_volume_above => "", # ?
53
+ :scanner_setting_pairs => "Annual,true",
54
+ :stock_type_filter => "Stock"
55
+ )
56
+
57
+ ib.send_message( mess )
58
+
59
+ # IB does not send any indication when all data is done being delivered.
60
+ # So we need to interrupt manually when our request is answered.
61
+ puts "\n******** Press <Enter> to exit... *********\n\n"
62
+ STDIN.gets
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Your script description here...
4
+
5
+ require 'bundler/setup'
6
+ require 'ib-api'
7
+
8
+ # First, connect to IB TWS and subscribe for events.
9
+ ib = IB::Connection.new :client_id => 1112 do | gw | #, :port => 7497 # TWS
10
+
11
+ # Subscribe to TWS alerts/errors
12
+ gw.subscribe(:Alert, :ManagedAccounts) { |msg| puts msg.to_human }
13
+ # Set log level
14
+ gw.logger.level = Logger::FATAL # DEBUG -- INFO -- WARN -- ERROR -- FATAL
15
+
16
+ end
17
+ # Put your code here
18
+ # ...
19
+
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script reproduces https://github.com/ib-ruby/ib-ruby/issues/12
4
+
5
+ require 'bundler/setup'
6
+ require 'ib-api'
7
+
8
+ contract = IB::Stock.new :symbol=> 'AAPL'
9
+
10
+ # First, connect to IB Gateway.
11
+ ib = IB::Connection.new :client_id => 1112 # id to identify your script
12
+ # :port => 7497 # TWS connection (instead of default Gateway)
13
+ # :received => false # Do not keep all received messages in memory
14
+
15
+ ib.subscribe(:Alert) { |msg| puts msg.to_human }
16
+ ib.subscribe(:MarketDataType) { |msg| puts msg.to_human }
17
+ ib.subscribe(:TickGeneric, :TickString, :TickPrice, :TickSize) { |msg| puts msg.inspect }
18
+ ib.send_message :RequestMarketDataType, :market_data_type => :delayed
19
+ ib.send_message :RequestMarketData, id: 123, contract: contract
20
+
21
+ puts "\nSubscribed to market data"
22
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
23
+ gets
24
+ puts "Cancelling market data subscription.."
25
+
26
+ ib.send_message :CancelMarketData, id: 123
27
+ sleep 1
28
+ puts "Done."
@@ -0,0 +1,87 @@
1
+ module CoreExtensions
2
+ module Array
3
+ module DuplicatesCounter
4
+ def count_duplicates
5
+ self.each_with_object(Hash.new(0)) { |element, counter| counter[element] += 1 }.sort_by{|k,v| -v}.to_h
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ Array.include CoreExtensions::Array::DuplicatesCounter
12
+
13
+
14
+
15
+
16
+ class Time
17
+ # Render datetime in IB format (zero padded "yyyymmdd HH:mm:ss")
18
+ def to_ib
19
+ "#{year}#{sprintf("%02d", month)}#{sprintf("%02d", day)} " +
20
+ "#{sprintf("%02d", hour)}:#{sprintf("%02d", min)}:#{sprintf("%02d", sec)}"
21
+ end
22
+ end # Time
23
+
24
+ class Numeric
25
+ # Conversion 0/1 into true/false
26
+ def to_bool
27
+ self == 0 ? false : true
28
+ end
29
+ end
30
+
31
+ class TrueClass
32
+ def to_bool
33
+ self
34
+ end
35
+ end
36
+
37
+ class FalseClass
38
+ def to_bool
39
+ self
40
+ end
41
+ end
42
+
43
+ class String
44
+ def to_bool
45
+ case self.chomp.upcase
46
+ when 'TRUE', 'T', '1'
47
+ true
48
+ when 'FALSE', 'F', '0', ''
49
+ false
50
+ else
51
+ error "Unable to convert #{self} to bool"
52
+ end
53
+ end
54
+ end
55
+
56
+ class NilClass
57
+ # We still need to pass on nil, meaning: no value
58
+ def to_bool
59
+ self
60
+ end
61
+ end
62
+
63
+ class Symbol
64
+ def to_f
65
+ 0
66
+ end
67
+
68
+ # ActiveModel serialization depends on this method
69
+ def <=> other
70
+ to_s <=> other.to_s
71
+ end
72
+ end
73
+
74
+ class Object
75
+ # We still need to pass on nil, meaning: no value
76
+ def to_sup
77
+ self.to_s.upcase unless self.nil?
78
+ end
79
+ end
80
+
81
+ ### Patching Object#error in ib/errors
82
+ # def error message, type=:standard
83
+
84
+ ### Patching Object#log, #default_logger= in ib/logger
85
+ # def default_logger
86
+ # def default_logger= logger
87
+ # def log *args
@@ -0,0 +1,7 @@
1
+ module IB
2
+
3
+ end
4
+ IbRuby = IB
5
+ Ib = IB
6
+
7
+ require 'requires'
@@ -0,0 +1,103 @@
1
+ module IB
2
+
3
+ # Base class for tableless IB data Models, extends ActiveModel API
4
+ class Base
5
+ extend ActiveModel::Naming
6
+ extend ActiveModel::Callbacks
7
+ include ActiveModel::Validations
8
+ include ActiveModel::Serialization
9
+ #include ActiveModel::Serializers::Xml
10
+ include ActiveModel::Serializers::JSON
11
+
12
+ define_model_callbacks :initialize
13
+
14
+ # If a opts hash is given, keys are taken as attribute names, values as data.
15
+ # The model instance fields are then set automatically from the opts Hash.
16
+ def initialize attributes={}, opts={}
17
+ run_callbacks :initialize do
18
+ error "Argument must be a Hash", :args unless attributes.is_a?(Hash)
19
+
20
+ self.attributes = attributes # set_attribute_defaults is now after_init callback
21
+ end
22
+ end
23
+
24
+ # ActiveModel API (for serialization)
25
+
26
+ def attributes
27
+ @attributes ||= Hash.new #HashWithIndifferentAccess.new
28
+ end
29
+
30
+ def attributes= attrs
31
+ attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
32
+ end
33
+
34
+ # ActiveModel-style read/write_attribute accessors
35
+ def [] key
36
+ attributes[key.to_sym]
37
+ end
38
+
39
+ def update_attribute key, value
40
+ @attributes[key.to_sym] = value
41
+ end
42
+
43
+ def []= key, val
44
+ # p key, val
45
+ attributes[key.to_sym] = val
46
+ end
47
+
48
+ def to_model
49
+ self
50
+ end
51
+
52
+ def new_record?
53
+ true
54
+ end
55
+
56
+ def save
57
+ valid?
58
+ end
59
+
60
+ alias save! save
61
+
62
+ ### Noop methods mocking ActiveRecord::Base macros
63
+
64
+ def self.attr_protected *args
65
+ end
66
+
67
+ def self.attr_accessible *args
68
+ end
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
+ end # Model
103
+ end # module IB
@@ -0,0 +1,160 @@
1
+ require 'active_model'
2
+ require 'active_support/concern'
3
+ #require 'active_support/hash_with_indifferent_access'
4
+
5
+ module IB
6
+
7
+ # Module adds prop Macro and
8
+ module BaseProperties
9
+ extend ActiveSupport::Concern
10
+
11
+ ### Instance methods
12
+
13
+ # Default presentation
14
+ def to_human
15
+ "<#{self.class.to_s.demodulize}: " + attributes.map do |attr, value|
16
+ "#{attr}: #{value}" unless value.nil?
17
+ end.compact.sort.join(' ') + ">"
18
+ end
19
+
20
+ # Comparison support
21
+ def content_attributes
22
+ #HashWithIndifferentAccess[attributes.reject do |(attr, _)|
23
+ #NoMethodError if a Hash is assigned to an attribute
24
+ Hash[attributes.reject do |(attr, _)|
25
+ attr.to_s =~ /(_count)\z/ ||
26
+ [:created_at, :updated_at, :type,
27
+ :id, :order_id, :contract_id].include?(attr.to_sym)
28
+ end]
29
+ end
30
+
31
+ =begin
32
+ Remove all Time-Stamps from the list of Attributes
33
+ =end
34
+ def invariant_attributes
35
+ attributes.reject{|x| x =~ /_at/}
36
+ end
37
+
38
+ # Update nil attributes from given Hash or model
39
+ def update_missing attrs
40
+ attrs = attrs.content_attributes unless attrs.kind_of?(Hash)
41
+
42
+ attrs.each { |attr, val| send "#{attr}=", val if send(attr).blank? }
43
+ self # for chaining
44
+ end
45
+
46
+ # Default Model comparison
47
+ def == other
48
+ case other
49
+ when String # Probably a Rails URI, delegate to AR::Base
50
+ super(other)
51
+ else
52
+ content_attributes.keys.inject(true) { |res, key|
53
+ res && other.respond_to?(key) && (send(key) == other.send(key)) }
54
+ end
55
+ end
56
+
57
+ ### Default attributes support
58
+
59
+ def default_attributes
60
+ {:created_at => Time.now
61
+ # :updated_at => Time.now,
62
+ }
63
+ end
64
+
65
+ def set_attribute_defaults
66
+ default_attributes.each do |key, val|
67
+ self.send("#{key}=", val) if self.send(key).nil?
68
+ # self.send("#{key}=", val) if self[key].nil? # Problems with association defaults
69
+ end
70
+ end
71
+
72
+ included do
73
+
74
+ after_initialize :set_attribute_defaults
75
+
76
+ ### Class macros
77
+
78
+ def self.prop *properties
79
+ prop_hash = properties.last.is_a?(Hash) ? properties.pop : {}
80
+
81
+ properties.each { |names| define_property names, nil }
82
+ prop_hash.each { |names, type| define_property names, type }
83
+ end
84
+
85
+ def self.define_property names, body
86
+ aliases = [names].flatten
87
+ name = aliases.shift
88
+ instance_eval do
89
+
90
+ define_property_methods name, body
91
+
92
+ aliases.each do |ali|
93
+ alias_method "#{ali}", name
94
+ alias_method "#{ali}=", "#{name}="
95
+ end
96
+ end
97
+ end
98
+
99
+ def self.define_property_methods name, body={}
100
+ #p name, body
101
+ case body
102
+ when '' # default getter and setter
103
+ define_property_methods name
104
+
105
+ when Array # [setter, getter, validators]
106
+ define_property_methods name,
107
+ :get => body[0],
108
+ :set => body[1],
109
+ :validate => body[2]
110
+
111
+ when Hash # recursion base case
112
+ getter = case # Define getter
113
+ when body[:get].respond_to?(:call)
114
+ body[:get]
115
+ when body[:get]
116
+ proc { self[name].send "to_#{body[:get]}" }
117
+ when VALUES[name] # property is encoded
118
+ proc { VALUES[name][self[name]] }
119
+ else
120
+ proc { self[name] }
121
+ end
122
+ define_method name, &getter if getter
123
+
124
+ setter = case # Define setter
125
+ when body[:set].respond_to?(:call)
126
+ body[:set]
127
+ when body[:set]
128
+ proc { |value| self[name] = value.send "to_#{body[:set]}" }
129
+ when CODES[name] # property is encoded
130
+ proc { |value| self[name] = CODES[name][value] || value }
131
+ else
132
+ proc { |value| self[name] = value } # p name, value;
133
+ end
134
+ define_method "#{name}=", &setter if setter
135
+
136
+ # Define validator(s)
137
+ [body[:validate]].flatten.compact.each do |validator|
138
+ case validator
139
+ when Proc
140
+ validates_each name, &validator
141
+ when Hash
142
+ validates name, validator.dup
143
+ end
144
+ end
145
+
146
+ # TODO define self[:name] accessors for :virtual and :flag properties
147
+
148
+ else # setter given
149
+ define_property_methods name, :set => body, :get => body
150
+ end
151
+ end
152
+
153
+ # Timestamps in lightweight models
154
+ unless defined?(ActiveRecord::Base) && ancestors.include?(ActiveRecord::Base)
155
+ prop :created_at #, :updated_at
156
+ end
157
+
158
+ end # included
159
+ end # module BaseProperties
160
+ end