ib-ruby 0.5.7 → 0.5.9
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +8 -0
- data/VERSION +1 -1
- data/bin/global_cancel +26 -0
- data/bin/place_order +34 -0
- data/lib/ib-ruby/connection.rb +19 -7
- data/lib/ib-ruby/messages/incoming.rb +4 -3
- data/lib/ib-ruby/messages/outgoing.rb +18 -7
- data/lib/ib-ruby/models/combo_leg.rb +1 -1
- data/lib/ib-ruby/models/contract.rb +1 -1
- data/lib/ib-ruby/models/order.rb +9 -1
- metadata +5 -1
data/HISTORY
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.9
|
data/bin/global_cancel
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This script allows you to cancel ALL Orders opened via IB API at once.
|
4
|
+
# Useful if your robot goes crazy and opens gazillions of wrong limit orders.
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
|
8
|
+
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'bundler/setup'
|
12
|
+
require 'ib-ruby'
|
13
|
+
|
14
|
+
# First, connect to IB TWS.
|
15
|
+
ib = IB::Connection.new
|
16
|
+
|
17
|
+
# Subscribe to TWS alerts/errors and account-related messages
|
18
|
+
# that TWS sends in response to account data request
|
19
|
+
ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
|
20
|
+
|
21
|
+
ib.send_message :RequestGlobalCancel
|
22
|
+
|
23
|
+
ib.send_message :RequestAllOpenOrders
|
24
|
+
|
25
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
26
|
+
gets
|
data/bin/place_order
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This script connects to IB API, subscribes to account info and prints out
|
4
|
+
# messages received from IB (update every 3 minute or so)
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
|
8
|
+
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'bundler/setup'
|
12
|
+
require 'ib-ruby'
|
13
|
+
|
14
|
+
# First, connect to IB TWS.
|
15
|
+
ib = IB::Connection.new
|
16
|
+
|
17
|
+
# Subscribe to TWS alerts/errors and account-related messages
|
18
|
+
# that TWS sends in response to account data request
|
19
|
+
ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
|
20
|
+
|
21
|
+
wfc = IB::Symbols::Stocks[:wfc]
|
22
|
+
buy_order = IB::Models::Order.new :total_quantity => 100,
|
23
|
+
:limit_price => 1 + rand().round(2),
|
24
|
+
:action => 'BUY',
|
25
|
+
:order_type => 'LMT'
|
26
|
+
|
27
|
+
sleep 0.5 # waiting for :NextValidID
|
28
|
+
|
29
|
+
ib.place_order buy_order, wfc
|
30
|
+
|
31
|
+
ib.send_message :RequestAllOpenOrders
|
32
|
+
|
33
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
34
|
+
gets
|
data/lib/ib-ruby/connection.rb
CHANGED
@@ -22,12 +22,13 @@ module IB
|
|
22
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
|
+
:client_id => nil, # Will be randomly assigned
|
25
26
|
:connect => true,
|
26
27
|
:reader => true
|
27
28
|
}
|
28
29
|
|
29
|
-
attr_reader :server
|
30
|
-
|
30
|
+
attr_reader :server # Info about IB server and server connection state
|
31
|
+
attr_accessor :next_order_id # Next valid order id
|
31
32
|
|
32
33
|
def initialize(opts = {})
|
33
34
|
@options = DEFAULT_OPTIONS.merge(opts)
|
@@ -67,8 +68,10 @@ module IB
|
|
67
68
|
@server[:local_connect_time] = Time.now()
|
68
69
|
@server[:remote_connect_time] = @server[:socket].read_string
|
69
70
|
|
70
|
-
# Sending arbitrary client ID to identify subsequent communications.
|
71
|
-
|
71
|
+
# Sending (arbitrary) client ID to identify subsequent communications.
|
72
|
+
# The client with a client_id of 0 can manage the TWS-owned open orders.
|
73
|
+
# Other clients can only manage their own open orders.
|
74
|
+
@server[:client_id] = @options[:client_id] || random_id
|
72
75
|
@server[:socket].send(@server[:client_id])
|
73
76
|
|
74
77
|
@connected = true
|
@@ -161,9 +164,9 @@ module IB
|
|
161
164
|
msg_id = @server[:socket].read_int
|
162
165
|
|
163
166
|
# Debug:
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
+
unless [1, 2, 4, 6, 7, 8, 9, 12, 21, 53].include? msg_id
|
168
|
+
puts "Got message #{msg_id} (#{Messages::Incoming::Table[msg_id]})"
|
169
|
+
end
|
167
170
|
|
168
171
|
# Create new instance of the appropriate message type, and have it read the message.
|
169
172
|
# NB: Failure here usually means unsupported message type received
|
@@ -173,6 +176,15 @@ module IB
|
|
173
176
|
puts "No subscribers for message #{msg.class}!" if subscribers[msg.class].empty?
|
174
177
|
end
|
175
178
|
|
179
|
+
# Place Order (convenience wrapper for message :PlaceOrder)
|
180
|
+
def place_order order, contract
|
181
|
+
send_message :PlaceOrder,
|
182
|
+
:order => order,
|
183
|
+
:contract => contract,
|
184
|
+
:id => @next_order_id
|
185
|
+
@next_order_id += 1
|
186
|
+
end
|
187
|
+
|
176
188
|
protected
|
177
189
|
|
178
190
|
def random_id
|
@@ -364,7 +364,8 @@ module IB
|
|
364
364
|
|
365
365
|
@order = Models::Order.new :id => @socket.read_int
|
366
366
|
|
367
|
-
@contract = Models::Contract.new :
|
367
|
+
@contract = Models::Contract.new :con_id => @socket.read_string,
|
368
|
+
:symbol => @socket.read_string,
|
368
369
|
:sec_type => @socket.read_string,
|
369
370
|
:expiry => @socket.read_string,
|
370
371
|
:strike => @socket.read_decimal,
|
@@ -397,7 +398,7 @@ module IB
|
|
397
398
|
@order.fa_percentage = @socket.read_string
|
398
399
|
@order.fa_profile = @socket.read_string
|
399
400
|
@order.good_till_date = @socket.read_string
|
400
|
-
@order.
|
401
|
+
@order.rule_80a = @socket.read_string
|
401
402
|
@order.percent_offset = @socket.read_decimal
|
402
403
|
@order.settling_firm = @socket.read_string
|
403
404
|
@order.short_sale_slot = @socket.read_int
|
@@ -431,7 +432,7 @@ module IB
|
|
431
432
|
@order.trail_stop_price = @socket.read_decimal
|
432
433
|
@order.basis_points = @socket.read_decimal
|
433
434
|
@order.basis_points_type = @socket.read_int
|
434
|
-
@
|
435
|
+
@contract.combo_legs_description = @socket.read_string
|
435
436
|
@order.scale_init_level_size = @socket.read_int_max
|
436
437
|
@order.scale_subs_level_size = @socket.read_int_max
|
437
438
|
@order.scale_price_increment = @socket.read_decimal_max
|
@@ -73,35 +73,46 @@ module IB
|
|
73
73
|
|
74
74
|
### Defining (short) Outgoing Message classes for IB:
|
75
75
|
|
76
|
-
|
76
|
+
## Empty messages (no data)
|
77
|
+
|
78
|
+
# Request the open orders that were placed from THIS client. Each open order
|
79
|
+
# will be fed back through the OpenOrder and OrderStatus messages.
|
80
|
+
# NB: Client with a client_id of 0 will also receive the TWS-owned open orders.
|
81
|
+
# These orders will be associated with the client and a new orderId will be
|
82
|
+
# generated. This association will persist over multiple API and TWS sessions.
|
77
83
|
RequestOpenOrders = def_message 5
|
78
|
-
|
84
|
+
|
85
|
+
# Request the open orders placed from all clients and also from TWS. Each open
|
86
|
+
# order will be fed back through the OpenOrder and OrderStatus messages.
|
79
87
|
RequestAllOpenOrders = def_message 16
|
80
|
-
|
88
|
+
|
81
89
|
# Requests an XML document that describes the valid parameters that a scanner
|
82
90
|
# subscription can have (for outgoing RequestScannerSubscription message).
|
83
91
|
RequestScannerParameters = def_message 24
|
92
|
+
|
93
|
+
CancelNewsBulletins = def_message 13
|
94
|
+
RequestManagedAccounts = def_message 17
|
84
95
|
RequestCurrentTime = def_message 49
|
85
96
|
RequestGlobalCancel = def_message 58
|
86
97
|
|
87
|
-
|
98
|
+
## Data format is: @data = { :id => ticker_id}
|
88
99
|
CancelMarketData = def_message 2
|
89
100
|
CancelMarketDepth = def_message 11
|
90
101
|
CancelScannerSubscription = def_message 23
|
91
102
|
CancelHistoricalData = def_message 25
|
92
103
|
CancelRealTimeBars = def_message 51
|
93
104
|
|
94
|
-
|
105
|
+
## Data format is: @data = { :id => request_id }
|
95
106
|
CancelFundamentalData = def_message 53
|
96
107
|
CancelImpliedVolatility = def_message 56
|
97
108
|
CancelCalculateImpliedVolatility = CancelImpliedVolatility
|
98
109
|
CancelOptionPrice = def_message 57
|
99
110
|
CancelCalculateOptionPrice = CancelOptionPrice
|
100
111
|
|
101
|
-
|
112
|
+
## Data format is: @data ={ :id => order-id-to-cancel }
|
102
113
|
CancelOrder = def_message 4
|
103
114
|
|
104
|
-
|
115
|
+
## These messages contain just one or two keys, shown in the end of definition
|
105
116
|
# @data = { :number_of_ids => int }
|
106
117
|
RequestIds = def_message 8, 1, :number_of_ids
|
107
118
|
# data = { :all_messages => boolean }
|
@@ -141,7 +141,7 @@ module IB
|
|
141
141
|
def right=(x)
|
142
142
|
x.upcase! if x.is_a?(String)
|
143
143
|
x = nil if !x.nil? && x.empty?
|
144
|
-
x = nil if x == "0"
|
144
|
+
x = nil if x == "0" || x == "?"
|
145
145
|
raise(ArgumentError.new("Invalid right \"#{x}\" (must be one of PUT, CALL, P, C)")) unless x.nil? || ["PUT", "CALL", "P", "C", "0"].include?(x)
|
146
146
|
@right = x
|
147
147
|
end
|
data/lib/ib-ruby/models/order.rb
CHANGED
@@ -261,7 +261,7 @@ module IB
|
|
261
261
|
# This returns an Array of data from the given order,
|
262
262
|
# mixed with data from associated contract. Ugly mix, indeed.
|
263
263
|
def serialize_with contract
|
264
|
-
[contract.serialize_long(:sec_id),
|
264
|
+
[contract.serialize_long(:con_id, :sec_id),
|
265
265
|
action, # main order fields
|
266
266
|
total_quantity,
|
267
267
|
order_type,
|
@@ -336,6 +336,14 @@ module IB
|
|
336
336
|
end
|
337
337
|
end
|
338
338
|
|
339
|
+
def to_s #human
|
340
|
+
"<Order::" + #self.class.
|
341
|
+
instance_variables.map do |key|
|
342
|
+
value = instance_variable_get(key)
|
343
|
+
" #{key}=#{value}" unless value.nil? || value == '' || value == 0
|
344
|
+
end.compact.join(',') + " >"
|
345
|
+
end
|
346
|
+
|
339
347
|
end # class Order
|
340
348
|
end # module Models
|
341
349
|
end # module IB
|
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.9
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paul Legato
|
@@ -44,10 +44,12 @@ executables:
|
|
44
44
|
- account_info
|
45
45
|
- contract_details
|
46
46
|
- depth_of_market
|
47
|
+
- global_cancel
|
47
48
|
- historic_data
|
48
49
|
- historic_data_cli
|
49
50
|
- market_data
|
50
51
|
- option_data
|
52
|
+
- place_order
|
51
53
|
- template
|
52
54
|
- time_and_sales
|
53
55
|
extensions: []
|
@@ -58,10 +60,12 @@ files:
|
|
58
60
|
- bin/account_info
|
59
61
|
- bin/contract_details
|
60
62
|
- bin/depth_of_market
|
63
|
+
- bin/global_cancel
|
61
64
|
- bin/historic_data
|
62
65
|
- bin/historic_data_cli
|
63
66
|
- bin/market_data
|
64
67
|
- bin/option_data
|
68
|
+
- bin/place_order
|
65
69
|
- bin/template
|
66
70
|
- bin/time_and_sales
|
67
71
|
- lib/ib-ruby/connection.rb
|