ib-ruby 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY +4 -0
- data/README.md +25 -17
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +2 -1
- data/bin/contract_details +3 -2
- data/bin/depth_of_market +1 -1
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +57 -104
- data/bin/list_orders +4 -3
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +63 -0
- data/bin/place_order +2 -4
- data/bin/template +1 -1
- data/bin/{generic_data.rb → tick_data} +3 -1
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +1 -0
- data/lib/ib-ruby/connection.rb +68 -68
- data/lib/ib-ruby/errors.rb +28 -0
- data/lib/ib-ruby/extensions.rb +7 -0
- data/lib/ib-ruby/messages.rb +1 -0
- data/lib/ib-ruby/messages/abstract_message.rb +16 -11
- data/lib/ib-ruby/messages/incoming.rb +125 -329
- data/lib/ib-ruby/messages/incoming/open_order.rb +193 -0
- data/lib/ib-ruby/messages/incoming/ticks.rb +131 -0
- data/lib/ib-ruby/messages/outgoing.rb +44 -45
- data/lib/ib-ruby/models/combo_leg.rb +16 -1
- data/lib/ib-ruby/models/contract.rb +18 -10
- data/lib/ib-ruby/models/contract/bag.rb +1 -7
- data/lib/ib-ruby/models/execution.rb +2 -1
- data/lib/ib-ruby/models/model.rb +1 -1
- data/lib/ib-ruby/models/order.rb +116 -56
- data/lib/ib-ruby/socket.rb +24 -3
- data/spec/account_helper.rb +2 -1
- data/spec/ib-ruby/messages/outgoing_spec.rb +1 -1
- data/spec/ib-ruby/models/combo_leg_spec.rb +0 -1
- data/spec/integration/account_info_spec.rb +2 -2
- data/spec/integration/contract_info_spec.rb +4 -4
- data/spec/integration/depth_data_spec.rb +3 -3
- data/spec/integration/historic_data_spec.rb +1 -1
- data/spec/integration/market_data_spec.rb +4 -4
- data/spec/integration/option_data_spec.rb +1 -1
- data/spec/integration/orders/combo_spec.rb +51 -0
- data/spec/integration/orders/execution_spec.rb +15 -8
- data/spec/integration/orders/placement_spec.rb +46 -72
- data/spec/integration/orders/valid_ids_spec.rb +6 -6
- data/spec/integration_helper.rb +0 -79
- data/spec/order_helper.rb +153 -0
- metadata +13 -4
@@ -1,5 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'order_helper'
|
2
2
|
|
3
|
+
#OPTS[:silent] = false
|
3
4
|
shared_examples_for 'Received single id' do
|
4
5
|
subject { @ib.received[:NextValidId].first }
|
5
6
|
|
@@ -41,7 +42,7 @@ describe 'Ids valid for Order placement', :connected => true, :integration => tr
|
|
41
42
|
before(:all) do
|
42
43
|
verify_account
|
43
44
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
44
|
-
@ib.wait_for 3, :OpenOrderEnd
|
45
|
+
@ib.wait_for :NextValidId, 3 # , :OpenOrderEnd
|
45
46
|
@id = {} # Moving id between contexts. Feels dirty.
|
46
47
|
end
|
47
48
|
|
@@ -51,14 +52,13 @@ describe 'Ids valid for Order placement', :connected => true, :integration => tr
|
|
51
52
|
|
52
53
|
it_behaves_like 'Received single id'
|
53
54
|
|
54
|
-
it
|
55
|
-
|
56
|
-
it 'receives also :OpenOrderEnd message' do
|
55
|
+
it 'receives also :OpenOrderEnd message', :pending => 'not in GW 924.2e' do
|
56
|
+
@ib.received[:OpenOrderEnd].should have_exactly(1).message
|
57
57
|
@ib.received[:OpenOrderEnd].first.should be_an IB::Messages::Incoming::OpenOrderEnd
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'logs connection notification' do
|
61
|
-
should_log /Connected to server, version:
|
61
|
+
should_log /Connected to server, version: .., connection time/
|
62
62
|
end
|
63
63
|
end # at connect
|
64
64
|
|
data/spec/integration_helper.rb
CHANGED
@@ -43,82 +43,3 @@ shared_examples_for 'Received Market Data' do
|
|
43
43
|
its(:to_human) { should =~ /TickSize/ }
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
47
|
-
### Helpers for placing and verifying orders
|
48
|
-
|
49
|
-
def place_order contract, opts
|
50
|
-
@contract = contract
|
51
|
-
@order = IB::Models::Order.new({:total_quantity => 100,
|
52
|
-
:limit_price => 9.13,
|
53
|
-
:action => 'BUY',
|
54
|
-
:order_type => 'LMT'}.merge(opts))
|
55
|
-
@order_id_before = @ib.next_order_id
|
56
|
-
@order_id_placed = @ib.place_order @order, @contract
|
57
|
-
@order_id_after = @ib.next_order_id
|
58
|
-
end
|
59
|
-
|
60
|
-
def check_status item, status
|
61
|
-
case status
|
62
|
-
when Regexp
|
63
|
-
item.status.should =~ status
|
64
|
-
when String
|
65
|
-
item.status.should == status
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def order_status_should_be status, index=0
|
70
|
-
msg = @ib.received[:OrderStatus][index]
|
71
|
-
msg.should be_an IB::Messages::Incoming::OrderStatus
|
72
|
-
msg.order_id.should == @order_id_placed
|
73
|
-
msg.perm_id.should be_an Integer
|
74
|
-
msg.client_id.should == OPTS[:connection][:client_id]
|
75
|
-
msg.parent_id.should == 0
|
76
|
-
msg.why_held.should == ''
|
77
|
-
check_status msg, status
|
78
|
-
|
79
|
-
if @contract == IB::Symbols::Forex[:eurusd]
|
80
|
-
msg.filled.should == 20000
|
81
|
-
msg.remaining.should == 0
|
82
|
-
msg.average_fill_price.should be > 1
|
83
|
-
msg.average_fill_price.should be < 2
|
84
|
-
msg.last_fill_price.should == msg.average_fill_price
|
85
|
-
else
|
86
|
-
msg.filled.should == 0
|
87
|
-
msg.remaining.should == @order.total_quantity
|
88
|
-
msg.average_fill_price.should == 0
|
89
|
-
msg.last_fill_price.should == 0
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def open_order_should_be status, index=0
|
94
|
-
msg = @ib.received[:OpenOrder][index]
|
95
|
-
msg.should be_an IB::Messages::Incoming::OpenOrder
|
96
|
-
msg.order.should == @order
|
97
|
-
msg.contract.should == @contract
|
98
|
-
msg.order.order_id.should == @order_id_placed
|
99
|
-
check_status msg.order, status
|
100
|
-
end
|
101
|
-
|
102
|
-
def execution_should_be side, opts={}
|
103
|
-
msg = @ib.received[:ExecutionData][opts[:index] || -1]
|
104
|
-
msg.request_id.should == (opts[:request_id] || -1)
|
105
|
-
msg.contract.should == @contract
|
106
|
-
|
107
|
-
exec = msg.execution
|
108
|
-
exec.perm_id.should be_an Integer
|
109
|
-
exec.perm_id.should == @ib.received[:OpenOrder].last.order.perm_id if @ib.received?(:OpenOrder)
|
110
|
-
exec.client_id.should == OPTS[:connection][:client_id]
|
111
|
-
exec.order_id.should be_an Integer
|
112
|
-
exec.order_id.should == @order.order_id if @order
|
113
|
-
exec.exec_id.should be_a String
|
114
|
-
exec.time.should =~ /\d\d:\d\d:\d\d/
|
115
|
-
exec.account_name.should == OPTS[:connection][:account_name]
|
116
|
-
exec.exchange.should == 'IDEALPRO'
|
117
|
-
exec.side.should == side
|
118
|
-
exec.shares.should == 20000
|
119
|
-
exec.cumulative_quantity.should == 20000
|
120
|
-
exec.price.should be > 1
|
121
|
-
exec.price.should be < 2
|
122
|
-
exec.price.should == exec.average_price
|
123
|
-
exec.liquidation.should == 0
|
124
|
-
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'integration_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'Placed Order' do
|
4
|
+
context "Placing" do
|
5
|
+
after(:all) { clean_connection } # Clear logs and message collector
|
6
|
+
|
7
|
+
it 'changes client`s next_order_id' do
|
8
|
+
@order_id_placed.should == @order_id_before
|
9
|
+
@ib.next_order_id.should == @order_id_before + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
it { @ib.received[:OpenOrder].should have_at_least(1).order_message }
|
13
|
+
it { @ib.received[:OrderStatus].should have_at_least(1).status_message }
|
14
|
+
|
15
|
+
it 'receives confirmation of Order submission' do
|
16
|
+
order_should_be /Submitted/ # ()Pre)Submitted
|
17
|
+
status_should_be /Submitted/
|
18
|
+
end
|
19
|
+
end # Placing
|
20
|
+
|
21
|
+
context "Retrieving placed" do
|
22
|
+
before(:all) do
|
23
|
+
@ib.send_message :RequestOpenOrders
|
24
|
+
@ib.wait_for :OpenOrderEnd
|
25
|
+
end
|
26
|
+
|
27
|
+
after(:all) { clean_connection } # Clear logs and message collector
|
28
|
+
|
29
|
+
it 'does not increase client`s next_order_id further' do
|
30
|
+
@ib.next_order_id.should == @order_id_after
|
31
|
+
end
|
32
|
+
|
33
|
+
it { @ib.received[:OpenOrder].should have_exactly(1).order_message }
|
34
|
+
it { @ib.received[:OrderStatus].should have_exactly(1).status_message }
|
35
|
+
it { @ib.received[:OpenOrderEnd].should have_exactly(1).order_end_message }
|
36
|
+
it { @ib.received[:Alert].should have_exactly(0).alert_messages }
|
37
|
+
|
38
|
+
it 'receives OpenOrder and OrderStatus for placed order' do
|
39
|
+
order_should_be /Submitted/
|
40
|
+
status_should_be /Submitted/
|
41
|
+
end
|
42
|
+
end # Retrieving
|
43
|
+
|
44
|
+
context "Cancelling placed order" do
|
45
|
+
before(:all) do
|
46
|
+
@ib.cancel_order @order_id_placed
|
47
|
+
@ib.wait_for :OrderStatus, :Alert
|
48
|
+
end
|
49
|
+
|
50
|
+
after(:all) { clean_connection } # Clear logs and message collector
|
51
|
+
|
52
|
+
it 'does not increase client`s next_order_id further' do
|
53
|
+
@ib.next_order_id.should == @order_id_after
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'does not receive OpenOrder message' do
|
57
|
+
@ib.received?(:OpenOrder).should be_false
|
58
|
+
end
|
59
|
+
|
60
|
+
it { @ib.received[:OrderStatus].should have_exactly(1).status_message }
|
61
|
+
it { @ib.received[:Alert].should have_exactly(1).alert_message }
|
62
|
+
|
63
|
+
it 'receives cancellation Order Status' do
|
64
|
+
status_should_be /Cancel/ # Cancelled / PendingCancel
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'receives Order cancelled Alert' do
|
68
|
+
alert = @ib.received[:Alert].first
|
69
|
+
alert.should be_an IB::Messages::Incoming::Alert
|
70
|
+
alert.message.should =~ /Order Canceled - reason:/
|
71
|
+
end
|
72
|
+
end # Cancelling
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
### Helpers for placing and verifying orders
|
77
|
+
|
78
|
+
def place_order contract, opts
|
79
|
+
@contract = contract
|
80
|
+
@order = IB::Models::Order.new({:total_quantity => 100,
|
81
|
+
:limit_price => 9.13,
|
82
|
+
:action => 'BUY',
|
83
|
+
:order_type => 'LMT'}.merge(opts))
|
84
|
+
@order_id_before = @ib.next_order_id
|
85
|
+
@order_id_placed = @ib.place_order @order, @contract
|
86
|
+
@order_id_after = @ib.next_order_id
|
87
|
+
end
|
88
|
+
|
89
|
+
def check_status item, status
|
90
|
+
case status
|
91
|
+
when Regexp
|
92
|
+
item.status.should =~ status
|
93
|
+
when String
|
94
|
+
item.status.should == status
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def status_should_be status, index=0
|
99
|
+
msg = @ib.received[:OrderStatus][index]
|
100
|
+
msg.should be_an IB::Messages::Incoming::OrderStatus
|
101
|
+
msg.order_id.should == @order_id_placed
|
102
|
+
msg.perm_id.should be_an Integer
|
103
|
+
msg.client_id.should == OPTS[:connection][:client_id]
|
104
|
+
msg.parent_id.should == 0
|
105
|
+
msg.why_held.should == ''
|
106
|
+
check_status msg, status
|
107
|
+
|
108
|
+
if @contract == IB::Symbols::Forex[:eurusd]
|
109
|
+
msg.filled.should == 20000
|
110
|
+
msg.remaining.should == 0
|
111
|
+
msg.average_fill_price.should be > 1
|
112
|
+
msg.average_fill_price.should be < 2
|
113
|
+
msg.last_fill_price.should == msg.average_fill_price
|
114
|
+
else
|
115
|
+
msg.filled.should == 0
|
116
|
+
msg.remaining.should == @order.total_quantity
|
117
|
+
msg.average_fill_price.should == 0
|
118
|
+
msg.last_fill_price.should == 0
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def order_should_be status, index=0
|
123
|
+
msg = @ib.received[:OpenOrder][index]
|
124
|
+
msg.should be_an IB::Messages::Incoming::OpenOrder
|
125
|
+
msg.order.should == @order
|
126
|
+
msg.contract.should == @contract
|
127
|
+
msg.order.order_id.should == @order_id_placed
|
128
|
+
check_status msg.order, status
|
129
|
+
end
|
130
|
+
|
131
|
+
def execution_should_be side, opts={}
|
132
|
+
msg = @ib.received[:ExecutionData][opts[:index] || -1]
|
133
|
+
msg.request_id.should == (opts[:request_id] || -1)
|
134
|
+
msg.contract.should == @contract
|
135
|
+
|
136
|
+
exec = msg.execution
|
137
|
+
exec.perm_id.should be_an Integer
|
138
|
+
exec.perm_id.should == @ib.received[:OpenOrder].last.order.perm_id if @ib.received?(:OpenOrder)
|
139
|
+
exec.client_id.should == OPTS[:connection][:client_id]
|
140
|
+
exec.order_id.should be_an Integer
|
141
|
+
exec.order_id.should == @order.order_id if @order
|
142
|
+
exec.exec_id.should be_a String
|
143
|
+
exec.time.should =~ /\d\d:\d\d:\d\d/
|
144
|
+
exec.account_name.should == OPTS[:connection][:account_name]
|
145
|
+
exec.exchange.should == 'IDEALPRO'
|
146
|
+
exec.side.should == side
|
147
|
+
exec.shares.should == 20000
|
148
|
+
exec.cumulative_quantity.should == 20000
|
149
|
+
exec.price.should be > 1
|
150
|
+
exec.price.should be < 2
|
151
|
+
exec.price.should == exec.average_price
|
152
|
+
exec.liquidation.should == 0
|
153
|
+
end
|
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
|
+
version: 0.7.0
|
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-03-
|
14
|
+
date: 2012-03-22 00:00:00 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -55,14 +55,15 @@ executables:
|
|
55
55
|
- cancel_orders
|
56
56
|
- contract_details
|
57
57
|
- depth_of_market
|
58
|
-
- generic_data.rb
|
59
58
|
- historic_data
|
60
59
|
- historic_data_cli
|
61
60
|
- list_orders
|
62
61
|
- market_data
|
63
62
|
- option_data
|
63
|
+
- place_combo_order
|
64
64
|
- place_order
|
65
65
|
- template
|
66
|
+
- tick_data
|
66
67
|
- time_and_sales
|
67
68
|
extensions: []
|
68
69
|
|
@@ -73,18 +74,20 @@ files:
|
|
73
74
|
- bin/cancel_orders
|
74
75
|
- bin/contract_details
|
75
76
|
- bin/depth_of_market
|
76
|
-
- bin/generic_data.rb
|
77
77
|
- bin/historic_data
|
78
78
|
- bin/historic_data_cli
|
79
79
|
- bin/list_orders
|
80
80
|
- bin/market_data
|
81
81
|
- bin/option_data
|
82
|
+
- bin/place_combo_order
|
82
83
|
- bin/place_order
|
83
84
|
- bin/template
|
85
|
+
- bin/tick_data
|
84
86
|
- bin/time_and_sales
|
85
87
|
- lib/ib-ruby.rb
|
86
88
|
- lib/ib-ruby/connection.rb
|
87
89
|
- lib/ib-ruby/constants.rb
|
90
|
+
- lib/ib-ruby/errors.rb
|
88
91
|
- lib/ib-ruby/extensions.rb
|
89
92
|
- lib/ib-ruby/logger.rb
|
90
93
|
- lib/ib-ruby/messages.rb
|
@@ -95,6 +98,8 @@ files:
|
|
95
98
|
- lib/ib-ruby/messages/abstract_message.rb
|
96
99
|
- lib/ib-ruby/messages/incoming.rb
|
97
100
|
- lib/ib-ruby/messages/outgoing.rb
|
101
|
+
- lib/ib-ruby/messages/incoming/open_order.rb
|
102
|
+
- lib/ib-ruby/messages/incoming/ticks.rb
|
98
103
|
- lib/ib-ruby/models/bar.rb
|
99
104
|
- lib/ib-ruby/models/combo_leg.rb
|
100
105
|
- lib/ib-ruby/models/contract.rb
|
@@ -111,6 +116,7 @@ files:
|
|
111
116
|
- spec/account_helper.rb
|
112
117
|
- spec/integration_helper.rb
|
113
118
|
- spec/message_helper.rb
|
119
|
+
- spec/order_helper.rb
|
114
120
|
- spec/README.md
|
115
121
|
- spec/spec_helper.rb
|
116
122
|
- spec/ib-ruby/connection_spec.rb
|
@@ -126,6 +132,7 @@ files:
|
|
126
132
|
- spec/integration/historic_data_spec.rb
|
127
133
|
- spec/integration/market_data_spec.rb
|
128
134
|
- spec/integration/option_data_spec.rb
|
135
|
+
- spec/integration/orders/combo_spec.rb
|
129
136
|
- spec/integration/orders/execution_spec.rb
|
130
137
|
- spec/integration/orders/open_order
|
131
138
|
- spec/integration/orders/placement_spec.rb
|
@@ -174,6 +181,7 @@ test_files:
|
|
174
181
|
- spec/account_helper.rb
|
175
182
|
- spec/integration_helper.rb
|
176
183
|
- spec/message_helper.rb
|
184
|
+
- spec/order_helper.rb
|
177
185
|
- spec/README.md
|
178
186
|
- spec/spec_helper.rb
|
179
187
|
- spec/ib-ruby/connection_spec.rb
|
@@ -189,6 +197,7 @@ test_files:
|
|
189
197
|
- spec/integration/historic_data_spec.rb
|
190
198
|
- spec/integration/market_data_spec.rb
|
191
199
|
- spec/integration/option_data_spec.rb
|
200
|
+
- spec/integration/orders/combo_spec.rb
|
192
201
|
- spec/integration/orders/execution_spec.rb
|
193
202
|
- spec/integration/orders/open_order
|
194
203
|
- spec/integration/orders/placement_spec.rb
|