ib-api 972.1 → 972.5
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +29 -29
- data/VERSION +1 -1
- data/api.gemspec +1 -1
- data/bin/console +4 -8
- data/changelog.md +2 -1
- data/lib/ib/connection.rb +19 -17
- data/lib/ib/logger.rb +1 -1
- data/lib/ib/messages/incoming/abstract_message.rb +7 -7
- data/lib/ib/messages/incoming/account_value.rb +5 -1
- data/lib/ib/messages/incoming/historical_data.rb +25 -5
- data/lib/ib/messages/outgoing/abstract_message.rb +3 -3
- data/lib/ib/messages/outgoing/bar_requests.rb +4 -5
- data/lib/ib/support.rb +34 -17
- data/lib/logging.rb +45 -0
- data/lib/models/ib/bag.rb +6 -0
- data/lib/models/ib/bar.rb +1 -1
- data/lib/models/ib/combo_leg.rb +22 -0
- data/lib/models/ib/contract.rb +32 -38
- data/lib/models/ib/option.rb +3 -1
- data/lib/models/ib/order.rb +5 -0
- data/lib/models/ib/spread.rb +29 -20
- metadata +8 -20
- data/example/README.md +0 -76
- data/example/account_info +0 -54
- data/example/account_positions +0 -30
- data/example/account_summary +0 -88
- data/example/cancel_orders +0 -74
- data/example/fa_accounts +0 -25
- data/example/fundamental_data +0 -40
- data/example/historic_data_cli +0 -186
- data/example/list_orders +0 -45
- data/example/portfolio_csv +0 -81
- data/example/scanner_data +0 -62
- data/example/template +0 -19
- data/example/tick_data +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0beb8b8f1edf85049336ec063de7fcaa5c0c0e1dae3e6f813131f997718892ad
|
4
|
+
data.tar.gz: c2178ec4cdff3a6d90c7ef0c1cd68dab1620ce57ab2feba811873a113d1a6536
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1b6919bbc9adf1044b602bb64da8b67f0bfe2ec54c354a6a6465e2bf7dfa49355315029c0bba3ae682b2226dea3002d74a0e3ba7b02834de7217d22ec2f2461
|
7
|
+
data.tar.gz: 8e3bc0babb443933c0b843884a2ec76ceb2fb0df7ea89aad1912c68b672c217dd56b4a8ea90ed350b83660f838895853f3aadc9e1fb2c5baf2ddc029c5e7fc22
|
data/Gemfile.lock
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
GIT
|
2
2
|
remote: https://github.com/ohler55/ox.git
|
3
|
-
revision:
|
3
|
+
revision: 59c4234fe01fb5de08d49b39ecf5fc7338c1ffdc
|
4
4
|
specs:
|
5
|
-
ox (2.
|
5
|
+
ox (2.14.4)
|
6
6
|
|
7
7
|
PATH
|
8
8
|
remote: .
|
9
9
|
specs:
|
10
|
-
ib-api (972.1)
|
10
|
+
ib-api (972.3.1)
|
11
11
|
activemodel
|
12
12
|
activesupport (>= 6.0)
|
13
13
|
|
14
14
|
GEM
|
15
15
|
remote: https://rubygems.org/
|
16
16
|
specs:
|
17
|
-
activemodel (6.1.
|
18
|
-
activesupport (= 6.1.
|
19
|
-
activesupport (6.1.
|
17
|
+
activemodel (6.1.3.2)
|
18
|
+
activesupport (= 6.1.3.2)
|
19
|
+
activesupport (6.1.3.2)
|
20
20
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
21
21
|
i18n (>= 1.6, < 2)
|
22
22
|
minitest (>= 5.1)
|
23
23
|
tzinfo (~> 2.0)
|
24
24
|
zeitwerk (~> 2.3)
|
25
25
|
coderay (1.1.3)
|
26
|
-
concurrent-ruby (1.1.
|
26
|
+
concurrent-ruby (1.1.8)
|
27
27
|
diff-lcs (1.4.4)
|
28
|
-
ffi (1.
|
28
|
+
ffi (1.15.0)
|
29
29
|
formatador (0.2.5)
|
30
30
|
guard (2.16.2)
|
31
31
|
formatador (>= 0.2.4)
|
@@ -41,55 +41,55 @@ GEM
|
|
41
41
|
guard (~> 2.1)
|
42
42
|
guard-compat (~> 1.1)
|
43
43
|
rspec (>= 2.99.0, < 4.0)
|
44
|
-
i18n (1.8.
|
44
|
+
i18n (1.8.10)
|
45
45
|
concurrent-ruby (~> 1.0)
|
46
|
-
listen (3.
|
46
|
+
listen (3.5.1)
|
47
47
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
48
48
|
rb-inotify (~> 0.9, >= 0.9.10)
|
49
49
|
lumberjack (1.2.8)
|
50
50
|
method_source (1.0.0)
|
51
|
-
minitest (5.14.
|
51
|
+
minitest (5.14.4)
|
52
52
|
nenv (0.3.0)
|
53
53
|
notiffany (0.1.3)
|
54
54
|
nenv (~> 0.1)
|
55
55
|
shellany (~> 0.0)
|
56
|
-
pry (0.
|
56
|
+
pry (0.14.1)
|
57
57
|
coderay (~> 1.1)
|
58
58
|
method_source (~> 1.0)
|
59
|
-
rake (13.0.
|
60
|
-
rb-fsevent (0.
|
59
|
+
rake (13.0.3)
|
60
|
+
rb-fsevent (0.11.0)
|
61
61
|
rb-inotify (0.10.1)
|
62
62
|
ffi (~> 1.0)
|
63
|
-
rspec (3.
|
64
|
-
rspec-core (~> 3.
|
65
|
-
rspec-expectations (~> 3.
|
66
|
-
rspec-mocks (~> 3.
|
63
|
+
rspec (3.10.0)
|
64
|
+
rspec-core (~> 3.10.0)
|
65
|
+
rspec-expectations (~> 3.10.0)
|
66
|
+
rspec-mocks (~> 3.10.0)
|
67
67
|
rspec-collection_matchers (1.2.0)
|
68
68
|
rspec-expectations (>= 2.99.0.beta1)
|
69
|
-
rspec-core (3.
|
70
|
-
rspec-support (~> 3.
|
71
|
-
rspec-expectations (3.
|
69
|
+
rspec-core (3.10.1)
|
70
|
+
rspec-support (~> 3.10.0)
|
71
|
+
rspec-expectations (3.10.1)
|
72
72
|
diff-lcs (>= 1.2.0, < 2.0)
|
73
|
-
rspec-support (~> 3.
|
73
|
+
rspec-support (~> 3.10.0)
|
74
74
|
rspec-its (1.3.0)
|
75
75
|
rspec-core (>= 3.0.0)
|
76
76
|
rspec-expectations (>= 3.0.0)
|
77
|
-
rspec-mocks (3.
|
77
|
+
rspec-mocks (3.10.2)
|
78
78
|
diff-lcs (>= 1.2.0, < 2.0)
|
79
|
-
rspec-support (~> 3.
|
80
|
-
rspec-support (3.
|
79
|
+
rspec-support (~> 3.10.0)
|
80
|
+
rspec-support (3.10.2)
|
81
81
|
shellany (0.0.1)
|
82
|
-
thor (1.0
|
82
|
+
thor (1.1.0)
|
83
83
|
tzinfo (2.0.4)
|
84
84
|
concurrent-ruby (~> 1.0)
|
85
85
|
value_semantics (3.6.0)
|
86
86
|
zeitwerk (2.4.2)
|
87
87
|
|
88
88
|
PLATFORMS
|
89
|
-
|
89
|
+
x86_64-linux
|
90
90
|
|
91
91
|
DEPENDENCIES
|
92
|
-
bundler
|
92
|
+
bundler
|
93
93
|
guard
|
94
94
|
guard-rspec
|
95
95
|
ib-api!
|
@@ -101,4 +101,4 @@ DEPENDENCIES
|
|
101
101
|
value_semantics
|
102
102
|
|
103
103
|
BUNDLED WITH
|
104
|
-
|
104
|
+
2.2.3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
972.
|
1
|
+
972.5
|
data/api.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
36
|
spec.require_paths = ["lib"]
|
37
37
|
|
38
|
-
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "bundler"
|
39
39
|
spec.add_development_dependency "rake", "~> 13.0"
|
40
40
|
spec.add_development_dependency "rspec", "~> 3.0"
|
41
41
|
spec.add_dependency 'activesupport', '>= 6.0'
|
data/bin/console
CHANGED
@@ -10,8 +10,6 @@
|
|
10
10
|
require 'bundler/setup'
|
11
11
|
require 'yaml'
|
12
12
|
|
13
|
-
require 'logger'
|
14
|
-
|
15
13
|
require 'ib-api'
|
16
14
|
|
17
15
|
class Array
|
@@ -47,7 +45,6 @@ read_yml = -> (key) do
|
|
47
45
|
puts "Namespace is IB ! "
|
48
46
|
puts
|
49
47
|
puts '-'* 45
|
50
|
-
include LogDev
|
51
48
|
include IB
|
52
49
|
require 'irb'
|
53
50
|
client_id = ARGV[1] || read_yml[:client_id]
|
@@ -62,16 +59,15 @@ read_yml = -> (key) do
|
|
62
59
|
end
|
63
60
|
|
64
61
|
ARGV.clear
|
65
|
-
logger = default_logger # Logger.new STDOUT
|
66
62
|
|
67
63
|
## The Block takes instructions which are executed after initializing all instance-variables
|
68
64
|
## and prior to the connection-process
|
69
65
|
## Here we just subscribe to some events
|
70
66
|
C = Connection.new client_id: client_id, port: port do |c| # future use__ , optional_capacities: "+PACEAPI" do |c|
|
71
67
|
|
72
|
-
c.subscribe( :ContractData, :BondContractData) { |msg| logger.info { msg.contract.to_human } }
|
73
|
-
c.subscribe( :Alert, :ContractDataEnd, :ManagedAccounts, :OrderStatus ) {| m| logger.info { m.to_human } }
|
74
|
-
c.subscribe( :PortfolioValue, :AccountValue, :OrderStatus, :OpenOrderEnd, :ExecutionData ) {| m| logger.info { m.to_human }}
|
68
|
+
c.subscribe( :ContractData, :BondContractData) { |msg| c.logger.info { msg.contract.to_human } }
|
69
|
+
c.subscribe( :Alert, :ContractDataEnd, :ManagedAccounts, :OrderStatus ) {| m| c.logger.info { m.to_human } }
|
70
|
+
c.subscribe( :PortfolioValue, :AccountValue, :OrderStatus, :OpenOrderEnd, :ExecutionData ) {| m| c.logger.info { m.to_human }}
|
75
71
|
# c.subscribe :ManagedAccounts do |msg|
|
76
72
|
# puts "------------------------------- Managed Accounts ----------------------------------"
|
77
73
|
# puts "Detected Accounts: #{msg.accounts.account.join(' -- ')} "
|
@@ -79,8 +75,8 @@ read_yml = -> (key) do
|
|
79
75
|
# end
|
80
76
|
|
81
77
|
c.subscribe( :OpenOrder){ |msg| "Open Order detected and stored: C.received[:OpenOrders] " }
|
82
|
-
c.logger.level = Logger::INFO
|
83
78
|
end
|
79
|
+
C.logger.level = Logger::INFO
|
84
80
|
unless C.received[:OpenOrder].blank?
|
85
81
|
puts "------------------------------- OpenOrders ----------------------------------"
|
86
82
|
puts C.received[:OpenOrder].to_human.join "\n"
|
data/changelog.md
CHANGED
data/lib/ib/connection.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'thread'
|
2
2
|
#require 'active_support'
|
3
3
|
require 'ib/socket'
|
4
|
-
require '
|
4
|
+
require 'logger'
|
5
|
+
require 'logging'
|
5
6
|
require 'ib/messages'
|
6
7
|
|
7
8
|
module IB
|
@@ -18,10 +19,9 @@ module IB
|
|
18
19
|
## public data-queue: received, received?, wait_for, clear_received
|
19
20
|
## misc: reader_running?
|
20
21
|
|
21
|
-
include
|
22
|
+
include Support::Logging # provides default_logger
|
22
23
|
|
23
24
|
mattr_accessor :current
|
24
|
-
mattr_accessor :logger ## borrowed from active_support
|
25
25
|
# Please note, we are realizing only the most current TWS protocol versions,
|
26
26
|
# thus improving performance at the expense of backwards compatibility.
|
27
27
|
# Older protocol versions support can be found in older gem versions.
|
@@ -40,7 +40,7 @@ module IB
|
|
40
40
|
connect: true, # Connect at initialization
|
41
41
|
received: true, # Keep all received messages in a @received Hash
|
42
42
|
# redis: false, # future plans
|
43
|
-
logger:
|
43
|
+
logger: nil,
|
44
44
|
client_id: rand( 1001 .. 9999 ) ,
|
45
45
|
client_version: IB::Messages::CLIENT_VERSION, # lib/ib/server_versions.rb
|
46
46
|
optional_capacities: "", # TWS-Version 974: "+PACEAPI"
|
@@ -49,17 +49,13 @@ module IB
|
|
49
49
|
# V 974 release motes
|
50
50
|
# API messages sent at a higher rate than 50/second can now be paced by TWS at the 50/second rate instead of potentially causing a disconnection. This is now done automatically by the RTD Server API and can be done with other API technologies by invoking SetConnectOptions("+PACEAPI") prior to eConnect.
|
51
51
|
|
52
|
-
|
52
|
+
self.class.configure_logger logger
|
53
53
|
# convert parameters into instance-variables and assign them
|
54
|
-
|
55
|
-
next unless type == :key
|
56
|
-
|
57
|
-
when :logger
|
58
|
-
self.logger = logger
|
59
|
-
else
|
54
|
+
method(__method__).parameters.each do |type, k|
|
55
|
+
next unless type == :key ## available: key , keyrest
|
56
|
+
next if k.to_s == 'logger'
|
60
57
|
v = eval(k.to_s)
|
61
58
|
instance_variable_set("@#{k}", v) unless v.nil?
|
62
|
-
end
|
63
59
|
end
|
64
60
|
|
65
61
|
# A couple of locks to avoid race conditions in JRuby
|
@@ -79,9 +75,9 @@ module IB
|
|
79
75
|
yield self if block_given?
|
80
76
|
|
81
77
|
self.subscribe(:NextValidId) do |msg|
|
82
|
-
|
78
|
+
self.logger.progname = "Connection#connect"
|
83
79
|
self.next_local_id = msg.local_id
|
84
|
-
|
80
|
+
self.logger.info { "Got next valid order id: #{next_local_id}." }
|
85
81
|
end
|
86
82
|
|
87
83
|
# Ensure the transmission of NextValidId.
|
@@ -100,7 +96,7 @@ module IB
|
|
100
96
|
def update_next_order_id
|
101
97
|
i,finish = 0, false
|
102
98
|
sub = self.subscribe(:NextValidID) { finish = true }
|
103
|
-
connected? ?
|
99
|
+
connected? ? self.send_message( :RequestIds ) : open()
|
104
100
|
Timeout::timeout(1, IB::TransmissionError,"Could not get NextValidId" ) do
|
105
101
|
loop { sleep 0.1; break if finish }
|
106
102
|
end
|
@@ -186,7 +182,13 @@ module IB
|
|
186
182
|
when what.is_a?(Class) && what < Messages::Incoming::AbstractMessage
|
187
183
|
[what]
|
188
184
|
when what.is_a?(Symbol)
|
189
|
-
|
185
|
+
if Messages::Incoming.const_defined?(what)
|
186
|
+
[Messages::Incoming.const_get(what)]
|
187
|
+
elsif TechnicalAnalysis::Signals.const_defined?(what)
|
188
|
+
[TechnicalAnalysis::Signals.const_get?(what)]
|
189
|
+
else
|
190
|
+
error "#{what} is no IB::Messages or TechnicalAnalyis::Signals class"
|
191
|
+
end
|
190
192
|
when what.is_a?(Regexp)
|
191
193
|
Messages::Incoming::Classes.values.find_all { |klass| klass.to_s =~ what }
|
192
194
|
else
|
@@ -416,7 +418,7 @@ module IB
|
|
416
418
|
@subscribe_lock.synchronize do
|
417
419
|
subscribers[msg.class].each { |_, subscriber| subscriber.call(msg) }
|
418
420
|
end
|
419
|
-
logger.
|
421
|
+
logger.info { "No subscribers for message #{msg.class}!" } if subscribers[msg.class].empty?
|
420
422
|
|
421
423
|
# Collect all received messages into a @received Hash
|
422
424
|
if @received
|
data/lib/ib/logger.rb
CHANGED
@@ -30,12 +30,12 @@ module IB
|
|
30
30
|
@created_at = Time.now
|
31
31
|
if source.is_a?(Hash) # Source is a @data Hash
|
32
32
|
@data = source
|
33
|
-
@buffer =[] # initialize empty buffer, indicates a
|
33
|
+
@buffer =[] # initialize empty buffer, indicates a successful initializing
|
34
34
|
else
|
35
35
|
@buffer = source
|
36
36
|
### DEBUG DEBUG DEBUG RAW STREAM ###############
|
37
37
|
# if uncommented, the raw-input from the tws is included in the logging
|
38
|
-
|
38
|
+
## puts "BUFFER :> #{buffer.inspect} "
|
39
39
|
### DEBUG DEBUG DEBUG RAW STREAM ###############
|
40
40
|
@data = Hash.new
|
41
41
|
self.load
|
@@ -43,11 +43,11 @@ module IB
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def valid?
|
46
|
-
@buffer.empty?
|
46
|
+
@buffer.empty?
|
47
47
|
end
|
48
48
|
|
49
49
|
## more recent messages omit the transmission of a version
|
50
|
-
## thus just load the parameter-map
|
50
|
+
## thus just load the parameter-map
|
51
51
|
def simple_load
|
52
52
|
load_map *self.class.data_map
|
53
53
|
rescue IB::Error => e
|
@@ -87,7 +87,7 @@ module IB
|
|
87
87
|
|
88
88
|
when Symbol # Normal map
|
89
89
|
group, name, type, block =
|
90
|
-
if instruction[2].nil? || instruction[2].is_a?(Proc) # lambda's are Proc's
|
90
|
+
if instruction[2].nil? || instruction[2].is_a?(Proc) # lambda's are Proc's
|
91
91
|
[nil] + instruction # No group, [ :name, :type, (:block) ]
|
92
92
|
else
|
93
93
|
instruction # [ :group, :name, :type, (:block)]
|
@@ -95,14 +95,14 @@ module IB
|
|
95
95
|
begin
|
96
96
|
data = @buffer.__send__("read_#{type}", &block)
|
97
97
|
rescue IB::LoadError, NoMethodError => e
|
98
|
-
error "Reading #{self.class}: #{e.class}: #{e.message} --> Instruction: #{name}" , :reader, false
|
98
|
+
error "Reading #{self.class}: #{e.class}: #{e.message} --> Instruction: #{name}" , :reader, false
|
99
99
|
end
|
100
100
|
# debug puts data.inspect
|
101
101
|
if group
|
102
102
|
@data[group] ||= {}
|
103
103
|
@data[group][name] = data
|
104
104
|
else
|
105
|
-
@data[name] = data
|
105
|
+
@data[name] = data
|
106
106
|
end
|
107
107
|
else
|
108
108
|
error "Unrecognized instruction #{instruction}"
|
@@ -26,7 +26,11 @@ module IB
|
|
26
26
|
|
27
27
|
class ReceiveFA
|
28
28
|
def accounts
|
29
|
-
xml[:ListOfAccountAliases][:AccountAlias].
|
29
|
+
if( a= xml[:ListOfAccountAliases][:AccountAlias]).is_a? Array
|
30
|
+
a.map{|x| Account.new x }
|
31
|
+
elsif a.is_a? Hash ## only one account (soley financial advisor)
|
32
|
+
[ Account.new( a ) ]
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
def to_human
|
@@ -41,12 +41,12 @@ module IB
|
|
41
41
|
IB::Bar.new :time => buffer.read_int_date, # conversion of epoche-time-integer to Dateime
|
42
42
|
# requires format_date in request to be "2"
|
43
43
|
# (outgoing/bar_requests # RequestHistoricalData#Encoding)
|
44
|
-
:open => buffer.
|
45
|
-
:high => buffer.
|
46
|
-
:low => buffer.
|
47
|
-
:close => buffer.
|
44
|
+
:open => buffer.read_float,
|
45
|
+
:high => buffer.read_float,
|
46
|
+
:low => buffer.read_float,
|
47
|
+
:close => buffer.read_float,
|
48
48
|
:volume => buffer.read_int,
|
49
|
-
:wap => buffer.
|
49
|
+
:wap => buffer.read_float,
|
50
50
|
# :has_gaps => buffer.read_string, # only in ServerVersion < 124
|
51
51
|
:trades => buffer.read_int
|
52
52
|
end
|
@@ -79,6 +79,26 @@ module IB
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
HistoricalDataUpdate = def_message [90, 0] ,
|
83
|
+
[:request_id, :int] ,
|
84
|
+
[:count, :int],
|
85
|
+
[:bar, :bar] # defined in support.rb
|
86
|
+
|
87
|
+
class HistoricalDataUpdate
|
88
|
+
attr_accessor :results
|
89
|
+
using IBSupport # extended Array-Class from abstract_message
|
90
|
+
|
91
|
+
def bar
|
92
|
+
@bar = IB::Bar.new @data[:bar]
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_human
|
96
|
+
"<HistDataUpdate #{request_id} #{bar}>"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
82
102
|
end # module Incoming
|
83
103
|
end # module Messages
|
84
104
|
end # module IB
|
@@ -25,9 +25,9 @@ module IB
|
|
25
25
|
#
|
26
26
|
def send_to socket
|
27
27
|
### debugging of outgoing Messages
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
# puts "------sendto ---------(debugging output in outgoing/abstract_message)"
|
29
|
+
# puts socket.prepare_message( self.preprocess).inspect.split('\x00')[3..-1].inspect
|
30
|
+
# puts "------sendto ---------"
|
31
31
|
socket.send_messages self.preprocess #.each {|data| socket.write_data data}
|
32
32
|
end
|
33
33
|
|
@@ -18,11 +18,10 @@ module IB
|
|
18
18
|
# unless BAR_SIZES.keys.include?(bar_size)
|
19
19
|
# error ":bar_size must be one of #{BAR_SIZES.inspect}", :args
|
20
20
|
# end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
[data_type, nil, contract]
|
21
|
+
unless data[:contract].is_a? IB::Contract
|
22
|
+
error "contract must be a valid IB::Contract" , :args
|
23
|
+
end
|
24
|
+
[data_type, nil, data[:contract]]
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|