ib-ruby 0.7.6 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +8 -0
- data/Rakefile +8 -0
- data/VERSION +1 -1
- data/bin/fundamental_data +6 -9
- data/lib/ib-ruby/connection.rb +16 -19
- data/lib/ib-ruby/constants.rb +3 -1
- data/lib/ib-ruby/extensions.rb +5 -0
- data/lib/ib-ruby/messages/incoming/contract_data.rb +46 -45
- data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +8 -5
- data/lib/ib-ruby/messages/incoming/execution_data.rb +2 -2
- data/lib/ib-ruby/messages/incoming/next_valid_id.rb +18 -0
- data/lib/ib-ruby/messages/incoming/open_order.rb +23 -16
- data/lib/ib-ruby/messages/incoming/order_status.rb +5 -3
- data/lib/ib-ruby/messages/incoming/scanner_data.rb +15 -11
- data/lib/ib-ruby/messages/incoming.rb +1 -5
- data/lib/ib-ruby/messages/outgoing/abstract_message.rb +2 -1
- data/lib/ib-ruby/messages/outgoing/place_order.rb +1 -1
- data/lib/ib-ruby/messages/outgoing.rb +1 -1
- data/lib/ib-ruby/models/bag.rb +59 -0
- data/lib/ib-ruby/models/combo_leg.rb +10 -6
- data/lib/ib-ruby/models/contract.rb +278 -0
- data/lib/ib-ruby/models/contract_detail.rb +70 -0
- data/lib/ib-ruby/models/execution.rb +22 -16
- data/lib/ib-ruby/models/model.rb +75 -17
- data/lib/ib-ruby/models/model_properties.rb +40 -26
- data/lib/ib-ruby/models/option.rb +62 -0
- data/lib/ib-ruby/models/order.rb +122 -86
- data/lib/ib-ruby/models/order_state.rb +11 -12
- data/lib/ib-ruby/models/underlying.rb +36 -0
- data/lib/ib-ruby/models.rb +1 -4
- data/spec/account_helper.rb +2 -1
- data/spec/db.rb +1 -1
- data/spec/db_helper.rb +105 -0
- data/spec/ib-ruby/connection_spec.rb +3 -3
- data/spec/ib-ruby/messages/incoming/open_order_spec.rb +5 -5
- data/spec/ib-ruby/messages/incoming/order_status_spec.rb +3 -3
- data/spec/ib-ruby/models/bag_spec.rb +15 -23
- data/spec/ib-ruby/models/bar_spec.rb +0 -5
- data/spec/ib-ruby/models/combo_leg_spec.rb +18 -25
- data/spec/ib-ruby/models/contract_detail_spec.rb +54 -0
- data/spec/ib-ruby/models/contract_spec.rb +25 -37
- data/spec/ib-ruby/models/execution_spec.rb +64 -19
- data/spec/ib-ruby/models/option_spec.rb +12 -34
- data/spec/ib-ruby/models/order_spec.rb +107 -45
- data/spec/ib-ruby/models/order_state_spec.rb +12 -12
- data/spec/ib-ruby/models/underlying_spec.rb +36 -0
- data/spec/integration/contract_info_spec.rb +65 -55
- data/spec/integration/fundamental_data_spec.rb +2 -2
- data/spec/integration/orders/attached_spec.rb +3 -3
- data/spec/integration/orders/combo_spec.rb +3 -3
- data/spec/integration/orders/placement_spec.rb +8 -8
- data/spec/integration/orders/{execution_spec.rb → trades_spec.rb} +8 -12
- data/spec/integration/orders/valid_ids_spec.rb +3 -3
- data/spec/message_helper.rb +1 -1
- data/spec/model_helper.rb +150 -85
- data/spec/order_helper.rb +35 -18
- metadata +18 -10
- data/lib/ib-ruby/models/contracts/bag.rb +0 -62
- data/lib/ib-ruby/models/contracts/contract.rb +0 -320
- data/lib/ib-ruby/models/contracts/option.rb +0 -66
- 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
|
-
|
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
|
-
|
175
|
+
subject.default_attributes.each do |name, value|
|
176
|
+
#p name, value
|
43
177
|
case value
|
44
|
-
when
|
45
|
-
subject.send(name).should be_a
|
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
|
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
|
-
|
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
|
-
|
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 '
|
8
|
-
@
|
9
|
-
@
|
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
|
40
|
-
@ib.
|
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 '
|
86
|
-
@
|
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 @
|
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
|
119
|
-
@ib.
|
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
|
-
@
|
161
|
-
@
|
162
|
-
@
|
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.
|
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.
|
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.
|
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.
|
215
|
-
exec.
|
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.
|
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-
|
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.
|
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.
|
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/
|
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/
|
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
|