ib-ruby 0.7.6 → 0.7.8

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 (61) hide show
  1. data/HISTORY +8 -0
  2. data/Rakefile +8 -0
  3. data/VERSION +1 -1
  4. data/bin/fundamental_data +6 -9
  5. data/lib/ib-ruby/connection.rb +16 -19
  6. data/lib/ib-ruby/constants.rb +3 -1
  7. data/lib/ib-ruby/extensions.rb +5 -0
  8. data/lib/ib-ruby/messages/incoming/contract_data.rb +46 -45
  9. data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +8 -5
  10. data/lib/ib-ruby/messages/incoming/execution_data.rb +2 -2
  11. data/lib/ib-ruby/messages/incoming/next_valid_id.rb +18 -0
  12. data/lib/ib-ruby/messages/incoming/open_order.rb +23 -16
  13. data/lib/ib-ruby/messages/incoming/order_status.rb +5 -3
  14. data/lib/ib-ruby/messages/incoming/scanner_data.rb +15 -11
  15. data/lib/ib-ruby/messages/incoming.rb +1 -5
  16. data/lib/ib-ruby/messages/outgoing/abstract_message.rb +2 -1
  17. data/lib/ib-ruby/messages/outgoing/place_order.rb +1 -1
  18. data/lib/ib-ruby/messages/outgoing.rb +1 -1
  19. data/lib/ib-ruby/models/bag.rb +59 -0
  20. data/lib/ib-ruby/models/combo_leg.rb +10 -6
  21. data/lib/ib-ruby/models/contract.rb +278 -0
  22. data/lib/ib-ruby/models/contract_detail.rb +70 -0
  23. data/lib/ib-ruby/models/execution.rb +22 -16
  24. data/lib/ib-ruby/models/model.rb +75 -17
  25. data/lib/ib-ruby/models/model_properties.rb +40 -26
  26. data/lib/ib-ruby/models/option.rb +62 -0
  27. data/lib/ib-ruby/models/order.rb +122 -86
  28. data/lib/ib-ruby/models/order_state.rb +11 -12
  29. data/lib/ib-ruby/models/underlying.rb +36 -0
  30. data/lib/ib-ruby/models.rb +1 -4
  31. data/spec/account_helper.rb +2 -1
  32. data/spec/db.rb +1 -1
  33. data/spec/db_helper.rb +105 -0
  34. data/spec/ib-ruby/connection_spec.rb +3 -3
  35. data/spec/ib-ruby/messages/incoming/open_order_spec.rb +5 -5
  36. data/spec/ib-ruby/messages/incoming/order_status_spec.rb +3 -3
  37. data/spec/ib-ruby/models/bag_spec.rb +15 -23
  38. data/spec/ib-ruby/models/bar_spec.rb +0 -5
  39. data/spec/ib-ruby/models/combo_leg_spec.rb +18 -25
  40. data/spec/ib-ruby/models/contract_detail_spec.rb +54 -0
  41. data/spec/ib-ruby/models/contract_spec.rb +25 -37
  42. data/spec/ib-ruby/models/execution_spec.rb +64 -19
  43. data/spec/ib-ruby/models/option_spec.rb +12 -34
  44. data/spec/ib-ruby/models/order_spec.rb +107 -45
  45. data/spec/ib-ruby/models/order_state_spec.rb +12 -12
  46. data/spec/ib-ruby/models/underlying_spec.rb +36 -0
  47. data/spec/integration/contract_info_spec.rb +65 -55
  48. data/spec/integration/fundamental_data_spec.rb +2 -2
  49. data/spec/integration/orders/attached_spec.rb +3 -3
  50. data/spec/integration/orders/combo_spec.rb +3 -3
  51. data/spec/integration/orders/placement_spec.rb +8 -8
  52. data/spec/integration/orders/{execution_spec.rb → trades_spec.rb} +8 -12
  53. data/spec/integration/orders/valid_ids_spec.rb +3 -3
  54. data/spec/message_helper.rb +1 -1
  55. data/spec/model_helper.rb +150 -85
  56. data/spec/order_helper.rb +35 -18
  57. metadata +18 -10
  58. data/lib/ib-ruby/models/contracts/bag.rb +0 -62
  59. data/lib/ib-ruby/models/contracts/contract.rb +0 -320
  60. data/lib/ib-ruby/models/contracts/option.rb +0 -66
  61. data/lib/ib-ruby/models/contracts.rb +0 -27
data/spec/model_helper.rb CHANGED
@@ -1,9 +1,137 @@
1
1
  require 'spec_helper'
2
+ require 'db_helper'
2
3
 
3
4
  def codes_and_values_for property
4
5
  Hash[IB::VALUES[property].map { |code, value| [[code, value], value] }]
5
6
  end
6
7
 
8
+ def numeric_assigns
9
+ {1313 => 1313,
10
+ [:foo, 'BAR'] => /is not a number/,
11
+ nil => /is not a number/}
12
+ end
13
+
14
+ def numeric_or_nil_assigns
15
+ numeric_assigns.merge(nil => nil)
16
+ end
17
+
18
+ def to_i_assigns
19
+ {[1313, '1313'] => 1313,
20
+ ['foo', 'BAR', nil, '', 0] => 0, } # Symbols NOT coerced! They DO have int equivalent
21
+ end
22
+
23
+ def float_assigns
24
+ {13.13 => 13.13,
25
+ 13 => 13.0,
26
+ nil => /is not a number/,
27
+ [:foo, 'BAR'] => /is not a number/}
28
+ end
29
+
30
+ def to_f_assigns
31
+ {13.13 => 13.13,
32
+ 13 => 13.0,
33
+ [:foo, 'BAR', '', nil, 0] => 0.0}
34
+ end
35
+
36
+ def float_or_nil_assigns
37
+ float_assigns.merge(nil => nil)
38
+ end
39
+
40
+ def boolean_assigns
41
+ {[1, true, 't'] => true,
42
+ [0, false, 'f'] => false}
43
+ end
44
+
45
+ def string_assigns
46
+ {[:Bar, 'Bar'] => 'Bar',
47
+ [:foo, 'foo'] => 'foo'}
48
+ end
49
+
50
+ def string_upcase_assigns
51
+ {[:cboe, :Cboe, 'cboE', 'CBOE'] => 'CBOE',
52
+ [:bar, 'Bar'] => 'BAR',
53
+ [:foo, 'foo'] => 'FOO'}
54
+ end
55
+
56
+ def open_close_assigns
57
+ {['SAME', 'same', 'S', 's', :same, 0, '0'] => :same,
58
+ ['OPEN', 'open', 'O', 'o', :open, 1, '1'] => :open,
59
+ ['CLOSE', 'close', 'C', 'c', :close, 2, '2'] => :close,
60
+ ['UNKNOWN', 'unknown', 'U', 'u', :unknown, 3, '3'] => :unknown,
61
+ [42, nil, 'Foo', :bar] => /should be same.open.close.unknown/}
62
+ end
63
+
64
+ def buy_sell_assigns
65
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
66
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell,
67
+ [1, nil, 'ASK', :foo] => /should be buy.sell/
68
+ }
69
+ end
70
+
71
+ def buy_sell_short_assigns
72
+ buy_sell_assigns.merge(
73
+ ['SSHORT', 'Short', 'short', :SHORT, :short, 'T', :T] => :short,
74
+ ['SSHORTX', 'Shortextemt', 'shortx', :short_exempt, 'X', :X] => :short_exempt,
75
+ [1, nil, 'ASK', :foo] => /should be buy.sell.short/)
76
+ end
77
+
78
+ def test_assigns cases, prop, name
79
+
80
+ # For all test cases given as an Array [res1, res2] or Hash {val => res} ...
81
+ (cases.is_a?(Array) ? cases.map { |e| [e, e] } : cases).each do |values, result|
82
+ #p prop, cases
83
+
84
+ # For all values in this test case ...
85
+ [values].flatten.each do |value|
86
+ #p prop, name, value, result
87
+
88
+ # Assigning this value to a property results in ...
89
+ case result
90
+ when Exception # ... Exception
91
+ expect { subject.send "#{prop}=", value }.
92
+ to raise_error result
93
+
94
+ when Regexp # ... Non-exceptional error, making model invalid
95
+ expect { subject.send "#{prop}=", value }.to_not raise_error
96
+ subject.valid? # just triggers validation
97
+
98
+ #pp subject.errors.messages
99
+
100
+ subject.errors.messages.should have_key name
101
+ subject.should be_invalid
102
+ msg = subject.errors.messages[name].find { |msg| msg =~ result }
103
+ msg.should =~ result
104
+
105
+ else # ... correct uniform assignment to result
106
+
107
+ was_valid = subject.valid?
108
+ expect { subject.send "#{prop}=", value }.to_not raise_error
109
+ subject.send("#{prop}").should == result
110
+ if was_valid
111
+ # Assignment keeps validity
112
+ subject.errors.messages.should_not have_key name
113
+ subject.should be_valid
114
+ end
115
+
116
+ if name != prop # additional asserts for aliases
117
+
118
+ # Assignment to alias changes property as well
119
+ subject.send("#{name}").should == result
120
+
121
+ # Unsetting alias unsets property as well
122
+ subject.send "#{prop}=", nil # unset alias
123
+ subject.send("#{prop}").should be_blank #== nil
124
+ subject.send("#{name}").should be_blank #== nil
125
+
126
+ # Assignment to original property changes alias as well
127
+ subject.send "#{name}=", value
128
+ subject.send("#{prop}").should == result
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+
7
135
  shared_examples_for 'Model' do
8
136
  context 'instantiation without properties' do
9
137
  subject { described_class.new }
@@ -18,7 +146,12 @@ shared_examples_for 'Model' do
18
146
 
19
147
 
20
148
  it 'has correct human-readeable format' do
21
- subject.to_human.should == human
149
+ case human
150
+ when Regexp
151
+ subject.to_human.should =~ human
152
+ else
153
+ subject.to_human.should == human
154
+ end
22
155
  end
23
156
  end
24
157
  end
@@ -39,10 +172,11 @@ shared_examples_for 'Model instantiated empty' do
39
172
  it { should_not be_nil }
40
173
 
41
174
  it 'sets all properties to defaults' do
42
- defined?(defaults) && defaults.each do |name, value|
175
+ subject.default_attributes.each do |name, value|
176
+ #p name, value
43
177
  case value
44
- when Module, Class
45
- subject.send(name).should be_a value
178
+ when Time
179
+ subject.send(name).should be_a Time
46
180
  else
47
181
  subject.send(name).should == value
48
182
  end
@@ -65,9 +199,6 @@ shared_examples_for 'Model instantiated with properties' do
65
199
  end
66
200
 
67
201
  shared_examples_for 'Model properties' do
68
- context 'essential properties are still set, even if not given explicitely' do
69
- its(:created_at) { should be_a Time }
70
- end
71
202
 
72
203
  it 'allows setting properties' do
73
204
  expect {
@@ -80,82 +211,33 @@ shared_examples_for 'Model properties' do
80
211
 
81
212
  it 'sets values to properties as directed by its setters' do
82
213
  defined?(assigns) && assigns.each do |props, cases|
83
- #p props, cases
84
-
85
214
  # For each given property ...
86
- [props].flatten.each do |prop|
87
-
88
- # For all test cases given as an Array [res1, res2] or Hash {val => res} ...
89
- (cases.is_a?(Array) ? cases.map { |e| [e, e] } : cases).each do |values, result|
215
+ [props].flatten.each { |prop| test_assigns cases, prop, prop }
90
216
 
91
- # For all values in this test case ...
92
- [values].flatten.each do |value|
93
-
94
- # Assigning this value to property results in ...
95
- case result
96
- when Exception # ... Exception
97
- expect { subject.send "#{prop}=", value }.
98
- to raise_error result
99
-
100
- when Regexp # ... Non-exceptional error, making model invalid
101
- expect { subject.send "#{prop}=", value }.to_not raise_error
102
- subject.should be_invalid
103
-
104
- #pp subject.errors.messages
105
- #p value, result
106
-
107
- subject.errors.messages[prop].should_not be_nil
108
- msg = subject.errors.messages[prop].find { |msg| msg =~ result }
109
- msg.should =~ result
110
-
111
- else # ... correct uniform assignment to result
112
-
113
- was_valid = subject.valid?
114
- expect { subject.send "#{prop}=", value }.to_not raise_error
115
- subject.send("#{prop}").should == result
116
-
117
- was_valid && (subject.should be_valid) # assignment keeps validity
118
- end
119
- end
120
- end
121
- end
122
217
  end
123
218
  end
124
219
 
220
+ it 'sets values to to aliased properties as well' do
221
+ defined?(aliases) && aliases.each do |alinames, cases|
222
+ name, aliases = *alinames
223
+ # For each original property or alias...
224
+ [name, aliases].flatten.each { |prop| test_assigns cases, prop, name }
225
+ end
226
+ end
125
227
  end
126
228
 
127
229
  shared_examples_for 'Valid Model' do
230
+
128
231
  it 'validates' do
129
- #subject.valid?
130
- #pp subject.errors.messages
131
232
  subject.should be_valid
132
233
  subject.errors.should be_empty
133
234
  end
134
235
 
135
- context 'with DB backend', :db => true do
136
- after(:all) do
137
- #DatabaseCleaner.clean
138
- end
139
-
140
- it 'is saved' do
141
- subject.save.should be_true
142
- end
143
-
144
- it 'is loaded just right' do
145
- models = described_class.find(:all)
146
- model = models.first
147
- #pp model
148
- models.should have_exactly(1).model
149
- model.should == subject
150
- model.should be_valid
151
- props.each do |name, value|
152
- model.send(name).should == value
153
- end
154
- end
155
- end # DB
236
+ it_behaves_like 'Valid DB-backed Model'
156
237
  end
157
238
 
158
239
  shared_examples_for 'Invalid Model' do
240
+
159
241
  it 'does not validate' do
160
242
  subject.should_not be_valid
161
243
  subject.should be_invalid
@@ -163,27 +245,10 @@ shared_examples_for 'Invalid Model' do
163
245
  subject.errors.messages.should == errors if defined? errors
164
246
  end
165
247
 
166
- context 'with DB backend', :db => true do
167
- after(:all) do
168
- #DatabaseCleaner.clean
169
- end
170
-
171
- it 'is not saved' do
172
- subject.save.should be_false
173
- end
174
-
175
- it 'is not loaded' do
176
- models = described_class.find(:all)
177
- models.should have_exactly(0).model
178
- end
179
- end # DB
248
+ it_behaves_like 'Invalid DB-backed Model'
180
249
  end
181
250
 
182
251
  shared_examples_for 'Contract' do
183
- it 'summary points to itself (ContractDetails artifact' do
184
- subject.summary.should == subject
185
- end
186
-
187
252
  it 'becomes invalid if assigned wrong :sec_type property' do
188
253
  subject.sec_type = 'FOO'
189
254
  subject.should be_invalid
data/spec/order_helper.rb CHANGED
@@ -4,9 +4,17 @@ shared_examples_for 'Placed Order' do
4
4
  context "Placing" do
5
5
  after(:all) { clean_connection } # Clear logs and message collector
6
6
 
7
- it 'changes client`s next_order_id' do
8
- @order_id_placed.should == @order_id_before
9
- @ib.next_order_id.should be >= @order_id_before
7
+ it 'sets placement-related properties' do
8
+ @order.placed_at.should be_a Time
9
+ @order.modified_at.should be_a Time
10
+ @order.placed_at.should == @order.modified_at
11
+ @order.local_id.should be_an Integer
12
+ @order.local_id.should == @local_id_before
13
+ end
14
+
15
+ it 'changes client`s next_local_id' do
16
+ @local_id_placed.should == @local_id_before
17
+ @ib.next_local_id.should be >= @local_id_before
10
18
  end
11
19
 
12
20
  it 'receives all appropriate response messages' do
@@ -25,6 +33,7 @@ shared_examples_for 'Placed Order' do
25
33
  order_should_be /Submit/, @attached_order
26
34
  end
27
35
  end
36
+
28
37
  end
29
38
  end # Placing
30
39
 
@@ -36,8 +45,8 @@ shared_examples_for 'Placed Order' do
36
45
 
37
46
  after(:all) { clean_connection } # Clear logs and message collector
38
47
 
39
- it 'does not increase client`s next_order_id further' do
40
- @ib.next_order_id.should == @order_id_after
48
+ it 'does not increase client`s next_local_id further' do
49
+ @ib.next_local_id.should == @local_id_after
41
50
  end
42
51
 
43
52
  it 'receives all appropriate response messages' do
@@ -50,6 +59,8 @@ shared_examples_for 'Placed Order' do
50
59
  order_should_be /Submitted/
51
60
  status_should_be /Submitted/
52
61
 
62
+ #pp @ib.received[:OpenOrder].first
63
+ #
53
64
  if @attached_order
54
65
  if contract_type == :butterfly && @attached_order.tif == :good_till_cancelled
55
66
  pending 'API Bug: Attached GTC orders not working for butterflies!'
@@ -82,8 +93,14 @@ shared_examples_for 'Placed Order' do
82
93
 
83
94
  after(:all) { clean_connection } # Clear logs and message collector
84
95
 
85
- it 'does not increase client`s next_order_id further' do
86
- @ib.next_order_id.should == @order_id_after
96
+ it 'sets placement-related properties' do
97
+ @order.modified_at.should be_a Time
98
+ @order.placed_at.should_not == @order.modified_at
99
+ end
100
+
101
+ it 'does not increase client`s or order`s local_id any more' do
102
+ @order.local_id.should == @local_id_before
103
+ @ib.next_local_id.should == @local_id_after
87
104
  end
88
105
 
89
106
  it 'receives all appropriate response messages' do
@@ -109,14 +126,14 @@ shared_examples_for 'Placed Order' do
109
126
 
110
127
  context "Cancelling placed order" do
111
128
  before(:all) do
112
- @ib.cancel_order @order_id_placed
129
+ @ib.cancel_order @local_id_placed
113
130
  @ib.wait_for [:OrderStatus, 3], :Alert
114
131
  end
115
132
 
116
133
  after(:all) { clean_connection } # Clear logs and message collector
117
134
 
118
- it 'does not increase client`s next_order_id further' do
119
- @ib.next_order_id.should == @order_id_after
135
+ it 'does not increase client`s next_local_id further' do
136
+ @ib.next_local_id.should == @local_id_after
120
137
  end
121
138
 
122
139
  it 'only receives OpenOrder message with PendingCancel' do
@@ -157,20 +174,20 @@ def place_order contract, opts = {}
157
174
  :limit_price => 9.13,
158
175
  :action => 'BUY',
159
176
  :order_type => 'LMT'}.merge(opts))
160
- @order_id_before = @ib.next_order_id
161
- @order_id_placed = @ib.place_order @order, @contract
162
- @order_id_after = @ib.next_order_id
177
+ @local_id_before = @ib.next_local_id
178
+ @local_id_placed = @ib.place_order @order, @contract
179
+ @local_id_after = @ib.next_local_id
163
180
  end
164
181
 
165
182
  def status_should_be status, order=@order
166
183
  msg = @ib.received[:OrderStatus].find do |msg|
167
- msg.order_id == order.order_id &&
184
+ msg.local_id == order.local_id &&
168
185
  status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
169
186
  end
170
187
  msg.should_not be_nil
171
188
  msg.should be_an IB::Messages::Incoming::OrderStatus
172
189
  order_state = msg.order_state
173
- order_state.order_id.should == order.order_id
190
+ order_state.local_id.should == order.local_id
174
191
  order_state.perm_id.should be_an Integer
175
192
  order_state.client_id.should == OPTS[:connection][:client_id]
176
193
  order_state.parent_id.should == 0 unless @attached_order
@@ -193,7 +210,7 @@ end
193
210
 
194
211
  def order_should_be status, order=@order
195
212
  msg = @ib.received[:OpenOrder].find do |msg|
196
- msg.order_id == order.order_id &&
213
+ msg.local_id == order.local_id &&
197
214
  status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
198
215
  end
199
216
  msg.should_not be_nil
@@ -211,8 +228,8 @@ def execution_should_be side, opts={}
211
228
  exec.perm_id.should be_an Integer
212
229
  exec.perm_id.should == @ib.received[:OpenOrder].last.order.perm_id if @ib.received?(:OpenOrder)
213
230
  exec.client_id.should == OPTS[:connection][:client_id]
214
- exec.order_id.should be_an Integer
215
- exec.order_id.should == @order.order_id if @order
231
+ exec.local_id.should be_an Integer
232
+ exec.local_id.should == @order.local_id if @order
216
233
  exec.exec_id.should be_a String
217
234
  exec.time.should =~ /\d\d:\d\d:\d\d/
218
235
  exec.account_name.should == OPTS[:connection][:account_name]
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: ib-ruby
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.7.6
5
+ version: 0.7.8
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-04-18 00:00:00 Z
14
+ date: 2012-04-23 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -21,7 +21,7 @@ dependencies:
21
21
  requirements:
22
22
  - - ">="
23
23
  - !ruby/object:Gem::Version
24
- version: 1.0.20
24
+ version: 1.1.3
25
25
  type: :runtime
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - ">="
100
100
  - !ruby/object:Gem::Version
101
- version: 2.8.0
101
+ version: 2.9.0
102
102
  type: :development
103
103
  version_requirements: *id008
104
104
  - !ruby/object:Gem::Dependency
@@ -176,6 +176,7 @@ files:
176
176
  - lib/ib-ruby/messages/incoming/execution_data.rb
177
177
  - lib/ib-ruby/messages/incoming/historical_data.rb
178
178
  - lib/ib-ruby/messages/incoming/market_depths.rb
179
+ - lib/ib-ruby/messages/incoming/next_valid_id.rb
179
180
  - lib/ib-ruby/messages/incoming/open_order.rb
180
181
  - lib/ib-ruby/messages/incoming/order_status.rb
181
182
  - lib/ib-ruby/messages/incoming/portfolio_value.rb
@@ -185,17 +186,18 @@ files:
185
186
  - lib/ib-ruby/messages/outgoing/abstract_message.rb
186
187
  - lib/ib-ruby/messages/outgoing/bar_requests.rb
187
188
  - lib/ib-ruby/messages/outgoing/place_order.rb
189
+ - lib/ib-ruby/models/bag.rb
188
190
  - lib/ib-ruby/models/bar.rb
189
191
  - lib/ib-ruby/models/combo_leg.rb
190
- - lib/ib-ruby/models/contracts.rb
192
+ - lib/ib-ruby/models/contract.rb
193
+ - lib/ib-ruby/models/contract_detail.rb
191
194
  - lib/ib-ruby/models/execution.rb
192
195
  - lib/ib-ruby/models/model.rb
193
196
  - lib/ib-ruby/models/model_properties.rb
197
+ - lib/ib-ruby/models/option.rb
194
198
  - lib/ib-ruby/models/order.rb
195
199
  - lib/ib-ruby/models/order_state.rb
196
- - lib/ib-ruby/models/contracts/bag.rb
197
- - lib/ib-ruby/models/contracts/contract.rb
198
- - lib/ib-ruby/models/contracts/option.rb
200
+ - lib/ib-ruby/models/underlying.rb
199
201
  - lib/ib-ruby/symbols/forex.rb
200
202
  - lib/ib-ruby/symbols/futures.rb
201
203
  - lib/ib-ruby/symbols/options.rb
@@ -203,6 +205,7 @@ files:
203
205
  - spec/account_helper.rb
204
206
  - spec/combo_helper.rb
205
207
  - spec/db.rb
208
+ - spec/db_helper.rb
206
209
  - spec/integration_helper.rb
207
210
  - spec/message_helper.rb
208
211
  - spec/model_helper.rb
@@ -220,11 +223,13 @@ files:
220
223
  - spec/ib-ruby/models/bag_spec.rb
221
224
  - spec/ib-ruby/models/bar_spec.rb
222
225
  - spec/ib-ruby/models/combo_leg_spec.rb
226
+ - spec/ib-ruby/models/contract_detail_spec.rb
223
227
  - spec/ib-ruby/models/contract_spec.rb
224
228
  - spec/ib-ruby/models/execution_spec.rb
225
229
  - spec/ib-ruby/models/option_spec.rb
226
230
  - spec/ib-ruby/models/order_spec.rb
227
231
  - spec/ib-ruby/models/order_state_spec.rb
232
+ - spec/ib-ruby/models/underlying_spec.rb
228
233
  - spec/integration/account_info_spec.rb
229
234
  - spec/integration/contract_info_spec.rb
230
235
  - spec/integration/depth_data_spec.rb
@@ -234,8 +239,8 @@ files:
234
239
  - spec/integration/option_data_spec.rb
235
240
  - spec/integration/orders/attached_spec.rb
236
241
  - spec/integration/orders/combo_spec.rb
237
- - spec/integration/orders/execution_spec.rb
238
242
  - spec/integration/orders/placement_spec.rb
243
+ - spec/integration/orders/trades_spec.rb
239
244
  - spec/integration/orders/valid_ids_spec.rb
240
245
  - tasks/common.rake
241
246
  - tasks/doc.rake
@@ -281,6 +286,7 @@ test_files:
281
286
  - spec/account_helper.rb
282
287
  - spec/combo_helper.rb
283
288
  - spec/db.rb
289
+ - spec/db_helper.rb
284
290
  - spec/integration_helper.rb
285
291
  - spec/message_helper.rb
286
292
  - spec/model_helper.rb
@@ -298,11 +304,13 @@ test_files:
298
304
  - spec/ib-ruby/models/bag_spec.rb
299
305
  - spec/ib-ruby/models/bar_spec.rb
300
306
  - spec/ib-ruby/models/combo_leg_spec.rb
307
+ - spec/ib-ruby/models/contract_detail_spec.rb
301
308
  - spec/ib-ruby/models/contract_spec.rb
302
309
  - spec/ib-ruby/models/execution_spec.rb
303
310
  - spec/ib-ruby/models/option_spec.rb
304
311
  - spec/ib-ruby/models/order_spec.rb
305
312
  - spec/ib-ruby/models/order_state_spec.rb
313
+ - spec/ib-ruby/models/underlying_spec.rb
306
314
  - spec/integration/account_info_spec.rb
307
315
  - spec/integration/contract_info_spec.rb
308
316
  - spec/integration/depth_data_spec.rb
@@ -312,7 +320,7 @@ test_files:
312
320
  - spec/integration/option_data_spec.rb
313
321
  - spec/integration/orders/attached_spec.rb
314
322
  - spec/integration/orders/combo_spec.rb
315
- - spec/integration/orders/execution_spec.rb
316
323
  - spec/integration/orders/placement_spec.rb
324
+ - spec/integration/orders/trades_spec.rb
317
325
  - spec/integration/orders/valid_ids_spec.rb
318
326
  has_rdoc:
@@ -1,62 +0,0 @@
1
- require 'ib-ruby/models/contracts/contract'
2
-
3
- module IB
4
- module Models
5
- module Contracts
6
-
7
- # "BAG" is not really a contract, but a combination (combo) of securities.
8
- # AKA basket or bag of securities. Individual securities in combo are represented
9
- # by ComboLeg objects.
10
- class Bag < Contract
11
- # General Notes:
12
- # 1. :exchange for the leg definition must match that of the combination order.
13
- # The exception is for a STK legs, which must specify the SMART exchange.
14
- # 2. :symbol => "USD" For combo Contract, this is an arbitrary value (like "USD")
15
-
16
- validates_format_of :sec_type, :with => /^bag$/, :message => "should be a bag"
17
- validates_format_of :right, :with => /^none$/, :message => "should be none"
18
- validates_format_of :expiry, :with => /^$/, :message => "should be blank"
19
- validate :legs_cannot_be_empty
20
-
21
- def legs_cannot_be_empty
22
- errors.add(:legs, "legs cannot be empty") if legs.empty?
23
- end
24
-
25
- def initialize opts = {}
26
- @legs = Array.new
27
- self.sec_type = :bag
28
- super opts
29
- end
30
-
31
- def description
32
- self[:description] || to_human
33
- end
34
-
35
- def to_human
36
- "<Bag: #{[symbol, exchange, currency].join(' ')} legs: #{legs_description} >"
37
- end
38
-
39
- ### Leg-related methods
40
- # TODO: Rewrite with legs and legs_description being strictly in sync...
41
-
42
- # TODO: Find a way to serialize legs without references...
43
- # IB-equivalent leg description.
44
- def legs_description
45
- self[:legs_description] || legs.map { |leg| "#{leg.con_id}|#{leg.weight}" }.join(',')
46
- end
47
-
48
- # Check if two Contracts have same legs (maybe in different order)
49
- def same_legs? other
50
- legs == other.legs ||
51
- legs_description.split(',').sort == other.legs_description.split(',').sort
52
- end
53
-
54
- # Contract comparison
55
- def == other
56
- super && same_legs?(other)
57
- end
58
-
59
- end # class Bag
60
- end # Contracts
61
- end # Models
62
- end # IB