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.
Files changed (50) hide show
  1. data/HISTORY +4 -0
  2. data/README.md +25 -17
  3. data/VERSION +1 -1
  4. data/bin/account_info +1 -1
  5. data/bin/cancel_orders +2 -1
  6. data/bin/contract_details +3 -2
  7. data/bin/depth_of_market +1 -1
  8. data/bin/historic_data +1 -1
  9. data/bin/historic_data_cli +57 -104
  10. data/bin/list_orders +4 -3
  11. data/bin/market_data +1 -1
  12. data/bin/option_data +1 -1
  13. data/bin/place_combo_order +63 -0
  14. data/bin/place_order +2 -4
  15. data/bin/template +1 -1
  16. data/bin/{generic_data.rb → tick_data} +3 -1
  17. data/bin/time_and_sales +1 -1
  18. data/lib/ib-ruby.rb +1 -0
  19. data/lib/ib-ruby/connection.rb +68 -68
  20. data/lib/ib-ruby/errors.rb +28 -0
  21. data/lib/ib-ruby/extensions.rb +7 -0
  22. data/lib/ib-ruby/messages.rb +1 -0
  23. data/lib/ib-ruby/messages/abstract_message.rb +16 -11
  24. data/lib/ib-ruby/messages/incoming.rb +125 -329
  25. data/lib/ib-ruby/messages/incoming/open_order.rb +193 -0
  26. data/lib/ib-ruby/messages/incoming/ticks.rb +131 -0
  27. data/lib/ib-ruby/messages/outgoing.rb +44 -45
  28. data/lib/ib-ruby/models/combo_leg.rb +16 -1
  29. data/lib/ib-ruby/models/contract.rb +18 -10
  30. data/lib/ib-ruby/models/contract/bag.rb +1 -7
  31. data/lib/ib-ruby/models/execution.rb +2 -1
  32. data/lib/ib-ruby/models/model.rb +1 -1
  33. data/lib/ib-ruby/models/order.rb +116 -56
  34. data/lib/ib-ruby/socket.rb +24 -3
  35. data/spec/account_helper.rb +2 -1
  36. data/spec/ib-ruby/messages/outgoing_spec.rb +1 -1
  37. data/spec/ib-ruby/models/combo_leg_spec.rb +0 -1
  38. data/spec/integration/account_info_spec.rb +2 -2
  39. data/spec/integration/contract_info_spec.rb +4 -4
  40. data/spec/integration/depth_data_spec.rb +3 -3
  41. data/spec/integration/historic_data_spec.rb +1 -1
  42. data/spec/integration/market_data_spec.rb +4 -4
  43. data/spec/integration/option_data_spec.rb +1 -1
  44. data/spec/integration/orders/combo_spec.rb +51 -0
  45. data/spec/integration/orders/execution_spec.rb +15 -8
  46. data/spec/integration/orders/placement_spec.rb +46 -72
  47. data/spec/integration/orders/valid_ids_spec.rb +6 -6
  48. data/spec/integration_helper.rb +0 -79
  49. data/spec/order_helper.rb +153 -0
  50. metadata +13 -4
@@ -4,7 +4,12 @@ module IB
4
4
  class IBSocket < TCPSocket
5
5
 
6
6
  # send nice null terminated binary data into socket
7
- def send data
7
+ def write_data data
8
+ # TWS wants to receive booleans as 1 or 0
9
+ data = "1" if data == true
10
+ data = "0" if data == false
11
+
12
+ #p data.to_s + EOL
8
13
  self.syswrite(data.to_s + EOL)
9
14
  end
10
15
 
@@ -26,11 +31,12 @@ module IB
26
31
 
27
32
  def read_int_max
28
33
  str = self.read_string
29
- str.nil? || str.empty? ? nil : str.to_i
34
+ str.to_i unless str.nil? || str.empty?
30
35
  end
31
36
 
32
37
  def read_boolean
33
- self.read_string.to_i != 0
38
+ str = self.read_string
39
+ str.nil? ? false : str.to_i != 0
34
40
  end
35
41
 
36
42
  def read_decimal
@@ -60,6 +66,21 @@ module IB
60
66
  def read_decimal_limit_2
61
67
  read_decimal_limit -2
62
68
  end
69
+
70
+ ### Complex operations
71
+
72
+ # Returns loaded Array or [] if count was 0
73
+ def read_array &block
74
+ count = read_int
75
+ count > 0 ? Array.new(count, &block) : []
76
+ end
77
+
78
+ # Returns loaded Hash
79
+ def read_hash
80
+ tags = read_array { |_| [read_string, read_string] }
81
+ tags.empty? ? Hash.new : Hash[*tags.flatten]
82
+ end
83
+
63
84
  end # class IBSocket
64
85
 
65
86
  end # module IB
@@ -16,7 +16,8 @@ def verify_account
16
16
  @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
17
17
  @ib.send_message :RequestAccountData, :subscribe => true
18
18
 
19
- @ib.wait_for 3, :AccountValue
19
+ @ib.wait_for :AccountDownloadEnd
20
+ @ib.send_message :RequestAccountData, :subscribe => false
20
21
  raise "Unable to verify IB PAPER ACCOUNT" unless @ib.received?(:AccountValue)
21
22
 
22
23
  received = @ib.received[:AccountValue].first.account_name
@@ -25,7 +25,7 @@ describe IB::Messages::Outgoing do
25
25
  end
26
26
 
27
27
  it 'encodes into Array' do
28
- subject.encode.should == [6, 2, true, "DUH"]
28
+ subject.encode(:server_version => 60).should == [6, 2, true, "DUH"]
29
29
  end
30
30
 
31
31
  end
@@ -19,7 +19,6 @@ describe IB::Models::ComboLeg do
19
19
 
20
20
  it { should_not be_nil }
21
21
  its(:con_id) {should == 0}
22
- its(:ratio) {should == 0}
23
22
  its(:open_close) {should == 0}
24
23
  its(:short_sale_slot) {should == 0}
25
24
  its(:designated_location) {should == ''}
@@ -12,7 +12,7 @@ describe "Request Account Data", :connected => true, :integration => true do
12
12
  context "with subscribe option set" do
13
13
  before(:all) do
14
14
  @ib.send_message :RequestAccountData, :subscribe => true
15
- @ib.wait_for 5, :AccountDownloadEnd
15
+ @ib.wait_for :AccountDownloadEnd, 5 # sec
16
16
  end
17
17
  after(:all) do
18
18
  @ib.send_message :RequestAccountData, :subscribe => false
@@ -25,7 +25,7 @@ describe "Request Account Data", :connected => true, :integration => true do
25
25
  context "without subscribe option" do
26
26
  before(:all) do
27
27
  @ib.send_message :RequestAccountData
28
- @ib.wait_for 5, :AccountDownloadEnd
28
+ @ib.wait_for :AccountDownloadEnd, 5 # sec
29
29
  end
30
30
 
31
31
  after(:all) do
@@ -16,7 +16,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
16
16
  @contract = IB::Models::Contract.new :symbol => 'AAPL',
17
17
  :sec_type => IB::SECURITY_TYPES[:stock]
18
18
  @ib.send_message :RequestContractData, :id => 111, :contract => @contract
19
- @ib.wait_for 3, :ContractDataEnd
19
+ @ib.wait_for :ContractDataEnd, 3 # sec
20
20
  end
21
21
 
22
22
  after(:all) { clean_connection } # Clear logs and message collector
@@ -66,7 +66,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
66
66
  :right => "CALL",
67
67
  :strike => 500
68
68
  @ib.send_message :RequestContractData, :id => 123, :contract => @contract
69
- @ib.wait_for 3, :ContractDataEnd
69
+ @ib.wait_for :ContractDataEnd, 3 # sec
70
70
  end
71
71
 
72
72
  after(:all) { clean_connection } # Clear logs and message collector
@@ -112,7 +112,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
112
112
  :exchange => "IDEALPRO",
113
113
  :sec_type => IB::SECURITY_TYPES[:forex]
114
114
  @ib.send_message :RequestContractData, :id => 135, :contract => @contract
115
- @ib.wait_for 3, :ContractDataEnd
115
+ @ib.wait_for :ContractDataEnd, 3 # sec
116
116
  end
117
117
 
118
118
  after(:all) { clean_connection } # Clear logs and message collector
@@ -155,7 +155,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
155
155
  before(:all) do
156
156
  @contract = IB::Symbols::Futures[:ym] # Mini Dow Jones Industrial
157
157
  @ib.send_message :RequestContractData, :id => 147, :contract => @contract
158
- @ib.wait_for 3, :ContractDataEnd
158
+ @ib.wait_for :ContractDataEnd, 3 # sec
159
159
  end
160
160
 
161
161
  after(:all) { clean_connection } # Clear logs and message collector
@@ -10,7 +10,7 @@ describe 'Request Depth of Market Data', :connected => true,
10
10
  @ib.send_message :RequestMarketDepth, :id => 456, :num_rows => 3,
11
11
  :contract => IB::Symbols::Forex[:eurusd]
12
12
 
13
- @ib.wait_for 10, [:MarketDepth, 8]
13
+ @ib.wait_for [:MarketDepth, 4], 6 # sec
14
14
  end
15
15
 
16
16
  after(:all) do
@@ -20,7 +20,7 @@ describe 'Request Depth of Market Data', :connected => true,
20
20
 
21
21
  subject { @ib.received[:MarketDepth].last }
22
22
 
23
- it { @ib.received[:MarketDepth].should have_at_least(8).depth_data }
23
+ it { @ib.received[:MarketDepth].should have_at_least(4).depth_data }
24
24
 
25
25
  it { should be_an IB::Messages::Incoming::MarketDepth }
26
26
  its(:request_id) { should == 456 }
@@ -30,7 +30,7 @@ describe 'Request Depth of Market Data', :connected => true,
30
30
 
31
31
  it 'has position field reflecting the row Id of this market depth entry' do
32
32
  subject.position.should be_an Integer
33
- subject.position.should be >= 1
33
+ subject.position.should be >= 0
34
34
  subject.position.should be <= 3
35
35
  end
36
36
 
@@ -37,7 +37,7 @@ describe 'Request Historic Data', :connected => true, :integration => true do
37
37
  before(:all) do
38
38
  # No historical data for GBP/CASH@IDEALPRO
39
39
  @ib.send_message :RequestHistoricalData, CORRECT_OPTS
40
- @ib.wait_for 5, :HistoricalData
40
+ @ib.wait_for :HistoricalData, 5 # sec
41
41
  end
42
42
 
43
43
  subject { @ib.received[:HistoricalData].last }
@@ -19,7 +19,7 @@ describe 'Request Market Data', :connected => true, :integration => true do
19
19
  :description => "Apple"
20
20
  )
21
21
  @ib.send_message :RequestMarketData, :id => 456, :contract => @contract
22
- @ib.wait_for 5, :TickSize, :TickString
22
+ @ib.wait_for :TickSize, :TickString, 3 # sec
23
23
  end
24
24
 
25
25
  after(:all) do
@@ -48,12 +48,12 @@ describe 'Request Market Data', :connected => true, :integration => true do
48
48
  before(:all) do
49
49
  @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
50
50
 
51
- ##TODO consider a follow the sun market lookup for windening the types tested
51
+ ##TODO consider a follow the sun market lookup for widening the types tested
52
52
  @ib.subscribe(:Alert, :TickPrice, :TickSize) {}
53
53
  @ib.send_message :RequestMarketData, :id => 456,
54
54
  :contract => IB::Symbols::Forex[:eurusd]
55
55
 
56
- @ib.wait_for 3, :TickPrice, :TickSize
56
+ @ib.wait_for :TickPrice, :TickSize, 3 # sec
57
57
  end
58
58
 
59
59
  after(:all) do
@@ -84,7 +84,7 @@ describe 'Request Market Data', :connected => true, :integration => true do
84
84
 
85
85
  @ib.send_message :RequestMarketData, :id => 456,
86
86
  :contract => IB::Symbols::Forex[:eurusd]
87
- @ib.wait_for 3, :TickPrice, :TickSize
87
+ @ib.wait_for :TickPrice, :TickSize, 3 # sec
88
88
  end
89
89
 
90
90
  after(:all) do
@@ -9,7 +9,7 @@ describe 'Request Market Data for Options', :if => :us_trading_hours,
9
9
 
10
10
  @ib.send_message :RequestMarketData, :id => 456,
11
11
  :contract => IB::Symbols::Options[:aapl500]
12
- @ib.wait_for 5, :TickPrice, :TickSize, :TickString, :TickOption
12
+ @ib.wait_for :TickPrice, :TickSize, :TickString, :TickOption, 5 # sec
13
13
  end
14
14
 
15
15
  after(:all) do
@@ -0,0 +1,51 @@
1
+ require 'order_helper'
2
+
3
+ #OPTS[:silent] = false
4
+
5
+ def butterfly symbol, expiry, right, *strikes
6
+ raise 'No Connection!' unless @ib && @ib.connected?
7
+
8
+ legs = strikes.zip([1, -2, 1]).map do |strike, weight|
9
+ # Create contract
10
+ contract = IB::Models::Contract::Option.new :symbol => symbol,
11
+ :expiry => expiry,
12
+ :right => right,
13
+ :strike => strike
14
+ # Find out contract's con_id
15
+ @ib.clear_received :ContractData, :ContractDataEnd
16
+ @ib.send_message :RequestContractData, :id => strike, :contract => contract
17
+ @ib.wait_for :ContractDataEnd, 3
18
+ con_id = @ib.received[:ContractData].last.contract.con_id
19
+
20
+ # Create Comboleg from con_id and weight
21
+ IB::Models::ComboLeg.new :con_id => con_id, :weight => weight
22
+ end
23
+
24
+ # Create new Combo contract
25
+ IB::Models::Contract::Bag.new :symbol => symbol,
26
+ :currency => "USD", # Only US options in combo Contracts
27
+ :exchange => "SMART",
28
+ :legs => legs
29
+ end
30
+
31
+ describe "Combo Order", :connected => true, :integration => true do
32
+
33
+ before(:all) { verify_account }
34
+
35
+ context "Limit" do # , :if => :us_trading_hours
36
+ before(:all) do
37
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
38
+ @ib.wait_for :NextValidId
39
+ @ib.clear_received # to avoid conflict with pre-existing Orders
40
+
41
+ @combo = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
42
+
43
+ place_order @combo, :limit_price => 0.01 #, :what_if => true
44
+ @ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2], 5
45
+ end
46
+
47
+ after(:all) { close_connection }
48
+
49
+ it_behaves_like 'Placed Order'
50
+ end # Limit
51
+ end # Combo Orders
@@ -1,5 +1,6 @@
1
- require 'integration_helper'
1
+ require 'order_helper'
2
2
 
3
+ #OPTS[:silent] = false
3
4
  describe "Trades", :connected => true, :integration => true, :slow => true do
4
5
 
5
6
  before(:all) { verify_account }
@@ -21,9 +22,15 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
21
22
  :total_quantity => 20000,
22
23
  :limit_price => 2,
23
24
  :action => 'BUY'
25
+ #:all_or_none => 1,
26
+ #:fa_profile => 2,
27
+ #:percent_offset => 3,
28
+ #:clearing_account => 'z',
29
+ #:what_if => true
24
30
 
25
31
  @ib.wait_for(5, :ExecutionData, :OpenOrder) do
26
- @ib.received[:OpenOrder].last.order.commission
32
+ @ib.received[:OpenOrder].last &&
33
+ @ib.received[:OpenOrder].last.order.commission
27
34
  end
28
35
  end
29
36
 
@@ -43,7 +50,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
43
50
  it { @ib.received[:ExecutionDataEnd].should be_empty }
44
51
 
45
52
  it 'receives filled OpenOrder' do
46
- open_order_should_be 'Filled', -1
53
+ order_should_be 'Filled', -1
47
54
  msg = @ib.received[:OpenOrder].last
48
55
  msg.order.commission.should == 2.5
49
56
  end
@@ -53,7 +60,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
53
60
  end
54
61
 
55
62
  it 'receives OrderStatus with fill details' do
56
- order_status_should_be 'Filled', -1
63
+ status_should_be 'Filled', -1
57
64
  end
58
65
  end # Placing BUY
59
66
 
@@ -65,7 +72,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
65
72
  :limit_price => 1,
66
73
  :action => 'SELL'
67
74
 
68
- @ib.wait_for(5, :ExecutionData, :OpenOrder) do
75
+ @ib.wait_for(:ExecutionData, :OpenOrder, 5) do
69
76
  @ib.received[:OpenOrder].last.order.commission
70
77
  end
71
78
  end
@@ -85,7 +92,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
85
92
  it { @ib.received[:ExecutionData].should have_exactly(1).execution_data }
86
93
 
87
94
  it 'receives filled OpenOrder' do
88
- open_order_should_be 'Filled', -1
95
+ order_should_be 'Filled', -1
89
96
  msg = @ib.received[:OpenOrder].last
90
97
  msg.order.commission.should == 2.5
91
98
  end
@@ -95,7 +102,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
95
102
  end
96
103
 
97
104
  it 'receives OrderStatus with fill details' do
98
- order_status_should_be 'Filled', -1
105
+ status_should_be 'Filled', -1
99
106
  end
100
107
  end # Placing SELL
101
108
 
@@ -107,7 +114,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
107
114
  :request_id => 456,
108
115
  :client_id => OPTS[:connection][:client_id],
109
116
  :time => (Time.now-10).to_ib # Time zone problems possible
110
- @ib.wait_for 3, :ExecutionData
117
+ @ib.wait_for :ExecutionData, 3 # sec
111
118
  end
112
119
 
113
120
  #after(:all) { clean_connection }
@@ -1,19 +1,19 @@
1
- require 'integration_helper'
1
+ require 'order_helper'
2
2
 
3
- describe "Orders", :connected => true, :integration => true do
3
+ #OPTS[:silent] = false
4
+ describe 'Orders', :connected => true, :integration => true do
4
5
 
5
6
  before(:all) { verify_account }
6
7
 
7
- context "Placing wrong order", :slow => true do
8
+ context 'Placing wrong order', :slow => true do
8
9
 
9
10
  before(:all) do
10
11
  @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
11
-
12
12
  @ib.wait_for :NextValidId
13
13
 
14
14
  place_order IB::Symbols::Stocks[:wfc],
15
15
  :limit_price => 9.131313 # Weird non-acceptable price
16
- @ib.wait_for 1
16
+ @ib.wait_for 1 # sec
17
17
  end
18
18
 
19
19
  after(:all) { close_connection }
@@ -39,88 +39,62 @@ describe "Orders", :connected => true, :integration => true do
39
39
 
40
40
  end # Placing wrong order
41
41
 
42
- context "Off-market stock order" do
42
+ context 'What-if order' do
43
43
  before(:all) do
44
44
  @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
45
45
  @ib.wait_for :NextValidId
46
46
 
47
47
  place_order IB::Symbols::Stocks[:wfc],
48
- :limit_price => 9.13 # Set acceptable price
49
- @ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2]
48
+ :limit_price => 9.13, # Set acceptable price
49
+ :what_if => true # Hypothetical
50
+ @ib.wait_for 1
50
51
  end
51
52
 
52
53
  after(:all) { close_connection }
53
54
 
54
- context "Placing" do
55
- after(:all) { clean_connection } # Clear logs and message collector
56
-
57
- it 'changes client`s next_order_id' do
58
- @order_id_placed.should == @order_id_before
59
- @ib.next_order_id.should == @order_id_before + 1
60
- end
61
-
62
- it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
63
- it { @ib.received[:OrderStatus].should have_at_least(1).status_message }
64
-
65
- it 'receives confirmation of Order submission' do
66
- open_order_should_be /Submitted/ # ()Pre)Submitted
67
- order_status_should_be /Submitted/
68
- end
69
- end # Placing
70
-
71
- context "Retrieving placed orders" do
72
- before(:all) do
73
- @ib.send_message :RequestOpenOrders
74
- @ib.wait_for :OpenOrderEnd
75
- end
76
-
77
- after(:all) { clean_connection } # Clear logs and message collector
78
-
79
- it 'does not increase client`s next_order_id further' do
80
- @ib.next_order_id.should == @order_id_after
81
- end
82
-
83
- it { @ib.received[:OpenOrder].should have_exactly(1).open_order_message }
84
- it { @ib.received[:OrderStatus].should have_exactly(1).status_message }
85
- it { @ib.received[:OpenOrderEnd].should have_exactly(1).order_end_message }
86
- it { @ib.received[:Alert].should have_exactly(0).alert_messages }
87
-
88
- it 'receives OpenOrder and OrderStatus for placed order' do
89
- open_order_should_be /Submitted/
90
- order_status_should_be /Submitted/
91
- end
92
- end # Retrieving
93
-
94
- context "Cancelling placed order" do
95
- before(:all) do
96
- @ib.cancel_order @order_id_placed
97
-
98
- @ib.wait_for :OrderStatus, :Alert
99
- end
55
+ it 'changes client`s next_order_id' do
56
+ @order_id_placed.should == @order_id_before
57
+ @ib.next_order_id.should == @order_id_before + 1
58
+ end
100
59
 
101
- after(:all) { clean_connection } # Clear logs and message collector
60
+ it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
61
+ it { @ib.received[:OrderStatus].should have_exactly(0).status_messages }
62
+
63
+ it 'returns as what-if Order with margin and commission info' do
64
+ order_should_be /PreSubmitted/
65
+ order = @ib.received[:OpenOrder].first.order
66
+ order.what_if.should == true
67
+ order.equity_with_loan.should be_a Float
68
+ order.init_margin.should be_a Float
69
+ order.maint_margin.should be_a Float
70
+ order.commission.should be_a Float
71
+ order.equity_with_loan.should be > 0
72
+ order.init_margin.should be > 0
73
+ order.maint_margin.should be > 0
74
+ order.commission.should be > 1
75
+ end
102
76
 
103
- it 'does not increase client`s next_order_id further' do
104
- @ib.next_order_id.should == @order_id_after
105
- end
77
+ it 'is not actually opened though' do
78
+ @ib.clear_received
79
+ @ib.send_message :RequestOpenOrders
80
+ @ib.wait_for :OpenOrderEnd
81
+ @ib.received[:OpenOrder].should have_exactly(0).order_message
82
+ end
83
+ end
106
84
 
107
- it 'does not receive OpenOrder message' do
108
- @ib.received?(:OpenOrder).should be_false
109
- end
85
+ context 'Off-market stock order' do
86
+ before(:all) do
87
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
88
+ @ib.wait_for :NextValidId
110
89
 
111
- it { @ib.received[:OrderStatus].should have_exactly(1).status_message }
112
- it { @ib.received[:Alert].should have_exactly(1).alert_message }
90
+ place_order IB::Symbols::Stocks[:wfc],
91
+ :limit_price => 9.13 # Set acceptable price
92
+ @ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2]
93
+ end
113
94
 
114
- it 'receives cancellation Order Status' do
115
- order_status_should_be /Cancel/ # Cancelled / PendingCancel
116
- end
95
+ after(:all) { close_connection }
117
96
 
118
- it 'receives Order cancelled Alert' do
119
- alert = @ib.received[:Alert].first
120
- alert.should be_an IB::Messages::Incoming::Alert
121
- alert.message.should =~ /Order Canceled - reason:/
122
- end
123
- end # Cancelling
97
+ it_behaves_like 'Placed Order'
124
98
 
125
99
  context "Cancelling wrong order" do
126
100
  before(:all) do