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.
- 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
|