ib-api 972.2 → 972.3
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/VERSION +1 -1
- data/lib/ib/connection.rb +13 -2
- 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/bar_requests.rb +4 -5
- data/lib/ib/support.rb +30 -15
- 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 +31 -39
- data/lib/models/ib/spread.rb +22 -17
- metadata +3 -16
- 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: b8adaf6267b470da6c3e9918f11209d0ad63797a4facb61d2f561291a5435be4
|
4
|
+
data.tar.gz: 90ae6945b0cfa5dfc4c18b49d4d7fc65296a1b360abbf6e22a6a360c1ecebdb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9000425dd681aa181d70c81f6ab02705aba623d0c20fa124fabc652d0a9061ffd655980cc7ae307a9db8412ccb795149dcca4ebcb0239c7051da979298c25e5
|
7
|
+
data.tar.gz: 182b84997e82f20134187f4879f3157ad744aa3dd08bc909b6b901beab5817d90d973626b7a67be3da02ee495e4562bf479de635d8ab3897a9b073d5aaa8e33a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
972.
|
1
|
+
972.3
|
data/lib/ib/connection.rb
CHANGED
@@ -4,6 +4,11 @@ require 'ib/socket'
|
|
4
4
|
require 'ib/logger'
|
5
5
|
require 'ib/messages'
|
6
6
|
|
7
|
+
module TechnicalAnalysis
|
8
|
+
module Signals
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
7
12
|
module IB
|
8
13
|
# Encapsulates API connection to TWS or Gateway
|
9
14
|
class Connection
|
@@ -100,7 +105,7 @@ module IB
|
|
100
105
|
def update_next_order_id
|
101
106
|
i,finish = 0, false
|
102
107
|
sub = self.subscribe(:NextValidID) { finish = true }
|
103
|
-
connected? ?
|
108
|
+
connected? ? self.send_message( :RequestIds ) : open()
|
104
109
|
Timeout::timeout(1, IB::TransmissionError,"Could not get NextValidId" ) do
|
105
110
|
loop { sleep 0.1; break if finish }
|
106
111
|
end
|
@@ -186,7 +191,13 @@ module IB
|
|
186
191
|
when what.is_a?(Class) && what < Messages::Incoming::AbstractMessage
|
187
192
|
[what]
|
188
193
|
when what.is_a?(Symbol)
|
189
|
-
|
194
|
+
if Messages::Incoming.const_defined?(what)
|
195
|
+
[Messages::Incoming.const_get(what)]
|
196
|
+
elsif TechnicalAnalysis::Signals.const_defined?(what)
|
197
|
+
[TechnicalAnalysis::Signals.const_get?(what)]
|
198
|
+
else
|
199
|
+
error "#{what} is no IB::Messages or TechnicalAnalyis::Signals class"
|
200
|
+
end
|
190
201
|
when what.is_a?(Regexp)
|
191
202
|
Messages::Incoming::Classes.values.find_all { |klass| klass.to_s =~ what }
|
192
203
|
else
|
@@ -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
|
@@ -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
|
|
data/lib/ib/support.rb
CHANGED
@@ -62,7 +62,7 @@ module IBSupport
|
|
62
62
|
|
63
63
|
def read_int_date
|
64
64
|
t= read_int
|
65
|
-
|
65
|
+
s= Time.at(t.to_i)
|
66
66
|
# s.year == 1970 --> data is most likely a date-string
|
67
67
|
s.year == 1970 ? Date.parse(t.to_s) : s
|
68
68
|
end
|
@@ -139,20 +139,35 @@ module IBSupport
|
|
139
139
|
end
|
140
140
|
#
|
141
141
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
142
|
+
def read_contract # read a standard contract and return als hash
|
143
|
+
{ con_id: read_int,
|
144
|
+
symbol: read_string,
|
145
|
+
sec_type: read_string,
|
146
|
+
expiry: read_string,
|
147
|
+
strike: read_decimal,
|
148
|
+
right: read_string,
|
149
|
+
multiplier: read_int,
|
150
|
+
exchange: read_string,
|
151
|
+
currency: read_string,
|
152
|
+
local_symbol: read_string,
|
153
|
+
trading_class: read_string } # new Version 8
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
def read_bar # read a standard bar (Historical data bars)
|
158
|
+
{ :time => read_int_date, # conversion of epoche-time-integer to Dateime
|
159
|
+
# requires format_date in request to be "2"
|
160
|
+
# (outgoing/bar_requests # RequestHistoricalData#Encoding)
|
161
|
+
:open => read_float,
|
162
|
+
:high => read_float,
|
163
|
+
:low => read_float,
|
164
|
+
:close => read_float,
|
165
|
+
:wap => read_float,
|
166
|
+
:volume => read_int,
|
167
|
+
# :has_gaps => read_string, # only in ServerVersion < 124
|
168
|
+
:trades => read_int }
|
169
|
+
|
170
|
+
end
|
156
171
|
|
157
172
|
|
158
173
|
alias read_bool read_boolean
|
data/lib/models/ib/bag.rb
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
module IB
|
4
4
|
|
5
|
+
if defined?(Bag)
|
6
|
+
puts "Bag already a #{defined?(Bag)}"
|
7
|
+
|
8
|
+
# puts Bag.ancestors
|
9
|
+
IB.send(:remove_const, 'Bag')
|
10
|
+
end
|
5
11
|
# "BAG" is not really a contract, but a combination (combo) of securities.
|
6
12
|
# AKA basket or bag of securities. Individual securities in combo are represented
|
7
13
|
# by ComboLeg objects.
|
data/lib/models/ib/bar.rb
CHANGED
@@ -22,7 +22,7 @@ module IB
|
|
22
22
|
validates_numericality_of :open, :high, :low, :close, :volume
|
23
23
|
|
24
24
|
def to_human
|
25
|
-
|
25
|
+
"<Bar: #{time.strftime("(%d.%m.%y)%X")} wap #{wap.round(3)} OHLC #{open} #{high} #{low} #{close} " +
|
26
26
|
(trades ? "trades #{trades}" : "") + " vol #{volume}>"
|
27
27
|
end
|
28
28
|
|
data/lib/models/ib/combo_leg.rb
CHANGED
@@ -83,6 +83,28 @@ module IB
|
|
83
83
|
].flatten
|
84
84
|
end
|
85
85
|
|
86
|
+
|
87
|
+
# fields are generated by serialize(:extended)
|
88
|
+
# i.e.
|
89
|
+
# z= Strangle.build from: Symbols::Index.stoxx, p: 3700, c: 4000, expiry: 202106
|
90
|
+
# zc= z.combo_legs.serialize :extended
|
91
|
+
# => [[321584786, 1, "BUY", "DTB", 0, 0, "", -1], [321584637, 1, "BUY", "DTB", 0, 0, "", -1]]
|
92
|
+
# nz = zc.map{|o| ComboLeg.build *o }
|
93
|
+
# zc.map{|o| ComboLeg.build o } => # is equivalent
|
94
|
+
# => [#<IB::ComboLeg:0x0000000001c36bc0 @attributes={:con_id=>321584786, :ratio=>1, :side=>"B", :exchange=>"DTB", ...
|
95
|
+
# nz.first == z.combo_legs.first => true
|
96
|
+
#
|
97
|
+
def self.build *fields
|
98
|
+
self.new Hash[[:con_id,
|
99
|
+
:ratio,
|
100
|
+
:side, # reverse to_sup?
|
101
|
+
:exchange,
|
102
|
+
:open_close,
|
103
|
+
:short_sale_slot,
|
104
|
+
:designated_location,
|
105
|
+
:exempt_code].zip fields]
|
106
|
+
end
|
107
|
+
|
86
108
|
def to_human
|
87
109
|
"<ComboLeg: #{side} #{ratio} con_id #{con_id} at #{exchange}>"
|
88
110
|
end
|
data/lib/models/ib/contract.rb
CHANGED
@@ -6,7 +6,8 @@ require 'models/ib/underlying'
|
|
6
6
|
module IB
|
7
7
|
|
8
8
|
if defined?(Contract)
|
9
|
-
|
9
|
+
#Connection.current.logger.warn "Contract already a #{defined?(Contract)}"
|
10
|
+
|
10
11
|
# puts Contract.ancestors
|
11
12
|
# IB.send(:remove_const, 'Contract')
|
12
13
|
end
|
@@ -119,7 +120,7 @@ module IB
|
|
119
120
|
|
120
121
|
def default_attributes # :nodoc:
|
121
122
|
super.merge :con_id => 0,
|
122
|
-
:strike =>
|
123
|
+
:strike => "",
|
123
124
|
:right => :none, # Not an option
|
124
125
|
# :exchange => 'SMART',
|
125
126
|
:include_expired => false
|
@@ -136,15 +137,13 @@ module IB
|
|
136
137
|
|
137
138
|
def serialize *fields # :nodoc:
|
138
139
|
print_default = ->(field, default="") { field.blank? ? default : field }
|
139
|
-
## Non numeric entries are passed untouched, only 0 is converted to the default value
|
140
|
-
## Thus: a Zero-Strike-Option has to be defined with «strike: "0"»
|
141
|
-
print_not_zero = ->(field, default="") { field.is_a?(Numeric) && field.zero? ? default : field }
|
142
140
|
[(con_id.present? && !con_id.is_a?(Symbol) && con_id.to_i > 0 ? con_id : ""),
|
143
141
|
print_default[symbol],
|
144
142
|
print_default[self[:sec_type]],
|
145
143
|
( fields.include?(:option) ?
|
146
144
|
[ print_default[expiry],
|
147
|
-
|
145
|
+
## a Zero-Strike-Option has to be defined with «strike: -1 »
|
146
|
+
strike.present? && ( strike.is_a?(Numeric) && !strike.zero? && strike > 0 ) ? strike : strike<0 ? 0 : "",
|
148
147
|
print_default[self[:right]],
|
149
148
|
print_default[multiplier]] : nil ),
|
150
149
|
print_default[exchange],
|
@@ -219,20 +218,18 @@ module IB
|
|
219
218
|
# the link to contract-details is __not__ maintained.
|
220
219
|
def essential
|
221
220
|
|
222
|
-
|
223
|
-
the_attributes = [ :symbol , :con_id, :exchange, :right,
|
221
|
+
the_attributes = [ :sec_type, :symbol , :con_id, :exchange, :right,
|
224
222
|
:currency, :expiry, :strike, :local_symbol, :last_trading_day,
|
225
|
-
:multiplier, :primary_exchange, :trading_class ]
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
self.class.new the_hash.merge( self_attributes.map{|x| y = self.send(x); [x,y] unless y == :none }.compact.to_h )
|
223
|
+
:multiplier, :primary_exchange, :trading_class, :description ]
|
224
|
+
new_contract= self.class.new invariant_attributes.select{|k,_| the_attributes.include? k }.compact
|
225
|
+
new_contract[:description] = if @description.present?
|
226
|
+
@description
|
227
|
+
elsif contract_detail.present?
|
228
|
+
contract_detail.long_name
|
229
|
+
else
|
230
|
+
""
|
231
|
+
end
|
232
|
+
new_contract # return contract
|
236
233
|
end
|
237
234
|
|
238
235
|
|
@@ -383,6 +380,7 @@ In places where these terms are used to indicate a concept, we have left them as
|
|
383
380
|
|
384
381
|
|
385
382
|
### Now let's deal with Contract subclasses
|
383
|
+
begin
|
386
384
|
|
387
385
|
require_relative 'option'
|
388
386
|
require 'models/ib/bag'
|
@@ -390,9 +388,20 @@ In places where these terms are used to indicate a concept, we have left them as
|
|
390
388
|
require 'models/ib/future'
|
391
389
|
require 'models/ib/stock'
|
392
390
|
require 'models/ib/index'
|
391
|
+
### walkaraound to enable spreads with orientdb
|
392
|
+
if IB::const_defined? :Spread
|
393
|
+
IB::send(:remove_const, :Spread)
|
394
|
+
#puts "Spread already defined"
|
395
|
+
#puts "erasing"
|
396
|
+
end
|
397
|
+
require 'models/ib/spread.rb'
|
398
|
+
end
|
399
|
+
|
400
|
+
|
393
401
|
|
394
402
|
class Contract
|
395
403
|
# Contract subclasses representing specialized security types.
|
404
|
+
using IBSupport
|
396
405
|
|
397
406
|
Subclasses = Hash.new(Contract)
|
398
407
|
Subclasses[:bag] = IB::Bag
|
@@ -405,31 +414,14 @@ In places where these terms are used to indicate a concept, we have left them as
|
|
405
414
|
|
406
415
|
|
407
416
|
# This builds an appropriate Contract subclass based on its type
|
408
|
-
|
409
|
-
|
417
|
+
#
|
418
|
+
# the method is also used to copy Contract.values to new instances
|
410
419
|
def self.build opts = {}
|
411
420
|
subclass =( VALUES[:sec_type][opts[:sec_type]] || opts['sec_type'] || opts[:sec_type]).to_sym
|
412
421
|
Contract::Subclasses[subclass].new opts
|
413
422
|
end
|
414
423
|
|
415
|
-
|
416
|
-
def self.from_ib_ruby
|
417
|
-
keys = [:con_id, :symbol, :sec_type, :expiry, :strike, :right, :multiplier,
|
418
|
-
:exchange, :primary_exchange, :currency, :local_symbol]
|
419
|
-
props = Hash[keys.zip(string.split(":"))]
|
420
|
-
props.delete_if { |k, v| v.nil? || v.empty? }
|
421
|
-
Contract.build props
|
422
|
-
end
|
424
|
+
|
423
425
|
end # class Contract
|
424
426
|
end # module IB
|
425
427
|
|
426
|
-
class String
|
427
|
-
def to_contract
|
428
|
-
keys = [:con_id, :symbol, :sec_type, :expiry, :strike, :right, :multiplier,
|
429
|
-
:exchange, :primary_exchange, :currency, :local_symbol]
|
430
|
-
props = Hash[keys.zip(split(":"))]
|
431
|
-
props.delete_if { |k, v| v.nil? || v.empty? }
|
432
|
-
IB::Contract.build props
|
433
|
-
|
434
|
-
end
|
435
|
-
end
|
data/lib/models/ib/spread.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
#require 'ib/verify'
|
1
|
+
# require 'ib/verify'
|
2
2
|
module IB
|
3
|
-
|
3
|
+
if defined?(Spread)
|
4
|
+
puts "Bag already a #{defined?(Spread)}"
|
5
|
+
|
6
|
+
# puts Spread.ancestors
|
7
|
+
IB.send(:remove_const, 'Spread')
|
8
|
+
end
|
9
|
+
class Spread < Bag
|
4
10
|
has_many :legs
|
5
11
|
|
6
12
|
using IBSupport
|
@@ -63,14 +69,6 @@ Adds (or substracts) relative (back) measures to the front month, just passes ab
|
|
63
69
|
end
|
64
70
|
|
65
71
|
|
66
|
-
|
67
|
-
def serialize_rabbit
|
68
|
-
{ "Spread" => serialize( :option, :trading_class ),
|
69
|
-
'legs' => legs.map{ |y| y.serialize :option, :trading_class }, 'combo_legs' => combo_legs.map(&:serialize),
|
70
|
-
'misc' => [description]
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
74
72
|
# adds a leg to any spread
|
75
73
|
#
|
76
74
|
# Parameter:
|
@@ -90,7 +88,7 @@ Adds (or substracts) relative (back) measures to the front month, just passes ab
|
|
90
88
|
the_leg= ComboLeg.new( nc.attributes.slice( :con_id, :exchange )
|
91
89
|
.merge( leg_params ))
|
92
90
|
self.combo_legs << the_leg
|
93
|
-
self.description = description
|
91
|
+
self.description = "#{description.nil? ? "": description} added #{nc.to_human}" rescue "Spread: #{nc.to_human}"
|
94
92
|
self.legs << nc
|
95
93
|
end
|
96
94
|
self # return value to enable chaining
|
@@ -109,9 +107,15 @@ Adds (or substracts) relative (back) measures to the front month, just passes ab
|
|
109
107
|
self
|
110
108
|
end
|
111
109
|
|
112
|
-
|
110
|
+
# essentail
|
111
|
+
# effectivley clones the object
|
112
|
+
#
|
113
113
|
def essential
|
114
|
-
|
114
|
+
the_es = self.class.new invariant_attributes
|
115
|
+
the_es.legs = legs.map{|y| IB::Contract.build y.invariant_attributes}
|
116
|
+
the_es.combo_legs = combo_legs.map{|y| IB::ComboLeg.new y.invariant_attributes }
|
117
|
+
the_es.description = description
|
118
|
+
the_es # return
|
115
119
|
end
|
116
120
|
|
117
121
|
def multiplier
|
@@ -150,13 +154,14 @@ Adds (or substracts) relative (back) measures to the front month, just passes ab
|
|
150
154
|
:exchange => a.read_string
|
151
155
|
|
152
156
|
end
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
+
object= self.new container['Spread'].clone.read_contract
|
158
|
+
object.legs = container['legs'].map{|x| IB::Contract.build x.clone.read_contract}
|
159
|
+
object.combo_legs = container['combo_legs'].map{ |x| read_leg[ x.clone ] }
|
160
|
+
object.description = container['misc'].clone.read_string
|
157
161
|
object
|
158
162
|
|
159
163
|
end
|
164
|
+
|
160
165
|
end
|
161
166
|
|
162
167
|
|