ib-ruby 0.7.4 → 0.7.6

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 (93) hide show
  1. data/.gitignore +3 -0
  2. data/HISTORY +8 -0
  3. data/README.md +2 -2
  4. data/Rakefile +15 -0
  5. data/TODO +7 -2
  6. data/VERSION +1 -1
  7. data/bin/account_info +1 -1
  8. data/bin/cancel_orders +1 -1
  9. data/bin/contract_details +1 -1
  10. data/bin/depth_of_market +1 -1
  11. data/bin/fa_accounts +1 -1
  12. data/bin/fundamental_data +42 -0
  13. data/bin/historic_data +1 -1
  14. data/bin/historic_data_cli +1 -1
  15. data/bin/list_orders +1 -2
  16. data/bin/market_data +1 -1
  17. data/bin/option_data +1 -1
  18. data/bin/place_combo_order +1 -1
  19. data/bin/place_order +1 -1
  20. data/bin/template +1 -4
  21. data/bin/tick_data +2 -2
  22. data/bin/time_and_sales +1 -1
  23. data/lib/ib-ruby.rb +4 -0
  24. data/lib/ib-ruby/connection.rb +50 -34
  25. data/lib/ib-ruby/constants.rb +232 -37
  26. data/lib/ib-ruby/db.rb +25 -0
  27. data/lib/ib-ruby/extensions.rb +51 -1
  28. data/lib/ib-ruby/messages/abstract_message.rb +0 -8
  29. data/lib/ib-ruby/messages/incoming.rb +18 -493
  30. data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
  31. data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
  32. data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
  33. data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
  34. data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
  35. data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
  36. data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
  37. data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
  38. data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
  39. data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
  40. data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
  41. data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
  42. data/lib/ib-ruby/messages/outgoing.rb +25 -223
  43. data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
  44. data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
  45. data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
  46. data/lib/ib-ruby/models.rb +4 -0
  47. data/lib/ib-ruby/models/bar.rb +31 -14
  48. data/lib/ib-ruby/models/combo_leg.rb +48 -23
  49. data/lib/ib-ruby/models/contracts.rb +2 -2
  50. data/lib/ib-ruby/models/contracts/bag.rb +11 -7
  51. data/lib/ib-ruby/models/contracts/contract.rb +90 -66
  52. data/lib/ib-ruby/models/contracts/option.rb +16 -7
  53. data/lib/ib-ruby/models/execution.rb +34 -18
  54. data/lib/ib-ruby/models/model.rb +15 -7
  55. data/lib/ib-ruby/models/model_properties.rb +101 -44
  56. data/lib/ib-ruby/models/order.rb +176 -187
  57. data/lib/ib-ruby/models/order_state.rb +99 -0
  58. data/lib/ib-ruby/symbols/forex.rb +10 -10
  59. data/lib/ib-ruby/symbols/futures.rb +6 -6
  60. data/lib/ib-ruby/symbols/stocks.rb +3 -3
  61. data/spec/account_helper.rb +4 -5
  62. data/spec/combo_helper.rb +4 -4
  63. data/spec/db.rb +18 -0
  64. data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
  65. data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
  66. data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
  67. data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
  68. data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
  69. data/spec/ib-ruby/models/bag_spec.rb +97 -0
  70. data/spec/ib-ruby/models/bar_spec.rb +45 -0
  71. data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
  72. data/spec/ib-ruby/models/contract_spec.rb +134 -170
  73. data/spec/ib-ruby/models/execution_spec.rb +35 -50
  74. data/spec/ib-ruby/models/option_spec.rb +127 -0
  75. data/spec/ib-ruby/models/order_spec.rb +89 -68
  76. data/spec/ib-ruby/models/order_state_spec.rb +55 -0
  77. data/spec/integration/contract_info_spec.rb +4 -6
  78. data/spec/integration/fundamental_data_spec.rb +41 -0
  79. data/spec/integration/historic_data_spec.rb +4 -4
  80. data/spec/integration/market_data_spec.rb +1 -3
  81. data/spec/integration/orders/attached_spec.rb +8 -10
  82. data/spec/integration/orders/combo_spec.rb +2 -2
  83. data/spec/integration/orders/execution_spec.rb +0 -1
  84. data/spec/integration/orders/placement_spec.rb +1 -3
  85. data/spec/integration/orders/valid_ids_spec.rb +1 -2
  86. data/spec/message_helper.rb +1 -1
  87. data/spec/model_helper.rb +211 -0
  88. data/spec/order_helper.rb +44 -37
  89. data/spec/spec_helper.rb +36 -23
  90. data/spec/v.rb +7 -0
  91. data/tasks/doc.rake +1 -1
  92. metadata +116 -12
  93. data/spec/integration/orders/open_order +0 -98
@@ -1,73 +1,58 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
2
 
3
3
  describe IB::Models::Execution do # AKA IB::Execution
4
4
 
5
- let(:properties) do
5
+ let(:props) do
6
6
  {:account_name => "DU111110",
7
- :average_price => 1.31075,
8
7
  :client_id => 1111,
9
- :cumulative_quantity => 20000,
10
8
  :exchange => "IDEALPRO",
11
9
  :exec_id => "0001f4e8.4f5d48f1.01.01",
12
- :liquidation => 0,
10
+ :liquidation => true,
13
11
  :order_id => 373,
14
- :perm_id => 1695693613,
12
+ :perm_id => 1695693619,
15
13
  :price => 1.31075,
14
+ :average_price => 1.31075,
16
15
  :shares => 20000,
16
+ :cumulative_quantity => 20000,
17
17
  :side => :buy,
18
18
  :time => "20120312 15:41:09"
19
19
  }
20
20
  end
21
21
 
22
- context "instantiation" do
23
- context 'empty without properties' do
24
- subject { IB::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
22
+ let(:human) do
23
+ "<Execution: 20120312 15:41:09 buy 20000 at 1.31075 on IDEALPRO, " +
24
+ "cumulative 20000 at 1.31075, ids 373/1695693619/0001f4e8.4f5d48f1.01.01>"
25
+ end
35
26
 
36
- context 'with properties' do
37
- subject { IB::Execution.new properties }
27
+ let(:defaults) do
28
+ {:order_id => 0,
29
+ :client_id => 0,
30
+ :perm_id => 0,
31
+ :shares=> 0,
32
+ :price => 0,
33
+ :liquidation => false,
34
+ :created_at => Time,
35
+ }
36
+ end
38
37
 
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
38
+ let(:errors) do
39
+ {:side=>["should be buy/sell/short"],
40
+ :cumulative_quantity=>["is not a number"],
41
+ :average_price=>["is not a number"]}
42
+ end
46
43
 
47
- context "properties" do
44
+ let(:assigns) do
45
+ {:side =>
46
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
47
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell},
48
48
 
49
- it 'allows setting properties' do
50
- expect {
51
- x = IB::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
49
+ [:shares, :cumulative_quantity, :price, :average_price] =>
50
+ {[:foo, 'BAR', nil] => /is not a number/},
58
51
 
59
- it 'sets side as directed by its setter' do
60
- @x = IB::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
52
+ :liquidation => {[1, true] => true, [0, false] => false},
53
+ }
54
+ end
65
55
 
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
56
+ it_behaves_like 'Model'
72
57
 
73
58
  end # describe IB::Models::Contract
@@ -0,0 +1,127 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::Contracts::Option do # AKA IB::Option
4
+
5
+ let(:props) do
6
+ {:symbol => 'AAPL',
7
+ :expiry => '201301',
8
+ :strike => 600,
9
+ :right => :put,
10
+ }
11
+ end
12
+
13
+ let(:human) do
14
+ "<Option: AAPL 201301 put 600 SMART >"
15
+ end
16
+
17
+ let(:defaults) do
18
+ {:sec_type => :option,
19
+ :con_id => 0,
20
+ :strike => 0,
21
+ :min_tick => 0,
22
+ :include_expired => false,
23
+ :created_at => Time,
24
+ }
25
+ end
26
+
27
+ let(:errors) do
28
+ {:right => ["should be put or call"],
29
+ :strike => ["must be greater than 0"],
30
+ }
31
+ end
32
+
33
+ let(:assigns) do
34
+ {:expiry =>
35
+ {[200609, '200609'] => '200609',
36
+ [20060913, '20060913'] => '20060913',
37
+ [:foo, 2006, 42, 'bar'] => /should be YYYYMM or YYYYMMDD/},
38
+
39
+ :sec_type =>
40
+ {['OPT', :option] => :option,
41
+ IB::CODES[:sec_type].reject { |k, v,| k == :option }.to_a =>
42
+ /should be an option/},
43
+
44
+ :right =>
45
+ {["PUT", "put", "P", "p", :put] => :put,
46
+ ["CALL", "call", "C", "c", :call] => :call,
47
+ ['', '0', '?', :none, :foo, 'BAR', 42] => /should be put or call/},
48
+
49
+ :exchange =>
50
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
51
+ [:smart, 'SMART', 'smArt'] => 'SMART'},
52
+
53
+ :primary_exchange =>
54
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
55
+ [:SMART, 'SMART'] => /should not be SMART/},
56
+
57
+ :symbol =>
58
+ {['AAPL', :AAPL] => 'AAPL'},
59
+
60
+ :local_symbol =>
61
+ {['AAPL 130119C00500000', :'AAPL 130119C00500000'] =>
62
+ 'AAPL 130119C00500000',
63
+ 'BAR'=> /invalid OSI code/},
64
+
65
+ :strike => {[0, -30.0] => /must be greater than 0/},
66
+
67
+ :multiplier => {['123', 123] => 123},
68
+
69
+ [:under_con_id, :min_tick, :coupon] => {123 => 123}
70
+
71
+ }
72
+ end
73
+
74
+ context 'using shorter class name without properties' do
75
+ subject { IB::Models::Option.new }
76
+ it_behaves_like 'Model instantiated empty'
77
+ end
78
+
79
+ context 'using shortest class name without properties' do
80
+ subject { IB::Option.new }
81
+ it_behaves_like 'Model instantiated empty'
82
+ end
83
+
84
+ it_behaves_like 'Model'
85
+ it_behaves_like 'Self-equal Model'
86
+
87
+ context 'properly initiated' do
88
+ subject { IB::Option.new props }
89
+ it_behaves_like 'Contract'
90
+
91
+ it 'has extra osi accessor, aliasing :local_symbol' do
92
+ subject.osi = 'FOO'
93
+ subject.local_symbol.should == 'FOO'
94
+ subject.local_symbol = 'bar'
95
+ subject.osi.should == 'bar'
96
+ end
97
+ end
98
+
99
+ it 'correctly defines Contract type (sec_type) for Option contract' do
100
+ [IB::Contract.new(:sec_type => :option),
101
+ IB::Contract.new(:sec_type => 'OPT'),
102
+ IB::Option.new
103
+ ].each do |contract|
104
+ contract.should_not be_bag
105
+ contract.should_not be_bond
106
+ contract.should_not be_stock
107
+ contract.should be_option
108
+ end
109
+ end
110
+
111
+ context '.from_osi class builder' do
112
+ subject { IB::Option.from_osi 'AAPL130119C00500000' }
113
+
114
+ it 'builds a valid Option contract from OSI code' do
115
+ subject.should be_an IB::Option
116
+ subject.should be_valid
117
+ subject.symbol.should == 'AAPL'
118
+ subject.expiry.should == '130118' # <- NB: Change in date!
119
+ subject.right.should == :call
120
+ subject.strike.should == 500
121
+ #subject.osi.should == 'AAPL 130119C00500000'
122
+ end
123
+
124
+ it_behaves_like 'Contract'
125
+ end
126
+
127
+ end # describe IB::Contract
@@ -1,116 +1,137 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
2
 
3
3
  describe IB::Models::Order do
4
4
 
5
- let(:properties) do
6
- {:outside_rth => true,
7
- :open_close => 'C',
8
- :origin => IB::Order::Origin_Firm,
9
- :transmit => false,
5
+ let(:props) do
6
+ {:order_id => 23,
7
+ :order_ref => 'Test',
8
+ :client_id => 1111,
9
+ :perm_id => 173276893,
10
+ :parent_id => 0,
11
+ :side => :buy,
12
+ :order_type => :market_if_touched,
13
+ :limit_price => 0.01,
14
+ :total_quantity => 100,
15
+ :tif => :good_till_cancelled,
16
+ :open_close => :close,
17
+ :oca_group => '',
18
+ :oca_type => :reduce_no_block,
19
+ :origin => :firm,
10
20
  :designated_location => "WHATEVER",
11
21
  :exempt_code => 123,
12
- :delta_neutral_order_type => "HACK",
22
+ :delta_neutral_order_type => :market,
23
+ #:commission_currency => "USD",
24
+ #:status => 'PreSubmitted',
25
+ :transmit => false,
26
+ :outside_rth => true,
13
27
  :what_if => true,
14
28
  :not_held => true}
15
29
  end
16
30
 
17
- context "instantiation" do
18
- context 'empty without properties' do
19
- subject { IB::Order.new }
20
-
21
- it { should_not be_nil }
22
- its(:outside_rth) { should == false }
23
- its(:open_close) { should == "O" }
24
- its(:origin) { should == IB::Order::Origin_Customer }
25
- its(:transmit) { should == true }
26
- its(:designated_location) { should == '' }
27
- its(:exempt_code) { should == -1 }
28
- its(:delta_neutral_order_type) { should == '' }
29
- its(:what_if) { should == false }
30
- its(:not_held) { should == false }
31
- its(:created_at) { should be_a Time }
32
- end
31
+ # TODO: :presents => { Object => "Formatted"}
32
+ let(:human) do
33
+ "<Order: Test MIT GTC buy 100 New 0.01 #23/173276893 from 1111>"
34
+ end
33
35
 
34
- context 'with properties' do
35
- subject { IB::Order.new properties }
36
+ let(:defaults) do
37
+ {:outside_rth => false,
38
+ :open_close => :open,
39
+ :short_sale_slot => :default,
40
+ :tif => :day,
41
+ :order_type => :limit,
42
+ :origin => :customer,
43
+ :transmit => true,
44
+ :designated_location => '',
45
+ :exempt_code => -1,
46
+ :what_if => false,
47
+ :not_held => false,
48
+ :status => 'New',
49
+ :created_at => Time,
50
+ }
51
+ end
36
52
 
37
- it 'sets properties right' do
38
- properties.each do |name, value|
39
- subject.send(name).should == value
40
- end
41
- end
53
+ let(:errors) do
54
+ {:side =>["should be buy/sell/short"],
55
+ :order_id => ["is not a number"], }
56
+ end
42
57
 
43
- context 'essential properties are still set, even if not given explicitely' do
44
- its(:created_at) { should be_a Time }
45
- end
46
- end
58
+ let(:assigns) do
59
+ {[:order_type, :delta_neutral_order_type] => codes_and_values_for(:order_type),
60
+ :open_close =>
61
+ {['SAME', 'same', 'S', 's', :same, 0, '0'] => :same,
62
+ ['OPEN', 'open', 'O', 'o', :open, 1, '1'] => :open,
63
+ ['CLOSE', 'close', 'C', 'c', :close, 2, '2'] => :close,
64
+ ['UNKNOWN', 'unknown', 'U', 'u', :unknown, 3, '3'] => :unknown,
65
+ [42, nil, 'Foo', :bar] => /should be same.open.close.unknown/},
66
+
67
+ :side =>
68
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
69
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell,
70
+ ['SSHORT', 'Short', 'short', :SHORT, :short, 'T', :T] => :short,
71
+ ['SSHORTX', 'Shortextemt', 'shortx', :short_exempt, 'X', :X] => :short_exempt,
72
+ [1, nil, 'ASK', :foo] => /should be buy.sell.short/, },
73
+
74
+ [:what_if, :not_held, :outside_rth, :hidden, :transmit, :block_order, :sweep_to_fill,
75
+ :override_percentage_constraints, :all_or_none, :etrade_only, :firm_quote_only,
76
+ :opt_out_smart_routing, :scale_auto_reset, :scale_random_percent
77
+ ] => {[1, true] => true, [0, false] => false},
78
+ }
79
+ end
47
80
 
48
- it 'allows setting attributes' do
49
- x = IB::Order.new
50
- properties.each do |name, value|
51
- subject.send("#{name}=", value)
52
- subject.send(name).should == value
53
- end
54
- end
55
- end #instantiation
81
+ it_behaves_like 'Model'
82
+ it_behaves_like 'Self-equal Model'
56
83
 
57
84
  context 'equality' do
58
- subject { IB::Order.new properties }
85
+ subject { IB::Order.new props }
59
86
 
60
- it 'is self-equal ' do
61
- should == subject
62
- end
63
-
64
- it 'is equal to Order with the same properties' do
65
- should == IB::Order.new(properties)
66
- end
87
+ it_behaves_like 'Self-equal Model'
67
88
 
68
89
  it 'is not equal for Orders with different limit price' do
69
90
  order1 = IB::Order.new :total_quantity => 100,
70
- :limit_price => 1,
71
- :action => 'BUY'
91
+ :limit_price => 1,
92
+ :action => 'BUY'
72
93
 
73
94
  order2 = IB::Order.new :total_quantity => 100,
74
- :limit_price => 2,
75
- :action => 'BUY'
95
+ :limit_price => 2,
96
+ :action => 'BUY'
76
97
  order1.should_not == order2
77
98
  order2.should_not == order1
78
99
  end
79
100
 
80
101
  it 'is not equal for Orders with different total_quantity' do
81
102
  order1 = IB::Order.new :total_quantity => 20000,
82
- :limit_price => 1,
83
- :action => 'BUY'
103
+ :limit_price => 1,
104
+ :action => 'BUY'
84
105
 
85
106
  order2 = IB::Order.new :total_quantity => 100,
86
- :action => 'BUY',
87
- :limit_price => 1
107
+ :action => 'BUY',
108
+ :limit_price => 1
88
109
  order1.should_not == order2
89
110
  order2.should_not == order1
90
111
  end
91
112
 
92
113
  it 'is not equal for Orders with different action/side' do
93
114
  order1 = IB::Order.new :total_quantity => 100,
94
- :limit_price => 1,
95
- :action => 'SELL'
115
+ :limit_price => 1,
116
+ :action => 'SELL'
96
117
 
97
118
  order2 = IB::Order.new :total_quantity => 100,
98
- :action => 'BUY',
99
- :limit_price => 1
119
+ :action => 'BUY',
120
+ :limit_price => 1
100
121
  order1.should_not == order2
101
122
  order2.should_not == order1
102
123
  end
103
124
 
104
125
  it 'is not equal for Orders with different order_type' do
105
126
  order1 = IB::Order.new :total_quantity => 100,
106
- :limit_price => 1,
107
- :action => 'BUY',
108
- :order_type => 'LMT'
127
+ :limit_price => 1,
128
+ :action => 'BUY',
129
+ :order_type => 'LMT'
109
130
 
110
131
  order2 = IB::Order.new :total_quantity => 100,
111
- :action => 'BUY',
112
- :limit_price => 1,
113
- :order_type => 'MKT'
132
+ :action => 'BUY',
133
+ :limit_price => 1,
134
+ :order_type => 'MKT'
114
135
  order1.should_not == order2
115
136
  order2.should_not == order1
116
137
  end
@@ -0,0 +1,55 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::OrderState do
4
+
5
+ let(:props) do
6
+ {:order_id => 23,
7
+ :perm_id => 173276893,
8
+ :client_id => 1111,
9
+ :parent_id => 0,
10
+ :filled => 3,
11
+ :remaining => 2,
12
+ :last_fill_price => 0.5,
13
+ :average_fill_price => 0.55,
14
+ :why_held => 'child',
15
+
16
+ :init_margin => 500.0,
17
+ :maint_margin => 500.0,
18
+ :equity_with_loan => 750.0,
19
+ :commission_currency => 'USD',
20
+ :commission => 1.2,
21
+ :min_commission => 1,
22
+ :max_commission => 1.5,
23
+ :status => 'PreSubmitted',
24
+ :warning_text => 'Oh noes!',
25
+ }
26
+ end
27
+
28
+ # TODO: :presents => { Object => "Formatted"}
29
+ let(:human) do
30
+ "<OrderState: PreSubmitted #23/173276893 from 1111 filled 3/2 at 0.5/0.55 margin 500.0/500.0 equity 750.0 fee 1.2 why_held child warning Oh noes!>"
31
+ end
32
+
33
+ let(:defaults) do
34
+ {:created_at => Time,
35
+ }
36
+ end
37
+
38
+ let(:errors) do
39
+ {:order_id => ["is not a number"],
40
+ :client_id => ["is not a number"],
41
+ :perm_id => ["is not a number"], }
42
+ end
43
+
44
+ let(:assigns) do
45
+ { :tester => {1 => 1},
46
+ [:order_id, :perm_id, :client_id] =>
47
+ {[:foo, 'bar'] => /is not a number/,
48
+ [5.0, 2006.17] => /must be an integer/, }
49
+ }
50
+ end
51
+
52
+ it_behaves_like 'Model'
53
+ it_behaves_like 'Self-equal Model'
54
+
55
+ end # describe IB::Order