ib-ruby 0.5.21 → 0.6.1

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.
Files changed (38) hide show
  1. data/HISTORY +8 -0
  2. data/README.md +46 -27
  3. data/TODO +13 -2
  4. data/VERSION +1 -1
  5. data/bin/generic_data.rb +26 -0
  6. data/bin/place_order +1 -1
  7. data/lib/ib-ruby/connection.rb +126 -65
  8. data/lib/ib-ruby/messages/incoming.rb +3 -3
  9. data/lib/ib-ruby/models/bar.rb +11 -11
  10. data/lib/ib-ruby/models/combo_leg.rb +23 -29
  11. data/lib/ib-ruby/models/contract/bag.rb +34 -2
  12. data/lib/ib-ruby/models/contract/option.rb +2 -2
  13. data/lib/ib-ruby/models/contract.rb +151 -197
  14. data/lib/ib-ruby/models/execution.rb +27 -45
  15. data/lib/ib-ruby/models/model.rb +10 -4
  16. data/lib/ib-ruby/models/model_properties.rb +63 -0
  17. data/lib/ib-ruby/models/order.rb +274 -320
  18. data/lib/ib-ruby/symbols/stocks.rb +11 -5
  19. data/spec/account_helper.rb +80 -0
  20. data/spec/ib-ruby/connection_spec.rb +195 -52
  21. data/spec/ib-ruby/messages/incoming_spec.rb +4 -4
  22. data/spec/ib-ruby/models/combo_leg_spec.rb +1 -0
  23. data/spec/ib-ruby/models/contract_spec.rb +1 -1
  24. data/spec/ib-ruby/models/execution_spec.rb +73 -0
  25. data/spec/integration/account_info_spec.rb +12 -59
  26. data/spec/integration/contract_info_spec.rb +23 -37
  27. data/spec/integration/depth_data_spec.rb +4 -4
  28. data/spec/integration/historic_data_spec.rb +15 -27
  29. data/spec/integration/market_data_spec.rb +74 -61
  30. data/spec/integration/option_data_spec.rb +5 -48
  31. data/spec/integration/orders/execution_spec.rb +26 -31
  32. data/spec/integration/orders/open_order +2 -0
  33. data/spec/integration/orders/placement_spec.rb +28 -28
  34. data/spec/integration/orders/valid_ids_spec.rb +11 -11
  35. data/spec/integration_helper.rb +46 -32
  36. data/spec/message_helper.rb +4 -38
  37. data/spec/spec_helper.rb +2 -3
  38. metadata +9 -2
@@ -13,11 +13,17 @@ module IB
13
13
  :currency => "USD",
14
14
  :sec_type => SECURITY_TYPES[:stock],
15
15
  :description => "Wells Fargo"),
16
- :wrong => Models::Contract.new(:symbol => "QEEUUE",
17
- :exchange => "NYSE",
18
- :currency => "USD",
19
- :sec_type => SECURITY_TYPES[:stock],
20
- :description => "Non-existent stock"),
16
+
17
+ :aapl => Models::Contract.new(:symbol => "AAPL",
18
+ :currency => "USD",
19
+ :sec_type => SECURITY_TYPES[:stock],
20
+ :description => "Apple Inc."),
21
+
22
+ :wrong => Models::Contract.new(:symbol => "QEEUUE",
23
+ :exchange => "NYSE",
24
+ :currency => "USD",
25
+ :sec_type => SECURITY_TYPES[:stock],
26
+ :description => "Non-existent stock"),
21
27
  }
22
28
  end
23
29
  end
@@ -0,0 +1,80 @@
1
+ # Make sure integration tests are only run against the pre-configured PAPER ACCOUNT
2
+ def verify_account
3
+ return OPTS[:account_verified] if OPTS[:account_verified]
4
+
5
+ puts
6
+ puts 'WARNING: MAKE SURE TO RUN INTEGRATION TESTS AGAINST IB PAPER ACCOUNT ONLY!'
7
+ puts 'WARNING: FINANCIAL LOSSES MAY RESULT IF YOU RUN TESTS WITH REAL IB ACCOUNT!'
8
+ puts 'WARNING: YOU HAVE BEEN WARNED!'
9
+ puts
10
+ puts 'Configure your connection to IB PAPER ACCOUNT in spec/spec_helper.rb'
11
+ puts
12
+
13
+ account = OPTS[:connection][:account] || OPTS[:connection][:account_name]
14
+ raise "Please configure IB PAPER ACCOUNT in spec/spec_helper.rb" unless account
15
+
16
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
17
+ @ib.send_message :RequestAccountData, :subscribe => true
18
+
19
+ @ib.wait_for 3, :AccountValue
20
+ raise "Unable to verify IB PAPER ACCOUNT" unless @ib.received?(:AccountValue)
21
+
22
+ received = @ib.received[:AccountValue].first.account_name
23
+ raise "Connected to wrong account #{received}, expected #{account}" if account != received
24
+
25
+ close_connection
26
+ OPTS[:account_verified] = true
27
+ end
28
+
29
+ ### Helpers for placing and verifying orders
30
+
31
+ shared_examples_for 'Valid account data request' do
32
+
33
+ context "received :AccountUpdateTime message" do
34
+ subject { @ib.received[:AccountUpdateTime].first }
35
+
36
+ it { should be_an IB::Messages::Incoming::AccountUpdateTime }
37
+ its(:data) { should be_a Hash }
38
+ its(:time_stamp) { should =~ /\d\d:\d\d/ }
39
+ its(:to_human) { should =~ /AccountUpdateTime/ }
40
+ end
41
+
42
+ context "received :AccountValue message" do
43
+ subject { @ib.received[:AccountValue].first }
44
+
45
+ #ps
46
+ it { should be_an IB::Messages::Incoming::AccountValue }
47
+ its(:data) { should be_a Hash }
48
+ its(:account_name) { should =~ /\w\d/ }
49
+ its(:key) { should be_a String }
50
+ its(:value) { should be_a String }
51
+ its(:currency) { should be_a String }
52
+ its(:to_human) { should =~ /AccountValue/ }
53
+ end
54
+
55
+ context "received :PortfolioValue message" do
56
+ subject { @ib.received[:PortfolioValue].first }
57
+
58
+ it { should be_an IB::Messages::Incoming::PortfolioValue }
59
+ its(:contract) { should be_a IB::Models::Contract }
60
+ its(:data) { should be_a Hash }
61
+ its(:position) { should be_a Integer }
62
+ its(:market_price) { should be_a Float }
63
+ its(:market_value) { should be_a Float }
64
+ its(:average_cost) { should be_a Float }
65
+ its(:unrealized_pnl) { should be_a Float }
66
+ its(:realized_pnl) { should be_a Float }
67
+ its(:account_name) { should =~ /\w\d/ }
68
+ its(:to_human) { should =~ /PortfolioValue/ }
69
+ end
70
+
71
+ context "received :AccountDownloadEnd message" do
72
+ subject { @ib.received[:AccountDownloadEnd].first }
73
+
74
+ it { should be_an IB::Messages::Incoming::AccountDownloadEnd }
75
+ its(:data) { should be_a Hash }
76
+ its(:account_name) { should =~ /\w\d/ }
77
+ its(:to_human) { should =~ /AccountDownloadEnd/ }
78
+ end
79
+ end
80
+
@@ -1,94 +1,237 @@
1
1
  require 'message_helper'
2
+ require 'account_helper'
3
+
4
+ shared_examples_for 'Connected Connection' do
5
+
6
+ subject { @ib }
7
+
8
+ it_behaves_like 'Connected Connection without receiver'
9
+
10
+ it 'keeps received messages in Hash by default' do
11
+ subject.received.should be_a Hash
12
+ subject.received[:NextValidId].should_not be_empty
13
+ subject.received[:NextValidId].should have_exactly(1).message
14
+ end
15
+ end
16
+
17
+ shared_examples_for 'Connected Connection without receiver' do
18
+
19
+ it { should_not be_nil }
20
+ it { should be_connected }
21
+ its(:server) { should be_a Hash }
22
+ its(:server) { should have_key :reader }
23
+ its(:subscribers) { should have_at_least(1).item } # :NextValidId and empty Hashes
24
+ its(:next_order_id) { should be_a Fixnum } # Not before :NextValidId arrives
25
+ end
26
+
27
+ # Need top level method to access instance var (@received) in nested context
28
+ def create_connection opts={}
29
+ # Start disconnected (we need to set up catch-all subscriber first)
30
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger).merge(opts)
31
+
32
+ # Hash of received messages, keyed by message type
33
+ @received = Hash.new { |hash, key| hash[key] = Array.new }
34
+
35
+ @subscriber = proc { |msg| @received[msg.message_type] << msg }
36
+ end
2
37
 
3
38
  describe IB::Connection do
4
39
 
5
- context 'when connected to IB Gateway', :connected => true do
6
- # THIS depends on TWS|Gateway connectivity
40
+ context 'instantiated with default options', :connected => true do
7
41
  before(:all) do
8
- @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
9
- @ib.subscribe(:OpenOrderEnd) {}
42
+ create_connection
43
+ @ib.wait_for :NextValidId
10
44
  end
11
45
 
12
46
  after(:all) { close_connection }
13
47
 
14
- context 'instantiation with default options' do
15
- subject { @ib }
16
-
17
- it { should_not be_nil }
18
- it { should be_connected }
19
- its(:server) { should be_a Hash }
20
- its(:server) { should have_key :reader }
21
- its(:subscribers) { should have_at_least(1).item } # :NextValidID and empty Hashes
22
- its(:next_order_id) { should be_a Fixnum } # Not before :NextValidID arrives
23
- end
48
+ it_behaves_like 'Connected Connection'
24
49
 
25
50
  describe '#send_message', 'sending messages' do
26
51
  it 'allows 3 signatures representing IB::Messages::Outgoing' do
27
- expect {
28
- @ib.send_message :RequestOpenOrders, :subscribe => true
29
- }.to_not raise_error
52
+ expect { @ib.send_message :RequestOpenOrders }.to_not raise_error
30
53
 
31
- expect {
32
- @ib.send_message IB::Messages::Outgoing::RequestOpenOrders, :subscribe => true
54
+ expect { @ib.send_message IB::Messages::Outgoing::RequestOpenOrders
33
55
  }.to_not raise_error
34
56
 
35
- expect {
36
- @ib.send_message IB::Messages::Outgoing::RequestOpenOrders.new :subscribe => true
57
+ expect { @ib.send_message IB::Messages::Outgoing::RequestOpenOrders.new
37
58
  }.to_not raise_error
38
59
  end
39
60
 
40
61
  it 'has legacy #dispatch alias' do
41
- expect { @ib.dispatch :RequestOpenOrders, :subscribe => true
42
- }.to_not raise_error
62
+ expect { @ib.dispatch :RequestOpenOrders }.to_not raise_error
43
63
  end
44
64
  end
45
65
 
46
66
  context "subscriptions" do
67
+ before(:all) do
68
+ @id = {} # Moving id between contexts. Feels dirty.
69
+ end
70
+
71
+ describe '#subscribe' do
72
+ after(:all) { clean_connection }
73
+
74
+ it 'adds (multiple) subscribers, returning subscription id' do
75
+ @id[:first] = @ib.subscribe(IB::Messages::Incoming::OrderStatus) do |msg|
76
+ log msg.to_human
77
+ end
78
+
79
+ @id[:second] = @ib.subscribe /Value/, :OpenOrder, @subscriber
80
+
81
+ @id[:third] = @ib.subscribe /Account/, &@subscriber
82
+
83
+ [[@id[:first], IB::Messages::Incoming::OrderStatus],
84
+ [@id[:second], IB::Messages::Incoming::OpenOrder],
85
+ [@id[:second], IB::Messages::Incoming::PortfolioValue],
86
+ [@id[:second], IB::Messages::Incoming::AccountValue], # as /Value/
87
+ [@id[:third], IB::Messages::Incoming::AccountValue], # as /Account/
88
+ [@id[:third], IB::Messages::Incoming::AccountDownloadEnd],
89
+ [@id[:third], IB::Messages::Incoming::AccountUpdateTime],
90
+ ].each do |(subscriber_id, message_class)|
91
+ @ib.subscribers.should have_key(message_class)
92
+ @ib.subscribers[message_class].should have_key(subscriber_id)
93
+ end
94
+ end
47
95
 
48
- it '#subscribe, adds(multiple) subscribers' do
49
- @subscriber_id = @ib.subscribe(IB::Messages::Incoming::Alert, :OpenOrder, /Value/) do
96
+ it 'returns Integer subscription id' do
97
+ @id[:first].should be_an Integer
98
+ @id[:second].should be_an Integer
99
+ @id[:third].should be_an Integer
50
100
  end
51
101
 
52
- @subscriber_id.should be_a Fixnum
102
+ context 'when subscribed' do
53
103
 
54
- [IB::Messages::Incoming::Alert,
55
- IB::Messages::Incoming::OpenOrder,
56
- IB::Messages::Incoming::AccountValue,
57
- IB::Messages::Incoming::PortfolioValue
58
- ].each do |message_class|
59
- @ib.subscribers.should have_key(message_class)
60
- @ib.subscribers[message_class].should have_key(@subscriber_id)
104
+ before(:all) do
105
+ @ib.send_message :RequestAccountData
106
+ @ib.wait_for :AccountDownloadEnd
107
+ end
108
+
109
+ after(:all) { @ib.send_message :RequestAccountData, :subscribe => false }
110
+
111
+ it 'receives subscribed message types and processes them in subscriber callback' do
112
+ @received[:AccountValue].should_not be_empty
113
+ @received[:PortfolioValue].should_not be_empty
114
+ @received[:AccountDownloadEnd].should_not be_empty
115
+ @received[:AccountUpdateTime].should_not be_empty
116
+ end
117
+
118
+ it_behaves_like 'Valid account data request'
119
+ end
120
+ end # subscribe
121
+
122
+ describe '#unsubscribe' do
123
+ before(:all) { @result = @ib.unsubscribe @id[:first], @id[:second] }
124
+
125
+ it 'removes all subscribers at given id or ids' do
126
+ [IB::Messages::Incoming::OrderStatus,
127
+ IB::Messages::Incoming::OpenOrder,
128
+ IB::Messages::Incoming::PortfolioValue,
129
+ IB::Messages::Incoming::AccountValue,
130
+ ].each do |message_class|
131
+ @ib.subscribers[message_class].should_not have_key(@id[:first])
132
+ @ib.subscribers[message_class].should_not have_key(@id[:second])
133
+ end
61
134
  end
62
- end
63
135
 
64
- it '#unsubscribe, removes all subscribers at this id' do
65
- @ib.unsubscribe(@subscriber_id)
136
+ it 'does not remove subscribers at other ids' do
137
+ @ib.subscribers[IB::Messages::Incoming::AccountValue].should have_key(@id[:third])
138
+ @ib.subscribers[IB::Messages::Incoming::AccountDownloadEnd].should have_key(@id[:third])
139
+ @ib.subscribers[IB::Messages::Incoming::AccountUpdateTime].should have_key(@id[:third])
140
+ end
141
+
142
+ it 'returns an Array of removed subscribers' do
143
+ @result.should be_an Array
144
+ @result.should have_exactly(4).deleted_subscribers
145
+ end
66
146
 
67
- [IB::Messages::Incoming::Alert,
68
- IB::Messages::Incoming::OpenOrder,
69
- IB::Messages::Incoming::AccountValue,
70
- IB::Messages::Incoming::PortfolioValue
71
- ].each do |message_class|
72
- @ib.subscribers[message_class].should_not have_key(@subscriber_id)
147
+ it 'raises on nosense id given' do
148
+ expect { @ib.unsubscribe 'nonsense' }.to raise_error /No subscribers with id/
149
+ expect { @ib.unsubscribe rand(9999999) }.to raise_error /No subscribers with id/
73
150
  end
74
151
  end
75
152
 
153
+ context 'when unsubscribed' do
154
+
155
+ before(:all) do
156
+ @ib.send_message :RequestAccountData
157
+ @ib.wait_for { !@received[:AccountDownloadEnd].empty? }
158
+ end
159
+
160
+ after(:all) { @ib.send_message :RequestAccountData, :subscribe => false }
161
+
162
+ it 'receives subscribed message types still subscribed' do
163
+ @received[:AccountValue].should_not be_empty
164
+ @received[:AccountUpdateTime].should_not be_empty
165
+ @received[:AccountDownloadEnd].should_not be_empty
166
+ end
167
+
168
+ it 'does not receive unsubscribed message types' do
169
+ @received[:PortfolioValue].should be_empty
170
+ end
171
+
172
+ it { should_log /No subscribers for message .*:PortfolioValue/ }
173
+ it { should_not_log /No subscribers for message .*:AccountValue/ }
174
+ end # when subscribed
76
175
  end # subscriptions
176
+
177
+ describe '#connect' do
178
+ it 'raises on another connection attempt' do
179
+ expect { @ib.connect }.to raise_error /Already connected/
180
+ end
181
+ end
77
182
  end # connected
78
183
 
79
- context 'when not connected to IB Gateway' do
80
- before(:all) { @ib = IB::Connection.new :connect => false, :reader => false }
184
+ context 'instantiated passing :connect => false' do
185
+ before(:all) { create_connection :connect => false,
186
+ :reader => false }
187
+ subject { @ib }
188
+
189
+ it { should_not be_nil }
190
+ it { should_not be_connected }
191
+ its(:server) { should be_a Hash }
192
+ its(:server) { should_not have_key :reader }
193
+ its(:received) { should be_empty }
194
+ its(:subscribers) { should be_empty }
195
+ its(:next_order_id) { should be_nil }
196
+
197
+ describe 'connecting idle conection' do
198
+ before(:all) do
199
+ @ib.connect
200
+ @ib.start_reader
201
+ @ib.wait_for :NextValidId
202
+ end
203
+ after(:all) { close_connection }
204
+
205
+ it_behaves_like 'Connected Connection'
206
+ end
81
207
 
82
- context 'instantiation passing :connect => false' do
83
- subject { @ib }
208
+ end # not connected
84
209
 
85
- it { should_not be_nil }
86
- it { should_not be_connected }
87
- its(:server) { should be_a Hash }
88
- its(:server) { should_not have_key :reader }
89
- its(:subscribers) { should be_empty }
90
- its(:next_order_id) { should be_nil }
210
+ context 'instantiated passing :received => false' do
211
+ before(:all) { create_connection :connect => false,
212
+ :reader => false,
213
+ :received => false }
214
+ subject { @ib }
215
+
216
+ it { should_not be_nil }
217
+ it { should_not be_connected }
218
+ its(:server) { should be_a Hash }
219
+ its(:server) { should_not have_key :reader }
220
+ its(:received) { should be_empty }
221
+ its(:subscribers) { should be_empty }
222
+ its(:next_order_id) { should be_nil }
223
+
224
+ describe 'connecting idle conection' do
225
+ before(:all) do
226
+ @ib.connect
227
+ @ib.start_reader
228
+ @ib.wait_for 1 # ib.received not supposed to work!
229
+ end
230
+ after(:all) { close_connection }
231
+
232
+ it_behaves_like 'Connected Connection without receiver'
91
233
  end
92
234
 
93
235
  end # not connected
236
+
94
237
  end # describe IB::Connection
@@ -7,7 +7,7 @@ shared_examples_for 'Alert message' do
7
7
  its(:message_type) { should == :Alert }
8
8
  its(:message_id) { should == 4 }
9
9
  its(:version) { should == 2 }
10
- its(:data) { should == {:version=>2, :error_id=>-1, :code=>2104, :message=>"Market data farm connection is OK:cashfarm"}}
10
+ its(:data) { should == {:version=>2, :error_id=>-1, :code=>2104, :message=>"Market data farm connection is OK:cashfarm"} }
11
11
  its(:error_id) { should == -1 }
12
12
  its(:code) { should == 2104 }
13
13
  its(:message) { should =~ /Market data farm connection is OK/ }
@@ -37,13 +37,13 @@ describe IB::Messages::Incoming do
37
37
  context 'Message received from IB', :connected => true do
38
38
 
39
39
  before(:all) do
40
- connect_and_receive :Alert
41
- wait_for(2) { received? :Alert }
40
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
41
+ @ib.wait_for :Alert
42
42
  end
43
43
 
44
44
  after(:all) { close_connection }
45
45
 
46
- subject { @received[:Alert].first }
46
+ subject { @ib.received[:Alert].first }
47
47
 
48
48
  it_behaves_like 'Alert message'
49
49
  end #
@@ -22,6 +22,7 @@ describe IB::Models::ComboLeg do
22
22
  its(:ratio) {should == 0}
23
23
  its(:open_close) {should == 0}
24
24
  its(:short_sale_slot) {should == 0}
25
+ its(:designated_location) {should == ''}
25
26
  its(:exempt_code) {should == -1}
26
27
 
27
28
  its(:created_at) {should be_a Time}
@@ -21,7 +21,7 @@ describe IB::Models::Contract do
21
21
  it { should_not be_nil }
22
22
  its(:con_id) { should == 0 }
23
23
  its(:strike) { should == 0 }
24
- its(:sec_type) { should == '' }
24
+ its(:sec_type) { should be_nil }
25
25
  its(:created_at) { should be_a Time }
26
26
  its(:include_expired) { should == false }
27
27
  end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe IB::Models::Execution do
4
+
5
+ let(:properties) do
6
+ {:account_name => "DU111110",
7
+ :average_price => 1.31075,
8
+ :client_id => 1111,
9
+ :cumulative_quantity => 20000,
10
+ :exchange => "IDEALPRO",
11
+ :exec_id => "0001f4e8.4f5d48f1.01.01",
12
+ :liquidation => 0,
13
+ :order_id => 373,
14
+ :perm_id => 1695693613,
15
+ :price => 1.31075,
16
+ :shares => 20000,
17
+ :side => :buy,
18
+ :time => "20120312 15:41:09"
19
+ }
20
+ end
21
+
22
+ context "instantiation" do
23
+ context 'empty without properties' do
24
+ subject { IB::Models::Execution.new }
25
+
26
+ it { should_not be_nil }
27
+ its(:order_id) { should == 0 }
28
+ its(:client_id) { should == 0 }
29
+ its(:perm_id) { should == 0 }
30
+ its(:shares) { should == 0 }
31
+ its(:price) { should == 0 }
32
+ its(:liquidation) { should == 0 }
33
+ its(:created_at) { should be_a Time }
34
+ end
35
+
36
+ context 'with properties' do
37
+ subject { IB::Models::Execution.new properties }
38
+
39
+ it 'sets properties right' do
40
+ properties.each do |name, value|
41
+ subject.send(name).should == value
42
+ end
43
+ end
44
+ end
45
+ end #instantiation
46
+
47
+ context "properties" do
48
+
49
+ it 'allows setting properties' do
50
+ expect {
51
+ x = IB::Models::Execution.new
52
+ properties.each do |name, value|
53
+ subject.send("#{name}=", value)
54
+ subject.send(name).should == value
55
+ end
56
+ }.to_not raise_error
57
+ end
58
+
59
+ it 'sets side as directed by its setter' do
60
+ @x = IB::Models::Execution.new
61
+ ['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b].each do |val|
62
+ expect { @x.side = val }.to_not raise_error
63
+ @x.side.should == :buy
64
+ end
65
+
66
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S].each do |val|
67
+ expect { @x.side = val }.to_not raise_error
68
+ @x.side.should == :sell
69
+ end
70
+ end
71
+ end # properties
72
+
73
+ end # describe IB::Models::Contract
@@ -1,66 +1,10 @@
1
1
  require 'integration_helper'
2
2
 
3
- shared_examples_for 'Valid account data request' do
4
-
5
- after(:all) do
6
- @ib.send_message :RequestAccountData, :subscribe => false
7
- clean_connection
8
- end
9
-
10
- context "received :AccountUpdateTime message" do
11
- subject { @received[:AccountUpdateTime].first }
12
-
13
- it { should be_an IB::Messages::Incoming::AccountUpdateTime }
14
- its(:data) { should be_a Hash }
15
- its(:time_stamp) { should =~ /\d\d:\d\d/ }
16
- its(:to_human) { should =~ /AccountUpdateTime/ }
17
- end
18
-
19
- context "received :AccountValue message" do
20
- subject { @received[:AccountValue].first }
21
-
22
- #ps
23
- it { should be_an IB::Messages::Incoming::AccountValue }
24
- its(:data) { should be_a Hash }
25
- its(:account_name) { should =~ /\w\d/ }
26
- its(:key) { should be_a String }
27
- its(:value) { should be_a String }
28
- its(:currency) { should be_a String }
29
- its(:to_human) { should =~ /AccountValue/ }
30
- end
31
-
32
- context "received :PortfolioValue message" do
33
- subject { @received[:PortfolioValue].first }
34
-
35
- it { should be_an IB::Messages::Incoming::PortfolioValue }
36
- its(:contract) { should be_a IB::Models::Contract }
37
- its(:data) { should be_a Hash }
38
- its(:position) { should be_a Integer }
39
- its(:market_price) { should be_a Float }
40
- its(:market_value) { should be_a Float }
41
- its(:average_cost) { should be_a Float }
42
- its(:unrealized_pnl) { should be_a Float }
43
- its(:realized_pnl) { should be_a Float }
44
- its(:account_name) { should =~ /\w\d/ }
45
- its(:to_human) { should =~ /PortfolioValue/ }
46
- end
47
-
48
- context "received :AccountDownloadEnd message" do
49
- subject { @received[:AccountDownloadEnd].first }
50
-
51
- it { should be_an IB::Messages::Incoming::AccountDownloadEnd }
52
- its(:data) { should be_a Hash }
53
- its(:account_name) { should =~ /\w\d/ }
54
- its(:to_human) { should =~ /AccountDownloadEnd/ }
55
- end
56
- end
57
-
58
3
  describe "Request Account Data", :connected => true, :integration => true do
59
4
 
60
5
  before(:all) do
61
6
  verify_account
62
- connect_and_receive(:Alert, :AccountValue, :AccountDownloadEnd,
63
- :PortfolioValue, :AccountUpdateTime)
7
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
64
8
  end
65
9
 
66
10
  after(:all) { close_connection }
@@ -68,7 +12,11 @@ describe "Request Account Data", :connected => true, :integration => true do
68
12
  context "with subscribe option set" do
69
13
  before(:all) do
70
14
  @ib.send_message :RequestAccountData, :subscribe => true
71
- wait_for(5) { received? :AccountDownloadEnd }
15
+ @ib.wait_for 5, :AccountDownloadEnd
16
+ end
17
+ after(:all) do
18
+ @ib.send_message :RequestAccountData, :subscribe => false
19
+ clean_connection
72
20
  end
73
21
 
74
22
  it_behaves_like 'Valid account data request'
@@ -77,7 +25,12 @@ describe "Request Account Data", :connected => true, :integration => true do
77
25
  context "without subscribe option" do
78
26
  before(:all) do
79
27
  @ib.send_message :RequestAccountData
80
- wait_for(5) { received? :AccountDownloadEnd }
28
+ @ib.wait_for 5, :AccountDownloadEnd
29
+ end
30
+
31
+ after(:all) do
32
+ @ib.send_message :RequestAccountData, :subscribe => false
33
+ clean_connection
81
34
  end
82
35
 
83
36
  it_behaves_like 'Valid account data request'