ib-api 972.5.1 → 972.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +37 -42
- data/VERSION +1 -1
- data/bin/console +14 -16
- data/bin/console.yml +1 -1
- data/lib/ib/connection.rb +28 -20
- data/lib/ib/messages/outgoing/bar_requests.rb +2 -2
- data/lib/ib/raw_message.rb +85 -0
- data/lib/logging.rb +8 -7
- data/lib/models/ib/contract.rb +1 -1
- data/lib/models/ib/order.rb +6 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25eeaf6f08e2fd29800c3ed6d1ec94adfa5a61fecd2c9a37bfdc9a692f6cbaf9
|
4
|
+
data.tar.gz: aac0683bb11a8d7326a95a69b9e728321a70d70be072ee6d133d09dce6724251
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b28db7e5ee4aa73942e724caf8c65e07df46516eca725868fc7279f31238124d7fee05da3fe8a43737a820b43079790f3f1a77f0ff662600d89fdfcbf0c9734
|
7
|
+
data.tar.gz: ec8e9b32fd01c212249c3fb4da3c7d86b503d0d1cc6cf3854c25a03b98933e0b8a26981c56c45e1cd1799ce352053f3601ea0bef68c3297c41eb15e7c5847048
|
data/Gemfile.lock
CHANGED
@@ -1,39 +1,34 @@
|
|
1
|
-
GIT
|
2
|
-
remote: https://github.com/ohler55/ox.git
|
3
|
-
revision: 67ce6ecb45a0d1354e1f8ed9a155826ba986e21e
|
4
|
-
specs:
|
5
|
-
ox (2.13.4)
|
6
|
-
|
7
1
|
PATH
|
8
2
|
remote: .
|
9
3
|
specs:
|
10
|
-
ib-api (972.2)
|
4
|
+
ib-api (972.5.2)
|
11
5
|
activemodel
|
12
6
|
activesupport (>= 6.0)
|
7
|
+
ox
|
8
|
+
terminal-table
|
13
9
|
|
14
10
|
GEM
|
15
11
|
remote: https://rubygems.org/
|
16
12
|
specs:
|
17
|
-
activemodel (
|
18
|
-
activesupport (=
|
19
|
-
activesupport (
|
13
|
+
activemodel (7.0.4.2)
|
14
|
+
activesupport (= 7.0.4.2)
|
15
|
+
activesupport (7.0.4.2)
|
20
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
21
17
|
i18n (>= 1.6, < 2)
|
22
18
|
minitest (>= 5.1)
|
23
19
|
tzinfo (~> 2.0)
|
24
|
-
zeitwerk (~> 2.3)
|
25
20
|
coderay (1.1.3)
|
26
|
-
concurrent-ruby (1.
|
27
|
-
diff-lcs (1.
|
28
|
-
ffi (1.
|
29
|
-
formatador (
|
30
|
-
guard (2.
|
21
|
+
concurrent-ruby (1.2.2)
|
22
|
+
diff-lcs (1.5.0)
|
23
|
+
ffi (1.15.5)
|
24
|
+
formatador (1.1.0)
|
25
|
+
guard (2.18.0)
|
31
26
|
formatador (>= 0.2.4)
|
32
27
|
listen (>= 2.7, < 4.0)
|
33
28
|
lumberjack (>= 1.0.12, < 2.0)
|
34
29
|
nenv (~> 0.1)
|
35
30
|
notiffany (~> 0.0)
|
36
|
-
pry (>= 0.
|
31
|
+
pry (>= 0.13.0)
|
37
32
|
shellany (~> 0.0)
|
38
33
|
thor (>= 0.18.1)
|
39
34
|
guard-compat (1.2.1)
|
@@ -41,64 +36,64 @@ GEM
|
|
41
36
|
guard (~> 2.1)
|
42
37
|
guard-compat (~> 1.1)
|
43
38
|
rspec (>= 2.99.0, < 4.0)
|
44
|
-
i18n (1.
|
39
|
+
i18n (1.12.0)
|
45
40
|
concurrent-ruby (~> 1.0)
|
46
|
-
listen (3.
|
41
|
+
listen (3.8.0)
|
47
42
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
48
43
|
rb-inotify (~> 0.9, >= 0.9.10)
|
49
44
|
lumberjack (1.2.8)
|
50
45
|
method_source (1.0.0)
|
51
|
-
minitest (5.
|
46
|
+
minitest (5.17.0)
|
52
47
|
nenv (0.3.0)
|
53
48
|
notiffany (0.1.3)
|
54
49
|
nenv (~> 0.1)
|
55
50
|
shellany (~> 0.0)
|
56
|
-
|
51
|
+
ox (2.14.14)
|
52
|
+
pry (0.14.2)
|
57
53
|
coderay (~> 1.1)
|
58
54
|
method_source (~> 1.0)
|
59
|
-
rake (13.0.
|
60
|
-
rb-fsevent (0.
|
55
|
+
rake (13.0.6)
|
56
|
+
rb-fsevent (0.11.2)
|
61
57
|
rb-inotify (0.10.1)
|
62
58
|
ffi (~> 1.0)
|
63
|
-
rspec (3.
|
64
|
-
rspec-core (~> 3.
|
65
|
-
rspec-expectations (~> 3.
|
66
|
-
rspec-mocks (~> 3.
|
59
|
+
rspec (3.12.0)
|
60
|
+
rspec-core (~> 3.12.0)
|
61
|
+
rspec-expectations (~> 3.12.0)
|
62
|
+
rspec-mocks (~> 3.12.0)
|
67
63
|
rspec-collection_matchers (1.2.0)
|
68
64
|
rspec-expectations (>= 2.99.0.beta1)
|
69
|
-
rspec-core (3.
|
70
|
-
rspec-support (~> 3.
|
71
|
-
rspec-expectations (3.
|
65
|
+
rspec-core (3.12.1)
|
66
|
+
rspec-support (~> 3.12.0)
|
67
|
+
rspec-expectations (3.12.2)
|
72
68
|
diff-lcs (>= 1.2.0, < 2.0)
|
73
|
-
rspec-support (~> 3.
|
69
|
+
rspec-support (~> 3.12.0)
|
74
70
|
rspec-its (1.3.0)
|
75
71
|
rspec-core (>= 3.0.0)
|
76
72
|
rspec-expectations (>= 3.0.0)
|
77
|
-
rspec-mocks (3.
|
73
|
+
rspec-mocks (3.12.3)
|
78
74
|
diff-lcs (>= 1.2.0, < 2.0)
|
79
|
-
rspec-support (~> 3.
|
80
|
-
rspec-support (3.
|
75
|
+
rspec-support (~> 3.12.0)
|
76
|
+
rspec-support (3.12.0)
|
81
77
|
shellany (0.0.1)
|
82
|
-
|
83
|
-
|
78
|
+
terminal-table (3.0.2)
|
79
|
+
unicode-display_width (>= 1.1.1, < 3)
|
80
|
+
thor (1.2.1)
|
81
|
+
tzinfo (2.0.6)
|
84
82
|
concurrent-ruby (~> 1.0)
|
85
|
-
|
86
|
-
zeitwerk (2.4.2)
|
83
|
+
unicode-display_width (2.4.2)
|
87
84
|
|
88
85
|
PLATFORMS
|
89
|
-
|
86
|
+
x86_64-linux
|
90
87
|
|
91
88
|
DEPENDENCIES
|
92
89
|
bundler
|
93
90
|
guard
|
94
91
|
guard-rspec
|
95
92
|
ib-api!
|
96
|
-
ox!
|
97
93
|
rake (~> 13.0)
|
98
94
|
rspec
|
99
95
|
rspec-collection_matchers
|
100
96
|
rspec-its
|
101
|
-
value_semantics
|
102
97
|
|
103
98
|
BUNDLED WITH
|
104
|
-
|
99
|
+
2.3.22
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
972.5.
|
1
|
+
972.5.2
|
data/bin/console
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
### loads the active-orient environment
|
3
|
-
### and starts an interactive shell
|
4
2
|
###
|
5
3
|
### Parameter: t)ws | g)ateway (or number of port ) Default: Gateway ,
|
6
4
|
### client_id , Default 2000
|
@@ -17,10 +15,10 @@ class Array
|
|
17
15
|
# i.e
|
18
16
|
#
|
19
17
|
# 2.5.0 :006 > C.received[:OpenOrder].local_id
|
20
|
-
# => [16, 17, 21, 20, 19, 8, 7]
|
18
|
+
# => [16, 17, 21, 20, 19, 8, 7]
|
21
19
|
# 2.5.0 :007 > C.received[:OpenOrder].contract.to_human
|
22
|
-
# => ["<Bag: IECombo SMART USD legs: >", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: WFC USD>", "<Stock: WFC USD>"]
|
23
|
-
|
20
|
+
# => ["<Bag: IECombo SMART USD legs: >", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: GE USD>", "<Stock: WFC USD>", "<Stock: WFC USD>"]
|
21
|
+
|
24
22
|
# its included only in the console, for inspection purposes
|
25
23
|
|
26
24
|
def method_missing(method, *key)
|
@@ -32,16 +30,16 @@ class Array
|
|
32
30
|
end # Array
|
33
31
|
|
34
32
|
|
35
|
-
# read items from console.yml
|
33
|
+
# read items from console.yml
|
36
34
|
read_yml = -> (key) do
|
37
35
|
YAML::load_file( File.expand_path('../console.yml',__FILE__))[key]
|
38
36
|
end
|
39
37
|
|
40
38
|
|
41
|
-
puts
|
42
|
-
puts ">> IB-Core Interactive Console <<"
|
39
|
+
puts
|
40
|
+
puts ">> IB-Core Interactive Console <<"
|
43
41
|
puts '-'* 45
|
44
|
-
puts
|
42
|
+
puts
|
45
43
|
puts "Namespace is IB ! "
|
46
44
|
puts
|
47
45
|
puts '-'* 45
|
@@ -59,23 +57,23 @@ read_yml = -> (key) do
|
|
59
57
|
end
|
60
58
|
|
61
59
|
ARGV.clear
|
62
|
-
|
60
|
+
|
63
61
|
## The Block takes instructions which are executed after initializing all instance-variables
|
64
62
|
## and prior to the connection-process
|
65
|
-
## Here we just subscribe to some events
|
66
|
-
C = Connection.new
|
63
|
+
## Here we just subscribe to some events
|
64
|
+
C = Connection.new client_id: client_id, port: port do |c| # future use__ , optional_capacities: "+PACEAPI" do |c|
|
67
65
|
|
68
66
|
c.subscribe( :ContractData, :BondContractData) { |msg| c.logger.info { msg.contract.to_human } }
|
69
67
|
c.subscribe( :Alert, :ContractDataEnd, :ManagedAccounts, :OrderStatus ) {| m| c.logger.info { m.to_human } }
|
70
68
|
c.subscribe( :PortfolioValue, :AccountValue, :OrderStatus, :OpenOrderEnd, :ExecutionData ) {| m| c.logger.info { m.to_human }}
|
71
69
|
# c.subscribe :ManagedAccounts do |msg|
|
72
|
-
# puts "
|
73
|
-
# puts "Detected Accounts: #{msg.
|
70
|
+
# puts "------------------------------ Managed Accounts ----------------------------------"
|
71
|
+
# puts "Detected Accounts: #{msg.acounts.account.join(' -- ')} "
|
74
72
|
# puts
|
75
73
|
# end
|
76
74
|
|
77
|
-
c.subscribe( :OpenOrder){ |msg| "Open Order detected and stored: C.received[:OpenOrders] " }
|
78
|
-
end
|
75
|
+
c.subscribe( :OpenOrder){ |msg| puts "Open Order detected and stored: C.received[:OpenOrders] " }
|
76
|
+
end
|
79
77
|
#C.logger.level = Logger::FATAL
|
80
78
|
unless C.received[:OpenOrder].blank?
|
81
79
|
puts "------------------------------- OpenOrders ----------------------------------"
|
data/bin/console.yml
CHANGED
data/lib/ib/connection.rb
CHANGED
@@ -182,7 +182,7 @@ module IB
|
|
182
182
|
when what.is_a?(Symbol)
|
183
183
|
if Messages::Incoming.const_defined?(what)
|
184
184
|
[Messages::Incoming.const_get(what)]
|
185
|
-
elsif TechnicalAnalysis::Signals.const_defined?(what)
|
185
|
+
elsif defined?( TechnicalAnalysis ) && TechnicalAnalysis::Signals.const_defined?(what)
|
186
186
|
[TechnicalAnalysis::Signals.const_get?(what)]
|
187
187
|
else
|
188
188
|
error "#{what} is no IB::Messages or TechnicalAnalyis::Signals class"
|
@@ -284,22 +284,27 @@ module IB
|
|
284
284
|
begin
|
285
285
|
while (time_left = time_out - Time.now) > 0
|
286
286
|
# If socket is readable, process single incoming message
|
287
|
-
|
287
|
+
if RUBY_PLATFORM.match(/cygwin|mswin|mingw|bccwin|wince|emx/)
|
288
|
+
process_message if select [socket], nil, nil, time_left
|
289
|
+
|
290
|
+
|
288
291
|
# the following checks for shutdown of TWS side; ensures we don't run in a spin loop.
|
289
292
|
# unfortunately, it raises Errors in windows environment
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
293
|
+
else
|
294
|
+
if select [socket], nil, nil, time_left
|
295
|
+
# # Peek at the message from the socket; if it's blank then the
|
296
|
+
# # server side of connection (TWS) has likely shut down.
|
297
|
+
socket_likely_shutdown = socket.recvmsg(100, Socket::MSG_PEEK)[0] == ""
|
298
|
+
#
|
299
|
+
# # We go ahead process messages regardless (a no-op if socket_likely_shutdown).
|
300
|
+
process_message
|
301
|
+
#
|
302
|
+
# # After processing, if socket has shut down we sleep for 100ms
|
303
|
+
# # to avoid spinning in a tight loop. If the server side somehow
|
304
|
+
# # comes back up (gets reconnedted), normal processing
|
305
|
+
# # (without the 100ms wait) should happen.
|
306
|
+
sleep(0.1) if socket_likely_shutdown
|
307
|
+
end
|
303
308
|
end
|
304
309
|
end
|
305
310
|
rescue Errno::ECONNRESET => e
|
@@ -307,7 +312,7 @@ module IB
|
|
307
312
|
if e.message =~ /Connection reset by peer/
|
308
313
|
logger.fatal "Is another client listening on the same port?"
|
309
314
|
error "try reconnecting with a different client-id", :reader
|
310
|
-
else
|
315
|
+
else
|
311
316
|
logger.fatal "Aborting"
|
312
317
|
Kernel.exit
|
313
318
|
end
|
@@ -417,14 +422,17 @@ module IB
|
|
417
422
|
msg_id = the_decoded_message.shift.to_i
|
418
423
|
|
419
424
|
# Debug:
|
420
|
-
|
425
|
+
logger.debug { "Got message #{msg_id} (#{Messages::Incoming::Classes[msg_id]})"}
|
421
426
|
|
422
427
|
# Create new instance of the appropriate message type,
|
423
428
|
# and have it read the message from socket.
|
424
429
|
# NB: Failure here usually means unsupported message type received
|
425
|
-
|
426
|
-
|
427
|
-
|
430
|
+
unless Messages::Incoming::Classes[msg_id]
|
431
|
+
logger.error { "Got unsupported message #{msg_id}" }
|
432
|
+
error "Something strange happened - Reader has to be restarted" , :reader, true if msg_id.to_i.zero?
|
433
|
+
else
|
434
|
+
msg = Messages::Incoming::Classes[msg_id].new(the_decoded_message)
|
435
|
+
end
|
428
436
|
|
429
437
|
# Deliver message to all registered subscribers, alert if no subscribers
|
430
438
|
# Ruby 2.0 and above: Hashes are ordered.
|
@@ -62,7 +62,7 @@ module IB
|
|
62
62
|
bar_size,
|
63
63
|
data_type.to_s.upcase,
|
64
64
|
@data[:use_rth] ,
|
65
|
-
"
|
65
|
+
"" # not suported realtimebars option string
|
66
66
|
]
|
67
67
|
end
|
68
68
|
end # RequestRealTimeBars
|
@@ -189,7 +189,7 @@ module IB
|
|
189
189
|
2 , # @data[:format_date], format-date is hard-coded as int_date in incoming/historicalData
|
190
190
|
contract.serialize_legs ,
|
191
191
|
@data[:keep_up_todate], # 0 / 1
|
192
|
-
'
|
192
|
+
'' # chartOptions:TagValueList - For internal use only. Use default value XYZ.
|
193
193
|
]
|
194
194
|
end
|
195
195
|
end # RequestHistoricalData
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IB
|
4
|
+
# Convert data passed in from a TCP socket stream, and convert into
|
5
|
+
# raw messages. The messages
|
6
|
+
class RawMessageParser
|
7
|
+
HEADER_LNGTH = 4
|
8
|
+
def initialize(socket)
|
9
|
+
@socket = socket
|
10
|
+
@data = String.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
while true
|
15
|
+
append_new_data
|
16
|
+
|
17
|
+
next unless length_data?
|
18
|
+
next unless enough_data?
|
19
|
+
|
20
|
+
length = next_msg_length
|
21
|
+
validate_data_header(length)
|
22
|
+
|
23
|
+
raw = grab_message(length)
|
24
|
+
validate_message_footer(raw, length)
|
25
|
+
msg = parse_message(raw, length)
|
26
|
+
remove_message
|
27
|
+
yield msg
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# extract message and convert to
|
32
|
+
# an array split by null characters.
|
33
|
+
def grab_message(length)
|
34
|
+
@data.byteslice(HEADER_LNGTH, length)
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_message(raw, length)
|
38
|
+
raw.unpack1("A#{length}").split("\0")
|
39
|
+
end
|
40
|
+
|
41
|
+
def remove_message
|
42
|
+
length = next_msg_length
|
43
|
+
leftovers = @data.byteslice(length + HEADER_LNGTH..-1)
|
44
|
+
@data = if leftovers.nil?
|
45
|
+
String.new
|
46
|
+
else
|
47
|
+
leftovers
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def enough_data?
|
52
|
+
actual_lngth = next_msg_length + HEADER_LNGTH
|
53
|
+
echo 'too little data' if next_msg_length.nil?
|
54
|
+
return false if next_msg_length.nil?
|
55
|
+
@data.bytesize >= actual_lngth
|
56
|
+
end
|
57
|
+
|
58
|
+
def length_data?
|
59
|
+
@data.bytesize > HEADER_LNGTH
|
60
|
+
end
|
61
|
+
|
62
|
+
def next_msg_length
|
63
|
+
#can't check length if first 4 bytes don't exist
|
64
|
+
length = @data.byteslice(0..3).unpack1('N')
|
65
|
+
return 0 if length.nil?
|
66
|
+
length
|
67
|
+
end
|
68
|
+
|
69
|
+
def append_new_data
|
70
|
+
@data += @socket.recv_from
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_message_footer(msg,length)
|
74
|
+
last = msg.bytesize
|
75
|
+
last_byte = msg.byteslice(last-1,last)
|
76
|
+
raise 'Could not validate last byte' if last_byte.nil?
|
77
|
+
raise "Message has an invalid last byte. expecting \0, received: #{last_byte}" if last_byte != "\0"
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_data_header(length)
|
81
|
+
return true if length <= 5000
|
82
|
+
raise 'Message is longer than sane max length'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/logging.rb
CHANGED
@@ -26,20 +26,21 @@ module Support
|
|
26
26
|
@logger = logger
|
27
27
|
end
|
28
28
|
|
29
|
-
def configure_logger(log=
|
30
|
-
|
29
|
+
def configure_logger(log= STDOUT)
|
30
|
+
if log.is_a? Logger
|
31
31
|
@logger = log
|
32
32
|
else
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
@logger = Logger.new log
|
34
|
+
end
|
35
|
+
@logger.level = Logger::INFO
|
36
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
36
37
|
# "#{datetime.strftime("%d.%m.(%X)")}#{"%5s" % severity}->#{msg}\n"
|
37
38
|
"#{"%1s" % severity[0]}: #{msg}\n"
|
38
39
|
end
|
39
|
-
|
40
|
-
end # branch
|
40
|
+
@logger.debug "------------------------------ start logging ----------------------------"
|
41
41
|
end # def
|
42
42
|
end # module ClassMethods
|
43
43
|
end # module Logging
|
44
44
|
end # module Support
|
45
45
|
|
46
|
+
# source: https://github.com/jondot/sneakers/blob/master/lib/sneakers/concerns/logging.rb
|
data/lib/models/ib/contract.rb
CHANGED
data/lib/models/ib/order.rb
CHANGED
@@ -537,5 +537,11 @@ Format of serialisation
|
|
537
537
|
'OrderState' => order_state}
|
538
538
|
end
|
539
539
|
|
540
|
+
# expell uncommon attributes
|
541
|
+
def invariant_attributes
|
542
|
+
attributes.reject{ |x| [ :designated_location, :display_size, :etrade_only, :exempt_code, :ext_operator, :random_size, :random_price, :firm_quote_only, :scale_auto_reset, :scale_random_percent, :scale_table, :short_sale_slot, :solicided, :created_at, :modified_at ].include? x }
|
543
|
+
|
544
|
+
end
|
545
|
+
|
540
546
|
end # class Order
|
541
547
|
end # module IB
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ib-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 972.5.
|
4
|
+
version: 972.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hartmut Bischoff
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -165,6 +165,7 @@ files:
|
|
165
165
|
- lib/ib/messages/outgoing/request_tick_data.rb
|
166
166
|
- lib/ib/model.rb
|
167
167
|
- lib/ib/models.rb
|
168
|
+
- lib/ib/raw_message.rb
|
168
169
|
- lib/ib/server_versions.rb
|
169
170
|
- lib/ib/socket.rb
|
170
171
|
- lib/ib/support.rb
|