ib-api 972.2 → 972.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c55a18237300e1d54915e0fd71dc9a51766be578b8f25d73dd70a115961ed935
4
- data.tar.gz: f9aed73cec7a0959145d384f655dfbdd9f8416e6b0ddd4e21200ef30d458e149
3
+ metadata.gz: b8adaf6267b470da6c3e9918f11209d0ad63797a4facb61d2f561291a5435be4
4
+ data.tar.gz: 90ae6945b0cfa5dfc4c18b49d4d7fc65296a1b360abbf6e22a6a360c1ecebdb0
5
5
  SHA512:
6
- metadata.gz: 9a0fdbf9030c14c83b164531967ff130af078a3a1bdd6cf44697cb26887012d176ac929279eb8608b2920a2b4dd48b6434a129daf88cfdd1cb65a78014e35db9
7
- data.tar.gz: 64fa9394bd0a90c6a4c8abdc0c0a798816d913f5d25fd40fa67032db459cefb5bd296a1a7827ee05817f887c1b989ada9719494dfd6f348e25c45d0f4d7f37cd
6
+ metadata.gz: d9000425dd681aa181d70c81f6ab02705aba623d0c20fa124fabc652d0a9061ffd655980cc7ae307a9db8412ccb795149dcca4ebcb0239c7051da979298c25e5
7
+ data.tar.gz: 182b84997e82f20134187f4879f3157ad744aa3dd08bc909b6b901beab5817d90d973626b7a67be3da02ee495e4562bf479de635d8ab3897a9b073d5aaa8e33a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 972.2
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? ? self.send_message( :RequestIds ) : open()
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
- [Messages::Incoming.const_get(what)]
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].map{|x| Account.new x }
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.read_decimal,
45
- :high => buffer.read_decimal,
46
- :low => buffer.read_decimal,
47
- :close => buffer.read_decimal,
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.read_decimal,
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
- contract = data[:contract].is_a?(IB::Contract) ?
23
- data[:contract] : IB::Contract.from_ib_ruby(data[:contract])
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
- s= Time.at(t)
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
- 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
-
155
- end
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
- "<Bar: #{time} wap #{wap} OHLC #{open} #{high} #{low} #{close} " +
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
 
@@ -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
@@ -6,7 +6,8 @@ require 'models/ib/underlying'
6
6
  module IB
7
7
 
8
8
  if defined?(Contract)
9
- puts "Contract already a #{defined?(Contract)}"
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 => 0.0,
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
- print_default[strike],
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
- self_attributes = [ :sec_type]
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
- the_hash= the_attributes.map{|x| y= self.send(x); [x,y] if y.present? }.compact.to_h
227
- the_hash[:description] =
228
- if @description.present?
229
- @description
230
- elsif contract_detail.present?
231
- contract_detail.long_name
232
- else
233
- ""
234
- end
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
- # the method is also used to copy Contract.values to new instances
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
- # This returns a Contract initialized from the serialize_ib_ruby format string.
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
@@ -1,6 +1,12 @@
1
- #require 'ib/verify'
1
+ # require 'ib/verify'
2
2
  module IB
3
- class Spread < Bag
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 + " added #{nc.to_human}" rescue "Spread: #{nc.to_human}"
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
- invariant_attributes
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
- object= self.new container['Spread'].read_contract
154
- object.legs = container['legs'].map{|x| IB::Contract.build x.read_contract}
155
- object.combo_legs = container['combo_legs'].map{ |x| read_leg[ x ] }
156
- object.description = container['misc'].read_string
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