Class: IB::OrientGateway

Inherits:
Object
  • Object
show all
Includes:
AccountInfos, LogDev
Defined in:
lib/ib/orient-gateway.rb

Overview

The Gateway-Class defines anything which has to be done before a connection can be established. The Default Skeleton can easily be substituted by customized actions

The IB::Gateway can be used in three modes (1) IB::Gateway.new( connect:true, –other arguments– ) do | gateway | ** subscribe to Messages and define the response ** # This block is executed before a connect-attempt is made end (2) gw = IB:Gateway.new ** subscribe to Messages ** gw.connect (3) IB::Gateway.new connect:true, host: ‘localhost’ .…

Independently IB::Alert.alert_#nnn should be defined for a proper response to warnings, error- and system-messages.

The Connection to the TWS is realized throught IB::Connection. Additional to IB::Connection.current IB::Gateway.tws points to the active Connection.

To support asynchronic access, the :recieved-Array of the Connection-Class is not active. The Array is easily confused, if used in production mode with a FA-Account and has limits. Thus IB::Conncetion.wait_for(message) is not available until the programm is called with IB::Gateway.new serial_array: true (, …)

Instance Method Summary collapse

Methods included from AccountInfos

#load_managed_accounts

Constructor Details

#initialize(port: 4002, host: '127.0.0.1', client_id: random_id, subscribe_managed_accounts: true, subscribe_alerts: true, subscribe_order_messages: true, connect: true, get_account_data: false, serial_array: false, logger: default_logger, watchlists: [], **other_agruments_which_are_ignored, &b) ⇒ OrientGateway

7497,



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/ib/orient-gateway.rb', line 60

def initialize  port: 4002, # 7497, 
	host: '127.0.0.1',   # 'localhost:4001' is also accepted
	client_id:  random_id,
	subscribe_managed_accounts: true, 
	subscribe_alerts: true, 
	subscribe_order_messages: true, 
	connect: true, 
	get_account_data: false,
	serial_array: false, 
	logger: default_logger,
	watchlists: [] ,  # array of watchlists (IB::Symbols::{watchlist}) containing descriptions for complex positions
	**other_agruments_which_are_ignored,
	&b

	host, port = (host+':'+port.to_s).split(':') 

	self.logger = logger
	logger.info { '-' * 20 +' initialize ' + '-' * 20 }
	logger.tap{|l| l.progname =  'Gateway#Initialize' }

	@connection_parameter = { received: serial_array, port: port, host: host, connect: false, logger: logger, client_id: client_id }

	@accounts = []
	@watchlists = watchlists
	@gateway_parameter = { s_m_a: subscribe_managed_accounts, 
											s_a: subscribe_alerts,
											s_o_m: subscribe_order_messages,
											g_a_d:  }


	Thread.report_on_exception = true
	# https://blog.bigbinary.com/2018/04/18/ruby-2-5-enables-thread-report_on_exception-by-default.html
	self.current = self
	# establish Alert-framework
	#IB::Alert.logger = logger
	# initialise Connection without connecting
	prepare_connection &b
	# finally connect to the tws
	connect =  true if 
	if connect 
		if connect(100)  # tries to connect for about 2h
			()  if 
			#    request_open_orders() if request_open_orders || get_account_data 
		else
			@accounts = []   # definitivley reset @accounts
		end
	end

end

Instance Method Details

#account_data(account_or_id = nil) ⇒ Object

account_data provides a thread-safe access to linked content of accounts

(AccountValues, Portfolio-Values, Contracts and Orders)

It returns an Array of the return-values of the block

If called without a parameter, all clients are accessed



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/ib/orient-gateway.rb', line 267

def  =nil

	safe = ->() do
		@account_lock.synchronize do
			yield  
		end
	end

	if block_given?
		if .present?
			sa = .is_a?(IB::Account) ?  :  @accounts.detect{|x| x. ==  }
			safe[sa] if sa.is_a? IB::Account
		else
			clients.map{|sa| safe[sa]}
		end
	end
end

#active_watchlistsObject



110
111
112
# File 'lib/ib/orient-gateway.rb', line 110

def active_watchlists
	@watchlists
end

#advisorObject

The Advisor is always the first account. Anything works with single user accounts as well.



253
254
255
# File 'lib/ib/orient-gateway.rb', line 253

def advisor
	@accounts.first
end

#cancel_order(*orders) ⇒ Object

Cancels one or multible orders

Argument is either an order-object or a local_id



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/ib/orient-gateway.rb', line 225

def cancel_order *orders 

	logger.tap{|l| l.progname =  'Gateway#CancelOrder' }

	orders.compact.each do |o|
		local_id = if o.is_a? (IB::Order)
								 logger.info{ "Cancelling #{o.to_human}" }
								 o.local_id
							 else
								 o
							 end
		send_message :CancelOrder, :local_id => local_id.to_i
	end

end

#clientsObject

clients returns a list of Account-Objects

If only one Account is present, Client and Advisor are identical.



247
248
249
# File 'lib/ib/orient-gateway.rb', line 247

def  clients
	@accounts.find_all{ |x| x.is_a? IB::User }   # IB::User and IB::DemoUser 
end

#connect(maximal_count_of_retry = 100) ⇒ Object

Zentrale Methode Es wird ein Connection-Objekt (IB::Connection.current) angelegt. Sollte keine TWS vorhanden sein, wird eine entsprechende Meldung ausgegeben und der Verbindungsversuch wiederholt. Weiterhin meldet sich die Anwendung zur Auswertung von Messages der TWS an.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/ib/orient-gateway.rb', line 133

def connect maximal_count_of_retry=100

	i= -1
	logger.progname =  'Gateway#connect' 
	begin
		tws.connect
	rescue  Errno::ECONNREFUSED => e
		i+=1
		if i < maximal_count_of_retry
			if i.zero?
				logger.info 'No TWS!'
			else
				logger.info {"No TWS        Retry #{i}/ #{maximal_count_of_retry} " }
			end
			sleep i<50 ? 10 : 60   # Die ersten 50 Versuche im 10 Sekunden Abstand, danach 1 Min.
			retry
		else
			logger.info { "Giving up!!" }
			return false
		end
	rescue Errno::EHOSTUNREACH => e
		logger.error 'Cannot connect to specified host'
		logger.error  e
		return false
	rescue SocketError => e
		logger.error 'Wrong Adress, connection not possible'
		return false
	end

	tws.start_reader
	# let NextValidId-Event appear
	(1..30).each do |r|
		break if tws.next_local_id.present?
		sleep 0.1
		if r == 30
			error "Connected, NextLocalId is not initialized. Repeat with another client_id"
		end
	end
	# initialize @accounts (incl. aliases)
	tws.send_message :RequestFA, fa_data_type: 3
	logger.debug { "Communications successfully established" }
end

#disconnectObject



190
191
192
193
194
195
196
# File 'lib/ib/orient-gateway.rb', line 190

def disconnect
	logger.progname = 'Gateway#disconnect'

	tws.disconnect if tws.present?
	@accounts = [] # each{|y| y.update_attribute :connected,  false }
	logger.info "Connection closed" 
end

#get_hostObject



114
115
116
# File 'lib/ib/orient-gateway.rb', line 114

def get_host
	"#{@connection_parameter[:host]}: #{@connection_parameter[:port] }"
end

#reconnectObject



180
181
182
183
184
185
186
187
188
# File 'lib/ib/orient-gateway.rb', line 180

def reconnect
	logger.progname = 'Gateway#reconnect'
	if tws.present?
		disconnect
		sleep 1
	end
	logger.info "trying to reconnect ..."
	connect
end

#send_message(what, *args) ⇒ Object

Proxy for Connection#SendMessage allows reconnection if a socket_error occurs

checks the connection before sending a message.



207
208
209
210
211
212
213
214
215
216
# File 'lib/ib/orient-gateway.rb', line 207

def send_message what, *args
	logger.tap{|l| l.progname =  'Gateway#SendMessage' }
	begin
		if	check_connection
			tws.send_message what, *args
		else
			error( "Connection lost. Could not send message  #{what}" )
		end
	end
end

#update_local_order(order) ⇒ Object



118
119
120
121
# File 'lib/ib/orient-gateway.rb', line 118

def update_local_order order
	# @local_orders is initialized by #PrepareConnection
	@local_orders.update_or_create order, :local_id
end