ib-ruby 0.5.16 → 0.5.17
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/VERSION +1 -1
- data/lib/ib-ruby/connection.rb +11 -7
- data/lib/ib-ruby/messages/incoming.rb +31 -27
- data/lib/ib-ruby/models/order.rb +1 -1
- data/spec/spec_helper.rb +4 -1
- metadata +2 -2
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.17
|
data/lib/ib-ruby/connection.rb
CHANGED
@@ -19,7 +19,7 @@ module IB
|
|
19
19
|
|
20
20
|
CLIENT_VERSION = 48 # Was 27 in original Ruby code
|
21
21
|
SERVER_VERSION = 53 # Minimal server version. Latest, was 38 in current Java code.
|
22
|
-
DEFAULT_OPTIONS = {:host =>
|
22
|
+
DEFAULT_OPTIONS = {:host =>'127.0.0.1',
|
23
23
|
:port => '4001', # IB Gateway connection (default)
|
24
24
|
#:port => '7496', # TWS connection, with annoying pop-ups
|
25
25
|
:client_id => nil, # Will be randomly assigned
|
@@ -45,7 +45,6 @@ module IB
|
|
45
45
|
@server = Hash.new
|
46
46
|
|
47
47
|
connect if @options[:connect]
|
48
|
-
start_reader if @options[:reader]
|
49
48
|
Connection.current = self
|
50
49
|
end
|
51
50
|
|
@@ -58,7 +57,7 @@ module IB
|
|
58
57
|
end
|
59
58
|
|
60
59
|
def connect
|
61
|
-
raise
|
60
|
+
raise "Already connected!" if connected?
|
62
61
|
|
63
62
|
# TWS always sends NextValidID message at connect - save this id
|
64
63
|
self.subscribe(:NextValidID) do |msg|
|
@@ -71,7 +70,7 @@ module IB
|
|
71
70
|
# Secret handshake
|
72
71
|
@server[:socket].send(CLIENT_VERSION)
|
73
72
|
@server[:version] = @server[:socket].read_int
|
74
|
-
raise
|
73
|
+
raise "TWS version >= #{SERVER_VERSION} required." if @server[:version] < SERVER_VERSION
|
75
74
|
|
76
75
|
@server[:local_connect_time] = Time.now()
|
77
76
|
@server[:remote_connect_time] = @server[:socket].read_string
|
@@ -86,6 +85,8 @@ module IB
|
|
86
85
|
log.info "Connected to server, version: #{@server[:version]}, connection time: " +
|
87
86
|
"#{@server[:local_connect_time]} local, " +
|
88
87
|
"#{@server[:remote_connect_time]} remote."
|
88
|
+
|
89
|
+
start_reader if @options[:reader] # Allows reconnect
|
89
90
|
end
|
90
91
|
|
91
92
|
alias open connect # Legacy alias
|
@@ -95,9 +96,11 @@ module IB
|
|
95
96
|
@reader_running = false
|
96
97
|
@server[:reader].join
|
97
98
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
if connected?
|
100
|
+
@server[:socket].close
|
101
|
+
@server = Hash.new
|
102
|
+
@connected = false
|
103
|
+
end
|
101
104
|
end
|
102
105
|
|
103
106
|
alias close disconnect # Legacy alias
|
@@ -152,6 +155,7 @@ module IB
|
|
152
155
|
else
|
153
156
|
raise ArgumentError.new "Only able to send outgoing IB messages"
|
154
157
|
end
|
158
|
+
raise "Not able to send messages, IB not connected!" unless connected?
|
155
159
|
message.send_to(@server)
|
156
160
|
end
|
157
161
|
|
@@ -55,8 +55,14 @@ module IB
|
|
55
55
|
@data.has_key?(:id) ? @data[:id] : super
|
56
56
|
end
|
57
57
|
|
58
|
+
def respond_to? method
|
59
|
+
getter = method.to_s.sub(/=$/, '').to_sym
|
60
|
+
@data.has_key?(method) || @data.has_key?(getter) || super
|
61
|
+
end
|
62
|
+
|
58
63
|
protected
|
59
64
|
|
65
|
+
# TODO: method compilation instead of method_missing
|
60
66
|
def method_missing method, *args
|
61
67
|
getter = method.to_s.sub(/=$/, '').to_sym
|
62
68
|
if @data.has_key? method
|
@@ -68,11 +74,6 @@ module IB
|
|
68
74
|
end
|
69
75
|
end
|
70
76
|
|
71
|
-
def respond_to? method
|
72
|
-
getter = method.to_s.sub(/=$/, '').to_sym
|
73
|
-
@data.has_key?(method) || @data.has_key?(getter) || super
|
74
|
-
end
|
75
|
-
|
76
77
|
# Every message loads received message version first
|
77
78
|
def load
|
78
79
|
@data[:version] = @socket.read_int
|
@@ -156,11 +157,11 @@ module IB
|
|
156
157
|
[:last_fill_price, :decimal],
|
157
158
|
[:client_id, :int],
|
158
159
|
[:why_held, :string] do
|
159
|
-
"<OrderStatus: #{
|
160
|
-
" @ last/avg: #{
|
161
|
-
(
|
162
|
-
(
|
163
|
-
" id/perm: #{
|
160
|
+
"<OrderStatus: #{status} filled: #{filled}/#{remaining + filled}" +
|
161
|
+
" @ last/avg: #{last_fill_price}/#{average_fill_price}" +
|
162
|
+
(parent_id > 0 ? "parent_id: #{parent_id}" : "") +
|
163
|
+
(why_held != "" ? "why_held: #{why_held}" : "") +
|
164
|
+
" id/perm: #{id}/#{perm_id}>"
|
164
165
|
end
|
165
166
|
|
166
167
|
|
@@ -168,17 +169,17 @@ module IB
|
|
168
169
|
[:value, :string],
|
169
170
|
[:currency, :string],
|
170
171
|
[:account_name, :string]) do
|
171
|
-
"<AccountValue: #{
|
172
|
+
"<AccountValue: #{account_name}, #{key}=#{value} #{currency}>"
|
172
173
|
end
|
173
174
|
|
174
175
|
AccountUpdateTime = def_message(8, [:time_stamp, :string]) do
|
175
|
-
"<AccountUpdateTime: #{
|
176
|
+
"<AccountUpdateTime: #{time_stamp}>"
|
176
177
|
end
|
177
178
|
|
178
179
|
# This message is always sent by TWS automatically at connect.
|
179
180
|
# The IB::Connection class subscribes to it automatically and stores
|
180
181
|
# the order id in its @next_order_id attribute.
|
181
|
-
NextValidID = def_message(9, [:id, :int]) { "<NextValidID: #{
|
182
|
+
NextValidID = def_message(9, [:id, :int]) { "<NextValidID: #{id}>" }
|
182
183
|
|
183
184
|
NewsBulletins =
|
184
185
|
def_message 14, [:id, :int], # unique incrementing bulletin ID.
|
@@ -214,18 +215,18 @@ module IB
|
|
214
215
|
FundamentalData = def_message 50, [:id, :int], # request_id
|
215
216
|
[:data, :string]
|
216
217
|
|
217
|
-
ContractDataEnd = def_message(52, [:id, :int]) { "<ContractDataEnd: #{
|
218
|
+
ContractDataEnd = def_message(52, [:id, :int]) { "<ContractDataEnd: #{id}>" } # request_id
|
218
219
|
|
219
220
|
OpenOrderEnd = def_message(53) { "<OpenOrderEnd>" }
|
220
221
|
|
221
222
|
AccountDownloadEnd = def_message(54, [:account_name, :string]) do
|
222
|
-
"<AccountDownloadEnd: #{
|
223
|
+
"<AccountDownloadEnd: #{account_name}}>"
|
223
224
|
end # request_id
|
224
225
|
|
225
226
|
|
226
|
-
ExecutionDataEnd = def_message
|
227
|
+
ExecutionDataEnd = def_message(55, [:id, :int]) { "<ExecutionDataEnd: #{id}>" } # request_id
|
227
228
|
|
228
|
-
TickSnapshotEnd = def_message
|
229
|
+
TickSnapshotEnd = def_message(57, [:id, :int]) { "<TickSnapshotEnd: #{id}>" } # request_id
|
229
230
|
|
230
231
|
### Actual message classes (long definitions):
|
231
232
|
|
@@ -344,10 +345,9 @@ module IB
|
|
344
345
|
end
|
345
346
|
|
346
347
|
def to_human
|
347
|
-
"<TickOption #{type} for #{
|
348
|
-
"option @ #{
|
349
|
-
"
|
350
|
-
"theta #{@data[:theta]}, pv_dividend #{@data[:pv_dividend]}>"
|
348
|
+
"<TickOption #{type} for #{:id}: underlying @ #{under_price}, "+
|
349
|
+
"option @ #{option_price}, IV #{implied_volatility}%, delta #{delta}, " +
|
350
|
+
"gamma #{gamma}, vega #{vega}, theta #{theta}, pv_dividend #{pv_dividend}>"
|
351
351
|
end
|
352
352
|
end # TickOption
|
353
353
|
TickOptionComputation = TickOption
|
@@ -373,8 +373,8 @@ module IB
|
|
373
373
|
end
|
374
374
|
|
375
375
|
def to_human
|
376
|
-
"<#{self.class.to_s.split(
|
377
|
-
"#{
|
376
|
+
"<#{self.class.to_s.split(/::/).last}: #{operation} #{side} @ "+
|
377
|
+
"#{position} = #{price} x #{size}>"
|
378
378
|
end
|
379
379
|
end
|
380
380
|
|
@@ -415,13 +415,14 @@ module IB
|
|
415
415
|
"TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'
|
416
416
|
} Message #{code}: #{message}"
|
417
417
|
end
|
418
|
-
end # class
|
418
|
+
end # class Alert
|
419
419
|
Error = Alert
|
420
420
|
ErrorMessage = Alert
|
421
421
|
|
422
422
|
class OpenOrder < AbstractMessage
|
423
423
|
@message_id = 5
|
424
424
|
|
425
|
+
# TODO: Add id accessor to unify with OrderStatus message
|
425
426
|
attr_accessor :order, :contract
|
426
427
|
|
427
428
|
def load
|
@@ -657,6 +658,10 @@ module IB
|
|
657
658
|
:cumulative_quantity => @socket.read_int,
|
658
659
|
:average_price => @socket.read_decimal
|
659
660
|
end
|
661
|
+
|
662
|
+
def to_human
|
663
|
+
"<HistoricalData: req: #{id}, #{item_count} items, #{start_date} to #{end_date}>"
|
664
|
+
end
|
660
665
|
end # ExecutionData
|
661
666
|
|
662
667
|
# HistoricalData contains following @data:
|
@@ -702,8 +707,7 @@ module IB
|
|
702
707
|
end
|
703
708
|
|
704
709
|
def to_human
|
705
|
-
"<HistoricalData: req id #{
|
706
|
-
} items, from #{@data[:start_date_str]} to #{@data[:end_date_str]}>"
|
710
|
+
"<HistoricalData: req: #{id}, #{item_count} items, #{start_date} to #{end_date}>"
|
707
711
|
end
|
708
712
|
end # HistoricalData
|
709
713
|
|
@@ -818,7 +822,7 @@ module IB
|
|
818
822
|
end
|
819
823
|
|
820
824
|
def to_human
|
821
|
-
"<RealTimeBar: req
|
825
|
+
"<RealTimeBar: req: #{id}, #{bar}>"
|
822
826
|
end
|
823
827
|
end # RealTimeBar
|
824
828
|
RealTimeBars = RealTimeBar
|
data/lib/ib-ruby/models/order.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ib-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.5.
|
5
|
+
version: 0.5.17
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paul Legato
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2012-02-
|
14
|
+
date: 2012-02-12 00:00:00 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|