ib-extensions 1.0 → 1.1

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: b31bb7c59e25916c0ebc180446628175867a793e0c1020c7937b4226d67bc6da
4
- data.tar.gz: f3dbe5677eb8551819595134ed91fa08027d677863a0be778fe3a5011ca41235
3
+ metadata.gz: 57f9f4c819b5b0af154107d63a7cb970b2ab9209ef849f88246c185d287d3202
4
+ data.tar.gz: c8572a97aa46fe3ef9331bb7a4247f33ef43f5b4584cbd6223770ac1adcd3ced
5
5
  SHA512:
6
- metadata.gz: 9238aac43cf451bfc78e6afade296423b48d0b7c361a38338d3cd3e121a22df5e5b216296f890fbbaeb9647fc7d96c2a2e86e55321ac09f538844f3f8cc13ea6
7
- data.tar.gz: 477b5078b89583fcf8856a966e05558c53b85f0d746e036c11e4fd4ff8c08c0aca23c617044c3eea1f4f068b054d02622155aae7e4ebf9954c4dfc52da60b62b
6
+ metadata.gz: 383509cac1aa159affe7e8c73b62d0ea60fe825987b0cd8efaa60d24b50cd9f4eb8f6085c4b9d9bc22d0a06923a774df0c59436eabcfa4563620da60ae964503
7
+ data.tar.gz: c615ef1b9948f1db60d868911f6f169df14425c42ef50e6e2dad8082f8e1fe8666d47626251e0ec3e7e1dc8e2b0e25bb01d233c4c45da8c2935cbf39cf08a21b
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
  gem "ib-api", path: "../ib-api/"
6
6
  ## move this to gemspec and include as development dependency after the gem is released
7
- gem "ib-symbols", path: "../ib-symbols/"
7
+ gem "ib-symbols" #, path: "../ib-symbols/"
8
8
  #gem "ib-api", :git=> 'https://github.com/ib-ruby/ib-api.git'
9
9
  gem "rake", "~> 12.0"
10
+ gem 'dry-core'
data/Gemfile.lock CHANGED
@@ -1,38 +1,34 @@
1
1
  PATH
2
2
  remote: ../ib-api
3
3
  specs:
4
- ib-api (972.0)
4
+ ib-api (972.4)
5
5
  activemodel
6
6
  activesupport (>= 6.0)
7
7
 
8
- PATH
9
- remote: ../ib-symbols
10
- specs:
11
- ib-symbols (1.0)
12
- ib-api
13
- ox
14
-
15
8
  PATH
16
9
  remote: .
17
10
  specs:
18
- ib-extensions (1.0)
11
+ ib-extensions (1.1)
12
+ ib-api (~> 972.4)
19
13
  ox
20
14
 
21
15
  GEM
22
16
  remote: https://rubygems.org/
23
17
  specs:
24
- activemodel (6.0.3.4)
25
- activesupport (= 6.0.3.4)
26
- activesupport (6.0.3.4)
18
+ activemodel (6.1.3.2)
19
+ activesupport (= 6.1.3.2)
20
+ activesupport (6.1.3.2)
27
21
  concurrent-ruby (~> 1.0, >= 1.0.2)
28
- i18n (>= 0.7, < 2)
29
- minitest (~> 5.1)
30
- tzinfo (~> 1.1)
31
- zeitwerk (~> 2.2, >= 2.2.2)
22
+ i18n (>= 1.6, < 2)
23
+ minitest (>= 5.1)
24
+ tzinfo (~> 2.0)
25
+ zeitwerk (~> 2.3)
32
26
  coderay (1.1.3)
33
- concurrent-ruby (1.1.7)
27
+ concurrent-ruby (1.1.8)
34
28
  diff-lcs (1.4.4)
35
- ffi (1.13.1)
29
+ dry-core (0.5.0)
30
+ concurrent-ruby (~> 1.0)
31
+ ffi (1.15.0)
36
32
  formatador (0.2.5)
37
33
  guard (2.16.2)
38
34
  formatador (>= 0.2.4)
@@ -48,20 +44,23 @@ GEM
48
44
  guard (~> 2.1)
49
45
  guard-compat (~> 1.1)
50
46
  rspec (>= 2.99.0, < 4.0)
51
- i18n (1.8.5)
47
+ i18n (1.8.10)
52
48
  concurrent-ruby (~> 1.0)
53
- listen (3.3.1)
49
+ ib-symbols (1.0)
50
+ ib-api
51
+ ox
52
+ listen (3.5.1)
54
53
  rb-fsevent (~> 0.10, >= 0.10.3)
55
54
  rb-inotify (~> 0.9, >= 0.9.10)
56
55
  lumberjack (1.2.8)
57
56
  method_source (1.0.0)
58
- minitest (5.14.2)
57
+ minitest (5.14.4)
59
58
  nenv (0.3.0)
60
59
  notiffany (0.1.3)
61
60
  nenv (~> 0.1)
62
61
  shellany (~> 0.0)
63
- ox (2.13.4)
64
- pry (0.13.1)
62
+ ox (2.14.4)
63
+ pry (0.14.1)
65
64
  coderay (~> 1.1)
66
65
  method_source (~> 1.0)
67
66
  rake (12.3.3)
@@ -74,39 +73,39 @@ GEM
74
73
  rspec-mocks (~> 3.10.0)
75
74
  rspec-collection_matchers (1.2.0)
76
75
  rspec-expectations (>= 2.99.0.beta1)
77
- rspec-core (3.10.0)
76
+ rspec-core (3.10.1)
78
77
  rspec-support (~> 3.10.0)
79
- rspec-expectations (3.10.0)
78
+ rspec-expectations (3.10.1)
80
79
  diff-lcs (>= 1.2.0, < 2.0)
81
80
  rspec-support (~> 3.10.0)
82
81
  rspec-its (1.3.0)
83
82
  rspec-core (>= 3.0.0)
84
83
  rspec-expectations (>= 3.0.0)
85
- rspec-mocks (3.10.0)
84
+ rspec-mocks (3.10.2)
86
85
  diff-lcs (>= 1.2.0, < 2.0)
87
86
  rspec-support (~> 3.10.0)
88
- rspec-support (3.10.0)
87
+ rspec-support (3.10.2)
89
88
  shellany (0.0.1)
90
- thor (1.0.1)
91
- thread_safe (0.3.6)
92
- tzinfo (1.2.8)
93
- thread_safe (~> 0.1)
94
- zeitwerk (2.4.1)
89
+ thor (1.1.0)
90
+ tzinfo (2.0.4)
91
+ concurrent-ruby (~> 1.0)
92
+ zeitwerk (2.4.2)
95
93
 
96
94
  PLATFORMS
97
95
  ruby
98
96
 
99
97
  DEPENDENCIES
100
98
  bundler (~> 2.0)
99
+ dry-core
101
100
  guard
102
101
  guard-rspec
103
102
  ib-api!
104
103
  ib-extensions!
105
- ib-symbols!
104
+ ib-symbols
106
105
  rake (~> 12.0)
107
106
  rspec (~> 3.0)
108
107
  rspec-collection_matchers
109
108
  rspec-its
110
109
 
111
110
  BUNDLED WITH
112
- 2.1.4
111
+ 2.2.3
data/README.md CHANGED
@@ -1,18 +1,23 @@
1
1
  # IB/Extensions
2
2
 
3
- Helpers and Macros that ease the usage of the TWS-API of Interactive Brokers
4
-
5
- **status:** A stable Gem-Release is in preparation.
3
+ ---
6
4
 
7
5
  __Documentation: [https://ib-ruby.github.io/ib-doc/](https://ib-ruby.github.io/ib-doc/)__
8
6
 
9
- to activate use
7
+ __Questions, Contributions, Remarks: [Discussions are opened in ib-api](https://github.com/ib-ruby/ib-api/discussions)__
8
+
9
+ ---
10
+
11
+ __Helpers and Macros that ease the usage of the TWS-API of Interactive Brokers__
12
+
13
+ To activate use
10
14
  ```
11
- gem 'ib-extensions', git: 'https://github.com/ib-ruby/ib-extensions.git'
15
+ gem 'ib-extensions'
12
16
  ```
13
17
  in the Gemfile and require the extensions as needed
14
18
 
15
19
  ## Include all
20
+ (except gateway)
16
21
  ```
17
22
  require 'ib-api'
18
23
  require 'ib/extensions'
@@ -91,9 +96,9 @@ Its used in [Simple Monitor](https://github.com/ib-ruby/simple-monitor)
91
96
 
92
97
  ## Contributing
93
98
 
94
- Bug reports and pull requests are welcome on GitHub at https://github.com/ib-ruby/ib-extensions. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/ib-extensions/blob/master/CODE_OF_CONDUCT.md).
99
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ib-ruby/ib-extensions. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[ib-ruby/ib-extensions/blob/master/CODE_OF_CONDUCT.md).
95
100
 
96
101
 
97
102
  ## Code of Conduct
98
103
 
99
- Everyone interacting in the Ib::Extensions project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/ib-extensions/blob/master/CODE_OF_CONDUCT.md).
104
+ Everyone interacting in the Ib::Extensions project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ib-ruby/ib-extensions/blob/master/CODE_OF_CONDUCT.md).
data/bin/console CHANGED
@@ -48,7 +48,6 @@ read_yml = -> (key) do
48
48
  puts "Namespace is IB ! "
49
49
  puts
50
50
  puts '-'* 45
51
- include LogDev
52
51
  include IB
53
52
  require 'irb'
54
53
  client_id = ARGV[1] || read_yml[:client_id]
@@ -63,16 +62,15 @@ read_yml = -> (key) do
63
62
  end
64
63
 
65
64
  ARGV.clear
66
- logger = default_logger # Logger.new STDOUT
67
65
 
68
66
  ## The Block takes instructions which are executed after initializing all instance-variables
69
67
  ## and prior to the connection-process
70
68
  ## Here we just subscribe to some events
71
69
  C = Connection.new client_id: client_id, port: port do |c| # future use__ , optional_capacities: "+PACEAPI" do |c|
72
70
 
73
- c.subscribe( :ContractData, :BondContractData) { |msg| logger.info { msg.contract.to_human } }
74
- c.subscribe( :Alert, :ContractDataEnd, :ManagedAccounts, :OrderStatus ) {| m| logger.info { m.to_human } }
75
- c.subscribe( :PortfolioValue, :AccountValue, :OrderStatus, :OpenOrderEnd, :ExecutionData ) {| m| logger.info { m.to_human }}
71
+ c.subscribe( :ContractData, :BondContractData) { |msg| c.logger.info { msg.contract.to_human } }
72
+ c.subscribe( :Alert, :ContractDataEnd, :ManagedAccounts, :OrderStatus ) {| m| c.logger.info { m.to_human } }
73
+ c.subscribe( :PortfolioValue, :AccountValue, :OrderStatus, :OpenOrderEnd, :ExecutionData ) {| m| c.logger.info { m.to_human }}
76
74
  # c.subscribe :ManagedAccounts do |msg|
77
75
  # puts "------------------------------- Managed Accounts ----------------------------------"
78
76
  # puts "Detected Accounts: #{msg.accounts.account.join(' -- ')} "
@@ -12,6 +12,7 @@ LogLevel = Logger::DEBUG ##INFO # DEBUG # ERROR
12
12
  #require File.expand_path(File.dirname(__FILE__) + "/../config/boot")
13
13
 
14
14
  require 'ib-gateway'
15
+ require 'ib/verify'
15
16
  require 'ib/market-price'
16
17
  require 'ib/option-chain'
17
18
  require 'ib/eod'
@@ -48,7 +49,6 @@ read_yml = -> (key) do
48
49
  puts
49
50
  puts "Namespace is IB ! "
50
51
  puts
51
- puts '-'* 45
52
52
 
53
53
  include IB
54
54
  require 'irb'
@@ -74,17 +74,21 @@ read_yml = -> (key) do
74
74
  ## and prior to the connection-process
75
75
  ## Here we just subscribe to some events
76
76
  begin
77
- G = Gateway.new get_account_data: true, serial_array: true,
78
- client_id: client_id, port: port, logger: logger,
79
- watchlists: [:Spreads, :BuyAndHold]
77
+ G = Gateway.new get_account_data: true, serial_array: true,
78
+ client_id: client_id, port: port , logger: logger,
79
+ watchlists: [:Spreads, :Stillhalter, :BuyAndHold]
80
80
  rescue IB::TransmissionError => e
81
81
  puts "E: #{e.inspect}"
82
82
  end
83
83
 
84
84
  C = G.tws
85
+
86
+ C.subscribe(:TickGeneric, :TickOption, :TickRequestParameters, :MarketDataType, :TickString, :TickSize ){|x| x }
85
87
  unless C.received[:OpenOrder].blank?
86
88
  puts "------------------------------- OpenOrders ----------------------------------"
87
89
  puts C.received[:OpenOrder].to_human.join "\n"
90
+ puts " ---------------- Open Orders are present in G.clients.orders --------------"
91
+ puts ""
88
92
  end
89
93
  puts "Connection established on Port #{port}, client_id #{client_id} used"
90
94
  puts
@@ -94,4 +98,9 @@ read_yml = -> (key) do
94
98
  puts "some basic Messages are subscribed and accordingly displayed"
95
99
  puts '-'* 45
96
100
 
101
+ begin
97
102
  IRB.start(__FILE__)
103
+ #rescue IB::OrderAttributeError => e
104
+ # puts "OrderAtttribute ERROR"
105
+ end
106
+
data/changelog.md CHANGED
@@ -27,5 +27,11 @@
27
27
  * included specific alert-definitions in this directory:
28
28
  order-alerts, gateway-alerts
29
29
 
30
+ * moving model/spread.rb to `ib-api` Gem
30
31
 
32
+ #### Preparation of a Gem-Release
31
33
 
34
+ * Gateway#connect: initializing order-array by calling :RequestAllOrders after establishing the connection.
35
+
36
+ * Gateway#connect: Occasionally the request for AccountPositions/AllOrders fails. Then a reconnect is
37
+ appropriate. This is now implemented.
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
 
28
28
 
29
29
  spec.add_dependency "ox"
30
+ spec.add_dependency "ib-api", "~> 972.4"
30
31
  spec.add_development_dependency "bundler", "~> 2.0"
31
32
  spec.add_development_dependency "rspec", "~> 3.0"
32
33
  spec.add_development_dependency 'rspec-collection_matchers'
@@ -40,7 +40,6 @@ Important: The class is accessed asynchronically. Be careful while raising inter
40
40
  # acts as prototype for any generated method
41
41
  #require 'active_support'
42
42
 
43
- mattr_accessor :logger
44
43
 
45
44
  def self.method_missing( method_id, msg , *args, &block )
46
45
  if msg.is_a? IB::Messages::Incoming::Alert
@@ -62,6 +61,9 @@ Important: The class is accessed asynchronically. Be careful while raising inter
62
61
 
63
62
 
64
63
  class << self
64
+ def logger
65
+ IB::Connection.logger || IB::Gateway.logger
66
+ end
65
67
 
66
68
  def ignore_alert *codes
67
69
  codes.each do |n|
@@ -1,6 +1,11 @@
1
1
  module IB
2
2
  class Alert
3
3
 
4
+ def self.alert_388 msg
5
+ # Order size x is smaller than the minimum required size of yy.
6
+ IB::Gateway.logger.error msg.inspect
7
+ # error msg, :order, nil
8
+ end
4
9
  def self.alert_202 msg
5
10
  # do anything in a secure mutex-synchronized-environment
6
11
  any_order = IB::Gateway.current.account_data do | account |
data/lib/ib/eod.rb CHANGED
@@ -51,21 +51,21 @@ require 'active_support/core_ext/date/calculations'
51
51
  end
52
52
  end
53
53
  class Contract
54
- # Receive EOD-Data
55
- #
54
+ # Receive EOD-Data
55
+ #
56
56
  # The Enddate has to be specified (as Date Object), t
57
57
  #
58
- # The Duration can either be specified as Sting " yx D" or as Integer.
58
+ # The Duration can either be specified as Sting " yx D" or as Integer.
59
59
  # Altenative a start date can be specified with the :start parameter.
60
60
  #
61
- # The parameter :what specified the kind of received data:
61
+ # The parameter :what specified the kind of received data:
62
62
  # Valid values:
63
63
  # :trades, :midpoint, :bid, :ask, :bid_ask,
64
64
  # :historical_volatility, :option_implied_volatility,
65
65
  # :option_volume, :option_open_interest
66
- #
66
+ #
67
67
  # The results can be preprocessed through a block, thus
68
- #
68
+ #
69
69
  # puts IB::Symbols::Index::stoxx.eod( duration: '10 d')){|r| r.to_human}
70
70
  # <Bar: 2019-04-01 wap 0.0 OHLC 3353.67 3390.98 3353.67 3385.38 trades 1750 vol 0>
71
71
  # <Bar: 2019-04-02 wap 0.0 OHLC 3386.18 3402.77 3382.84 3395.7 trades 1729 vol 0>
@@ -79,24 +79,24 @@ require 'active_support/core_ext/date/calculations'
79
79
  # <Bar: 2019-04-12 wap 0.0 OHLC 3432.16 3454.77 3425.84 3447.83 trades 1715 vol 0>
80
80
  #
81
81
  # «to_human« is not needed here because ist aliased with `to_s`
82
- #
83
- # puts Symbols::Stocks.wfc.eod( start: Date.new(2019,10,9), duration: 3 )
82
+ #
83
+ # puts Symbols::Stocks.wfc.eod( start: Date.new(2019,10,9), duration: 3 )
84
84
  # <Bar: 2020-10-23 wap 23.3675 OHLC 23.55 23.55 23.12 23.28 trades 5778 vol 50096>
85
85
  # <Bar: 2020-10-26 wap 22.7445 OHLC 22.98 22.99 22.6 22.7 trades 6873 vol 79560>
86
86
  # <Bar: 2020-10-27 wap 22.086 OHLC 22.55 22.58 21.82 21.82 trades 7503 vol 97691>
87
87
 
88
- # puts Symbols::Stocks.wfc.eod( to: Date.new(2019,10,9), duration: 3 )
88
+ # puts Symbols::Stocks.wfc.eod( to: Date.new(2019,10,9), duration: 3 )
89
89
  # <Bar: 2019-10-04 wap 48.964 OHLC 48.61 49.25 48.54 49.21 trades 9899 vol 50561>
90
90
  # <Bar: 2019-10-07 wap 48.9445 OHLC 48.91 49.29 48.75 48.81 trades 10317 vol 50189>
91
91
  # <Bar: 2019-10-08 wap 47.9165 OHLC 48.25 48.34 47.55 47.82 trades 12607 vol 53577>
92
92
  #
93
- def eod start:nil, to: Date.today, duration: nil , what: :trades
93
+ def eod start:nil, to: Date.today, duration: nil , what: :trades
94
94
 
95
95
  tws = IB::Connection.current
96
96
  recieved = Queue.new
97
97
  r = nil
98
- # the hole response is transmitted at once!
99
- a= tws.subscribe(IB::Messages::Incoming::HistoricalData) do |msg|
98
+ # the hole response is transmitted at once!
99
+ a = tws.subscribe(IB::Messages::Incoming::HistoricalData) do |msg|
100
100
  if msg.request_id == con_id
101
101
  # msg.results.each { |entry| puts " #{entry}" }
102
102
  r = block_given? ? msg.results.map{|y| yield y} : msg.results
@@ -108,11 +108,10 @@ require 'active_support/core_ext/date/calculations'
108
108
  tws.logger.info msg.message
109
109
  # TWS Error 200: No security definition has been found for the request
110
110
  # TWS Error 354: Requested market data is not subscribed.
111
- # TWS Error 162 # Historical Market Data Service error
112
- recieved =[]
111
+ # TWS Error 162 # Historical Market Data Service error
112
+ recieved.close
113
113
  end
114
114
  end
115
-
116
115
 
117
116
  duration = if duration.present?
118
117
  duration.is_a?(String) ? duration : duration.to_s + " D"
@@ -133,19 +132,16 @@ require 'active_support/core_ext/date/calculations'
133
132
  :format_date => 2,
134
133
  :keep_up_todate => 0)
135
134
 
136
- Timeout::timeout(50) do # max 5 sec.
137
- sleep 0.1
138
- last_time = recieved.pop # blocks until a message is ready on the queue
139
- loop do
140
- sleep 0.1
141
- break if recieved.empty? # finish if no more data received
142
- end
135
+ Timeout::timeout(5) do # max 5 sec.
136
+ sleep 0.1
137
+ recieved.pop # blocks until a message is ready on the queue
138
+ break if recieved.closed? || recieved.empty? # finish if data received
139
+ end
143
140
  tws.unsubscribe a
144
141
  tws.unsubscribe b
145
142
 
146
143
  r # the collected result
147
144
 
148
- end
149
145
  end # def
150
146
  end # class
151
147
  end # module
data/lib/ib/extensions.rb CHANGED
@@ -7,3 +7,4 @@ require "ib/option-chain"
7
7
  require "ib/option-greeks"
8
8
  require "ib/order-prototypes"
9
9
  require "ib/spread-prototypes"
10
+ require "ib/models/option"
@@ -1,5 +1,5 @@
1
1
  module IB
2
2
  module Extensions
3
- VERSION = "1.0"
3
+ VERSION = "1.1"
4
4
  end
5
5
  end
data/lib/ib/gateway.rb CHANGED
@@ -75,47 +75,46 @@ IB::Gateway.new serial_array: true (, ...)
75
75
 
76
76
  =end
77
77
 
78
- class Gateway
78
+ class Gateway
79
79
 
80
- include LogDev # provides default_logger
81
- include AccountInfos # provides Handling of Account-Data provided by the tws
82
- include OrderHandling
80
+ include Support::Logging # provides default_logger
81
+ include AccountInfos # provides Handling of Account-Data provided by the tws
82
+ include OrderHandling
83
83
 
84
- # include GWSupport # introduces update_or_create, first_or_create and intercept to the Array-Class
84
+ # include GWSupport # introduces update_or_create, first_or_create and intercept to the Array-Class
85
85
 
86
- # from active-support. Add Logging at Class + Instance-Level
87
- mattr_accessor :logger
88
- # similar to the Connection-Class: current represents the active instance of Gateway
89
- mattr_accessor :current
90
- mattr_accessor :tws
86
+ # from active-support. Add Logging at Class + Instance-Level
87
+ # similar to the Connection-Class: current represents the active instance of Gateway
88
+ mattr_accessor :current
89
+ mattr_accessor :tws
91
90
 
92
91
 
93
92
 
94
- def initialize port: 4002, # 7497,
93
+ def initialize port: 4002, # 7497,
95
94
  host: '127.0.0.1', # 'localhost:4001' is also accepted
96
95
  client_id: random_id,
97
- subscribe_managed_accounts: true,
98
- subscribe_alerts: true,
99
- subscribe_order_messages: true,
100
- connect: true,
96
+ subscribe_managed_accounts: true,
97
+ subscribe_alerts: true,
98
+ subscribe_order_messages: true,
99
+ connect: true,
101
100
  get_account_data: false,
102
- serial_array: false,
103
- logger: default_logger,
101
+ serial_array: false,
102
+ logger: nil,
104
103
  watchlists: [] , # array of watchlists (IB::Symbols::{watchlist}) containing descriptions for complex positions
105
104
  **other_agruments_which_are_ignored,
106
105
  &b
107
106
 
108
- host, port = (host+':'+port.to_s).split(':')
107
+ host, port = (host+':'+port.to_s).split(':')
109
108
 
110
- self.logger = logger
111
- logger.info { '-' * 20 +' initialize ' + '-' * 20 }
112
- logger.tap{|l| l.progname = 'Gateway#Initialize' }
109
+ self.class.configure_logger logger
110
+
111
+ self.logger.info { '-' * 20 +' initialize ' + '-' * 20 }
113
112
 
114
113
  @connection_parameter = { received: serial_array, port: port, host: host, connect: false, logger: logger, client_id: client_id }
115
114
 
116
115
  @account_lock = Mutex.new
117
116
  @watchlists = watchlists
118
- @gateway_parameter = { s_m_a: subscribe_managed_accounts,
117
+ @gateway_parameter = { s_m_a: subscribe_managed_accounts,
119
118
  s_a: subscribe_alerts,
120
119
  s_o_m: subscribe_order_messages,
121
120
  g_a_d: get_account_data }
@@ -124,18 +123,31 @@ IB::Gateway.new serial_array: true (, ...)
124
123
  Thread.report_on_exception = true
125
124
  # https://blog.bigbinary.com/2018/04/18/ruby-2-5-enables-thread-report_on_exception-by-default.html
126
125
  Gateway.current = self
127
- # establish Alert-framework
128
- IB::Alert.logger = logger
129
126
  # initialise Connection without connecting
130
127
  prepare_connection &b
131
128
  # finally connect to the tws
132
129
  connect = true if get_account_data
133
- if connect
134
- if connect(100) # tries to connect for about 2h
135
- get_account_data(watchlists: watchlists.map{|b| IB::Symbols.allocate_collection b}) if get_account_data
136
- # request_open_orders() if request_open_orders || get_account_data
137
- else
138
- @accounts = [] # definitivley reset @accounts
130
+
131
+ if connect
132
+ i = 0
133
+ begin
134
+ i+=1
135
+ if connect(100) # tries to connect for about 2h
136
+ get_account_data(watchlists: watchlists.map{|b| IB::Symbols.allocate_collection b}) if get_account_data
137
+ # request_open_orders() if request_open_orders || get_account_data
138
+ else
139
+ @accounts = [] # definitivley reset @accounts
140
+ end
141
+ rescue IB::Error => e
142
+ disconnect
143
+ logger.fatal e.message
144
+ if e.message =~ /NextLocalId is not initialized/
145
+ Kernel.exit
146
+ elsif i < 5
147
+ retry
148
+ else
149
+ raise "could not get account data"
150
+ end
139
151
  end
140
152
  end
141
153
 
@@ -157,9 +169,9 @@ IB::Gateway.new serial_array: true (, ...)
157
169
 
158
170
  ## ------------------------------------- connect ---------------------------------------------##
159
171
  =begin
160
- Zentrale Methode
172
+ Zentrale Methode
161
173
  Es wird ein Connection-Objekt (IB::Connection.current) angelegt.
162
- Sollte keine TWS vorhanden sein, wird eine entsprechende Meldung ausgegeben und der Verbindungsversuch
174
+ Sollte keine TWS vorhanden sein, wird ein entsprechende Meldung ausgegeben und der Verbindungsversuch
163
175
  wiederholt.
164
176
  Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.
165
177
 
@@ -167,7 +179,6 @@ Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.
167
179
  def connect maximal_count_of_retry=100
168
180
 
169
181
  i= -1
170
- logger.progname = 'Gateway#connect'
171
182
  begin
172
183
  tws.connect
173
184
  rescue Errno::ECONNREFUSED => e
@@ -203,8 +214,10 @@ Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.
203
214
  end
204
215
  end
205
216
  # initialize @accounts (incl. aliases)
206
- tws.send_message :RequestFA, fa_data_type: 3
217
+ tws.send_message( :RequestFA, fa_data_type: 3) if fa?
207
218
  logger.debug { "Communications successfully established" }
219
+ # update open orders
220
+ request_open_orders if @gateway_parameter[:s_o_m] || @gateway_parameter[:g_a_d]
208
221
  end # def
209
222
 
210
223
 
@@ -212,7 +225,6 @@ Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.
212
225
 
213
226
 
214
227
  def reconnect
215
- logger.progname = 'Gateway#reconnect'
216
228
  if tws.present?
217
229
  disconnect
218
230
  sleep 1
@@ -222,11 +234,10 @@ Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.
222
234
  end
223
235
 
224
236
  def disconnect
225
- logger.progname = 'Gateway#disconnect'
226
237
 
227
238
  tws.disconnect if tws.present?
228
239
  @accounts = [] # each{|y| y.update_attribute :connected, false }
229
- logger.info "Connection closed"
240
+ logger.info "Connection closed"
230
241
  end
231
242
 
232
243
 
@@ -239,7 +250,6 @@ checks the connection before sending a message.
239
250
  =end
240
251
 
241
252
  def send_message what, *args
242
- logger.tap{|l| l.progname = 'Gateway#SendMessage' }
243
253
  begin
244
254
  if check_connection
245
255
  tws.send_message what, *args
@@ -256,9 +266,8 @@ Argument is either an order-object or a local_id
256
266
 
257
267
  =end
258
268
 
259
- def cancel_order *orders
269
+ def cancel_order *orders
260
270
 
261
- logger.tap{|l| l.progname = 'Gateway#CancelOrder' }
262
271
 
263
272
  orders.compact.each do |o|
264
273
  local_id = if o.is_a? (IB::Order)
@@ -273,14 +282,21 @@ Argument is either an order-object or a local_id
273
282
  end
274
283
 
275
284
  =begin
276
- clients returns a list of Account-Objects
285
+ clients returns a list of Account-Objects
277
286
 
278
287
  If only one Account is present, Client and Advisor are identical.
279
288
 
280
289
  =end
281
290
  def clients
282
- @accounts.find_all &:user?
291
+ @accounts.find_all &:user?
283
292
  end
293
+
294
+ # is the account a financial advisor
295
+ def fa?
296
+ !(advisor == clients.first)
297
+ end
298
+
299
+
284
300
  =begin
285
301
  The Advisor is always the first account
286
302
  =end
@@ -311,44 +327,38 @@ If called without a parameter, all clients are accessed
311
327
  sa = account_or_id.is_a?(IB::Account) ? account_or_id : @accounts.detect{|x| x.account == account_or_id }
312
328
  safe[sa] if sa.is_a? IB::Account
313
329
  else
314
- clients.map{|sa| safe[sa]}
330
+ clients.map{|s| safe[s]}
315
331
  end
316
332
  end
317
333
  end
318
334
 
319
335
 
320
- private
321
-
322
- def random_id
323
- rand 99999
324
- end
325
-
326
336
 
327
337
 
328
338
  def prepare_connection &b
329
339
  tws.disconnect if tws.is_a? IB::Connection
330
- self.tws = IB::Connection.new @connection_parameter
340
+ self.tws = IB::Connection.new **@connection_parameter.merge( logger: self.logger )
331
341
  @accounts = @local_orders = Array.new
332
342
 
333
343
  # prepare Advisor-User hierachy
334
344
  initialize_managed_accounts if @gateway_parameter[:s_m_a]
335
345
  initialize_alerts if @gateway_parameter[:s_a]
336
- initialize_order_handling if @gateway_parameter[:s_o_m] || @gateway_parameter[:g_a_d]
346
+ initialize_order_handling if @gateway_parameter[:s_o_m] || @gateway_parameter[:g_a_d]
337
347
  ## apply other initialisations which should apper before the connection as block
338
348
  ## i.e. after connection order-state events are fired if an open-order is pending
339
349
  ## a possible response is best defined before the connect-attempt is done
340
350
  # ## Attention
341
351
  # ## @accounts are not initialized yet (empty array)
342
- if block_given?
352
+ if block_given?
343
353
  yield self
344
354
 
345
355
  end
346
356
  end
347
357
 
348
358
  =begin
349
- InitializeManagedAccounts
359
+ InitializeManagedAccounts
350
360
  defines the Message-Handler for :ManagedAccounts
351
- Its always active.
361
+ Its always active.
352
362
  =end
353
363
 
354
364
  def initialize_managed_accounts
@@ -360,7 +370,6 @@ Its always active.
360
370
  end
361
371
 
362
372
  man_id = tws.subscribe( :ManagedAccounts ) do |msg|
363
- logger.progname = 'Gateway#InitializeManagedAccounts'
364
373
  if @accounts.empty?
365
374
  # just validate the message and put all together into an array
366
375
  @accounts = msg.accounts_list.split(',').map do |a|
@@ -377,8 +386,7 @@ Its always active.
377
386
  def initialize_alerts
378
387
 
379
388
  tws.subscribe( :AccountUpdateTime ){| msg | logger.debug{ msg.to_human }}
380
- tws.subscribe(:Alert) do |msg|
381
- logger.progname = 'Gateway#Alerts'
389
+ tws.subscribe(:Alert) do |msg|
382
390
  logger.debug " ----------------#{msg.code}-----"
383
391
  # delegate anything to IB::Alert
384
392
  IB::Alert.send("alert_#{msg.code}", msg )
@@ -388,16 +396,16 @@ Its always active.
388
396
 
389
397
  # Handy method to ensure that a connection is established and active.
390
398
  #
391
- # The connection is reset on the IB-side at least once a day. Then the
392
- # IB-Ruby-Connection has to be reestablished, too.
393
- #
394
- # check_connection reconnects if necessary and returns false if the connection is lost.
395
- #
399
+ # The connection is reset on the IB-side at least once a day. Then the
400
+ # IB-Ruby-Connection has to be reestablished, too.
401
+ #
402
+ # check_connection reconnects if necessary and returns false if the connection is lost.
403
+ #
396
404
  # It delays the process by 6 ms (150 MBit Cable connection)
397
405
  #
398
406
  # a = Time.now; G.check_connection; b= Time.now ;b-a
399
407
  # => 0.00066005
400
- #
408
+ #
401
409
  def check_connection
402
410
  answer = nil; count=0
403
411
  z= tws.subscribe( :CurrentTime ) { answer = true }
@@ -419,6 +427,12 @@ Its always active.
419
427
  tws.unsubscribe z
420
428
  count < 5 && answer # return value
421
429
  end
430
+ private
431
+
432
+ def random_id
433
+ rand 99999
434
+ end
435
+
422
436
  end # class
423
437
 
424
438
  end # module