ib-api 972.0

Sign up to get free protection for your applications and to get access to all the features.
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