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
@@ -3,15 +3,15 @@ require 'model_helper'
|
|
3
3
|
describe IB::Models::Order do
|
4
4
|
|
5
5
|
let(:props) do
|
6
|
-
{:
|
6
|
+
{:local_id => 23,
|
7
7
|
:order_ref => 'Test',
|
8
8
|
:client_id => 1111,
|
9
9
|
:perm_id => 173276893,
|
10
10
|
:parent_id => 0,
|
11
11
|
:side => :buy,
|
12
12
|
:order_type => :market_if_touched,
|
13
|
-
:limit_price => 0.
|
14
|
-
:
|
13
|
+
:limit_price => 0.1,
|
14
|
+
:quantity => 100,
|
15
15
|
:tif => :good_till_cancelled,
|
16
16
|
:open_close => :close,
|
17
17
|
:oca_group => '',
|
@@ -20,8 +20,6 @@ describe IB::Models::Order do
|
|
20
20
|
:designated_location => "WHATEVER",
|
21
21
|
:exempt_code => 123,
|
22
22
|
:delta_neutral_order_type => :market,
|
23
|
-
#:commission_currency => "USD",
|
24
|
-
#:status => 'PreSubmitted',
|
25
23
|
:transmit => false,
|
26
24
|
:outside_rth => true,
|
27
25
|
:what_if => true,
|
@@ -30,64 +28,128 @@ describe IB::Models::Order do
|
|
30
28
|
|
31
29
|
# TODO: :presents => { Object => "Formatted"}
|
32
30
|
let(:human) do
|
33
|
-
"<Order: Test MIT GTC buy 100 New 0.
|
34
|
-
end
|
35
|
-
|
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
|
-
}
|
31
|
+
"<Order: Test MIT GTC buy 100 New 0.1 #23/173276893 from 1111>"
|
51
32
|
end
|
52
33
|
|
53
34
|
let(:errors) do
|
54
|
-
{:side =>["should be buy/sell/short"]
|
55
|
-
:order_id => ["is not a number"], }
|
35
|
+
{:side =>["should be buy/sell/short"]}
|
56
36
|
end
|
57
37
|
|
58
38
|
let(:assigns) do
|
59
39
|
{[:order_type, :delta_neutral_order_type] => codes_and_values_for(:order_type),
|
40
|
+
|
60
41
|
:open_close =>
|
61
|
-
{[
|
42
|
+
{[42, nil, 'Foo', :bar] => /should be same.open.close.unknown/,
|
43
|
+
['SAME', 'same', 'S', 's', :same, 0, '0'] => :same,
|
62
44
|
['OPEN', 'open', 'O', 'o', :open, 1, '1'] => :open,
|
63
45
|
['CLOSE', 'close', 'C', 'c', :close, 2, '2'] => :close,
|
64
46
|
['UNKNOWN', 'unknown', 'U', 'u', :unknown, 3, '3'] => :unknown,
|
65
|
-
|
66
|
-
|
67
|
-
:
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
47
|
+
},
|
48
|
+
|
49
|
+
[:what_if, :not_held, :outside_rth, :hidden, :transmit, :block_order,
|
50
|
+
:sweep_to_fill, :override_percentage_constraints, :all_or_none,
|
51
|
+
:etrade_only, :firm_quote_only, :opt_out_smart_routing, :scale_auto_reset,
|
52
|
+
:scale_random_percent] => boolean_assigns,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
let(:aliases) do
|
57
|
+
{[:side, :action] => buy_sell_short_assigns,
|
58
|
+
[:local_id, :order_id] => numeric_or_nil_assigns,
|
59
|
+
[:quantity, :total_quantity] => numeric_or_nil_assigns,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:associations) do
|
64
|
+
{:order_states => [IB::OrderState.new(:status => :Foo),
|
65
|
+
IB::OrderState.new(:status => 'Bar'),],
|
66
|
+
|
67
|
+
:executions => [IB::Execution.new(:local_id => 23,
|
68
|
+
:client_id => 1111,
|
69
|
+
:perm_id => 173276893,
|
70
|
+
:exchange => "IDEALPRO",
|
71
|
+
:exec_id => "0001f4e8.4f5d48f1.01.01",
|
72
|
+
:price => 0.1,
|
73
|
+
:average_price => 0.1,
|
74
|
+
:shares => 40,
|
75
|
+
:cumulative_quantity => 40,
|
76
|
+
:side => :buy,
|
77
|
+
:time => "20120312 15:41:09"),
|
78
|
+
IB::Execution.new(:local_id => 23,
|
79
|
+
:client_id => 1111,
|
80
|
+
:perm_id => 173276893,
|
81
|
+
:exchange => "IDEALPRO",
|
82
|
+
:exec_id => "0001f4e8.4f5d48f1.01.02",
|
83
|
+
:price => 0.1,
|
84
|
+
:average_price => 0.1,
|
85
|
+
:shares => 60,
|
86
|
+
:cumulative_quantity => 100,
|
87
|
+
:side => :buy,
|
88
|
+
:time => "20120312 15:41:10")]
|
78
89
|
}
|
79
90
|
end
|
80
91
|
|
81
92
|
it_behaves_like 'Model'
|
82
93
|
it_behaves_like 'Self-equal Model'
|
83
94
|
|
95
|
+
context 'Order associations' do
|
96
|
+
after(:all) { DatabaseCleaner.clean }
|
97
|
+
|
98
|
+
subject { IB::Order.new props }
|
99
|
+
|
100
|
+
it 'has order_states collection' do
|
101
|
+
subject.order_states.should_not be_nil
|
102
|
+
subject.order_states.should be_an Array # lies, it's more like association proxy
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'has at least one (initial, New) OrderState' do
|
106
|
+
subject.order_states.should have_exactly(1).state
|
107
|
+
last_state = subject.order_states.last
|
108
|
+
last_state.should be_an IB::OrderState
|
109
|
+
last_state.status.should == 'New'
|
110
|
+
subject.save
|
111
|
+
last_state.order.should == subject if IB::DB
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'has abbreviated accessor to last (current) OrderState' do
|
115
|
+
subject.order_state.should == subject.order_states.last
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'has extra accessors to OrderState properties' do
|
119
|
+
subject.order_state.should_not be_nil
|
120
|
+
subject.status.should == 'New'
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'update Order state by ' do
|
124
|
+
|
125
|
+
it 'either adding new State to order_states ' do
|
126
|
+
subject.order_states << IB::OrderState.new(:status => :Foo)
|
127
|
+
subject.order_states.push IB::OrderState.new :status => :Bar
|
128
|
+
|
129
|
+
subject.status.should == 'Bar'
|
130
|
+
subject.save
|
131
|
+
subject.order_states.should have_exactly(3).states
|
132
|
+
subject.order_states.first.order.should == subject if IB::DB
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'or simply assigning to order_state accessor' do
|
136
|
+
subject.order_state = :Foo
|
137
|
+
subject.order_state = IB::OrderState.new :status => :Bar
|
138
|
+
|
139
|
+
subject.status.should == 'Bar'
|
140
|
+
subject.order_states.should have_exactly(3).states
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
84
146
|
context 'equality' do
|
85
147
|
subject { IB::Order.new props }
|
86
148
|
|
87
149
|
it_behaves_like 'Self-equal Model'
|
88
150
|
|
89
151
|
it 'is not equal for Orders with different limit price' do
|
90
|
-
order1 = IB::Order.new :
|
152
|
+
order1 = IB::Order.new :quantity => 100,
|
91
153
|
:limit_price => 1,
|
92
154
|
:action => 'BUY'
|
93
155
|
|
@@ -99,7 +161,7 @@ describe IB::Models::Order do
|
|
99
161
|
end
|
100
162
|
|
101
163
|
it 'is not equal for Orders with different total_quantity' do
|
102
|
-
order1 = IB::Order.new :
|
164
|
+
order1 = IB::Order.new :quantity => 20000,
|
103
165
|
:limit_price => 1,
|
104
166
|
:action => 'BUY'
|
105
167
|
|
@@ -111,11 +173,11 @@ describe IB::Models::Order do
|
|
111
173
|
end
|
112
174
|
|
113
175
|
it 'is not equal for Orders with different action/side' do
|
114
|
-
order1 = IB::Order.new :
|
176
|
+
order1 = IB::Order.new :quantity => 100,
|
115
177
|
:limit_price => 1,
|
116
178
|
:action => 'SELL'
|
117
179
|
|
118
|
-
order2 = IB::Order.new :
|
180
|
+
order2 = IB::Order.new :quantity => 100,
|
119
181
|
:action => 'BUY',
|
120
182
|
:limit_price => 1
|
121
183
|
order1.should_not == order2
|
@@ -123,12 +185,12 @@ describe IB::Models::Order do
|
|
123
185
|
end
|
124
186
|
|
125
187
|
it 'is not equal for Orders with different order_type' do
|
126
|
-
order1 = IB::Order.new :
|
188
|
+
order1 = IB::Order.new :quantity => 100,
|
127
189
|
:limit_price => 1,
|
128
190
|
:action => 'BUY',
|
129
191
|
:order_type => 'LMT'
|
130
192
|
|
131
|
-
order2 = IB::Order.new :
|
193
|
+
order2 = IB::Order.new :quantity => 100,
|
132
194
|
:action => 'BUY',
|
133
195
|
:limit_price => 1,
|
134
196
|
:order_type => 'MKT'
|
@@ -3,7 +3,7 @@ require 'model_helper'
|
|
3
3
|
describe IB::Models::OrderState do
|
4
4
|
|
5
5
|
let(:props) do
|
6
|
-
{:
|
6
|
+
{:local_id => 23,
|
7
7
|
:perm_id => 173276893,
|
8
8
|
:client_id => 1111,
|
9
9
|
:parent_id => 0,
|
@@ -30,22 +30,22 @@ describe IB::Models::OrderState do
|
|
30
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
31
|
end
|
32
32
|
|
33
|
-
let(:
|
34
|
-
{:
|
33
|
+
let(:errors) do
|
34
|
+
{:status => ["must not be empty"],
|
35
35
|
}
|
36
36
|
end
|
37
37
|
|
38
|
-
let(:
|
39
|
-
{:
|
40
|
-
|
41
|
-
|
38
|
+
let(:assigns) do
|
39
|
+
{[:status] =>
|
40
|
+
{[nil, ''] => /must not be empty/,
|
41
|
+
['Zorro', :Zorro] => 'Zorro' }
|
42
|
+
}
|
42
43
|
end
|
43
44
|
|
44
|
-
let(:
|
45
|
-
{
|
46
|
-
|
47
|
-
|
48
|
-
[5.0, 2006.17] => /must be an integer/, }
|
45
|
+
let(:aliases) do
|
46
|
+
{[:local_id, :order_id] => numeric_or_nil_assigns,
|
47
|
+
[:price, :last_fill_price] => float_or_nil_assigns,
|
48
|
+
[:average_price, :average_fill_price] => float_or_nil_assigns,
|
49
49
|
}
|
50
50
|
end
|
51
51
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'model_helper'
|
2
|
+
|
3
|
+
describe IB::Models::Underlying do # AKA IB::Underlying
|
4
|
+
|
5
|
+
let(:props) do
|
6
|
+
{:con_id => 234567,
|
7
|
+
:delta => 0.55,
|
8
|
+
:price => 20.5,
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:human) do
|
13
|
+
/<Underlying: con_id: 234567 .*delta: 0.55 price: 20.5.*>/
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:errors) do
|
17
|
+
{:delta => ['is not a number'],
|
18
|
+
:price => ['is not a number'],
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:assigns) do
|
23
|
+
{[:con_id, :delta, :price] => numeric_assigns,
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it_behaves_like 'Model'
|
28
|
+
it_behaves_like 'Self-equal Model'
|
29
|
+
|
30
|
+
context 'using shortest class name without properties' do
|
31
|
+
subject { IB::Underlying.new }
|
32
|
+
it_behaves_like 'Model instantiated empty'
|
33
|
+
it_behaves_like 'Self-equal Model'
|
34
|
+
end
|
35
|
+
|
36
|
+
end # describe IB::Contract
|
@@ -16,6 +16,8 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
16
16
|
@contract = IB::Contract.new :symbol => 'AAPL', :sec_type => :stock
|
17
17
|
@ib.send_message :RequestContractData, :id => 111, :contract => @contract
|
18
18
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
19
|
+
# java: 15:33:16:159 <- 9-6-111-0-AAPL-STK--0.0--- ---0-- -
|
20
|
+
# ruby: 15:36:15:736 <- 9-6-111-0-AAPL-STK--0.0---SMART--- --0-
|
19
21
|
end
|
20
22
|
|
21
23
|
after(:all) { clean_connection } # Clear logs and message collector
|
@@ -34,24 +36,26 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
34
36
|
|
35
37
|
@ib.received[:ContractData].each do |msg|
|
36
38
|
contract = msg.contract
|
37
|
-
|
39
|
+
detail = msg.contract_detail
|
38
40
|
|
41
|
+
contract.symbol.should == 'AAPL'
|
39
42
|
contract.local_symbol.should =~ /AAPL|APC/
|
40
|
-
contract.market_name.should =~ /NMS|USSTARS/
|
41
|
-
contract.trading_class.should =~ /NMS|USSTARS/
|
42
|
-
contract.long_name.should == 'APPLE INC'
|
43
|
-
contract.industry.should == 'Technology'
|
44
|
-
contract.category.should == 'Computers'
|
45
|
-
contract.subcategory.should == 'Computers'
|
46
|
-
contract.exchange.should == 'SMART'
|
47
43
|
contract.con_id.should be_an Integer
|
48
|
-
contract.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
49
|
-
contract.liquid_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
50
|
-
contract.valid_exchanges.should =~ /ISLAND|IBIS/
|
51
|
-
contract.order_types.should be_a String
|
52
|
-
contract.price_magnifier.should == 1
|
53
|
-
contract.min_tick.should be <= 0.01
|
54
44
|
contract.expiry.should == ''
|
45
|
+
contract.exchange.should == 'SMART'
|
46
|
+
|
47
|
+
detail.market_name.should =~ /NMS|USSTARS/
|
48
|
+
detail.trading_class.should =~ /NMS|USSTARS/
|
49
|
+
detail.long_name.should == 'APPLE INC'
|
50
|
+
detail.industry.should == 'Technology'
|
51
|
+
detail.category.should == 'Computers'
|
52
|
+
detail.subcategory.should == 'Computers'
|
53
|
+
detail.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
54
|
+
detail.liquid_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
55
|
+
detail.valid_exchanges.should =~ /ISLAND|IBIS/
|
56
|
+
detail.order_types.should be_a String
|
57
|
+
detail.price_magnifier.should == 1
|
58
|
+
detail.min_tick.should be <= 0.01
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end # Stock
|
@@ -60,9 +64,9 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
60
64
|
|
61
65
|
before(:all) do
|
62
66
|
@contract = IB::Option.new :symbol => "AAPL", :expiry => "201301",
|
63
|
-
:right =>
|
67
|
+
:right => :call, :strike => 500
|
64
68
|
@ib.send_message :RequestContractData, :id => 123, :contract => @contract
|
65
|
-
@ib.wait_for :ContractDataEnd,
|
69
|
+
@ib.wait_for :ContractDataEnd, 5 # sec
|
66
70
|
end
|
67
71
|
|
68
72
|
after(:all) { clean_connection } # Clear logs and message collector
|
@@ -79,24 +83,26 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
79
83
|
|
80
84
|
it 'receives Contract Data with extended fields' do
|
81
85
|
contract = subject.contract
|
82
|
-
|
86
|
+
detail = subject.contract_detail
|
83
87
|
|
88
|
+
contract.symbol.should == 'AAPL'
|
84
89
|
contract.local_symbol.should == 'AAPL 130119C00500000'
|
85
|
-
contract.market_name.should == 'AAPL'
|
86
|
-
contract.trading_class.should == 'AAPL'
|
87
|
-
contract.long_name.should == 'APPLE INC'
|
88
|
-
contract.industry.should == 'Technology'
|
89
|
-
contract.category.should == 'Computers'
|
90
|
-
contract.subcategory.should == 'Computers'
|
91
90
|
contract.expiry.should == '20130118'
|
92
91
|
contract.exchange.should == 'SMART'
|
93
92
|
contract.con_id.should be_an Integer
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
|
94
|
+
detail.market_name.should == 'AAPL'
|
95
|
+
detail.trading_class.should == 'AAPL'
|
96
|
+
detail.long_name.should == 'APPLE INC'
|
97
|
+
detail.industry.should == 'Technology'
|
98
|
+
detail.category.should == 'Computers'
|
99
|
+
detail.subcategory.should == 'Computers'
|
100
|
+
detail.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
101
|
+
detail.liquid_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
102
|
+
detail.valid_exchanges.should =~ /CBOE/
|
103
|
+
detail.order_types.should be_a String
|
104
|
+
detail.price_magnifier.should == 1
|
105
|
+
detail.min_tick.should == 0.01
|
100
106
|
end
|
101
107
|
end # Request Option data
|
102
108
|
|
@@ -125,24 +131,26 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
125
131
|
|
126
132
|
it 'receives Contract Data with extended fields' do
|
127
133
|
contract = subject.contract
|
128
|
-
|
134
|
+
detail = subject.contract_detail
|
129
135
|
|
136
|
+
contract.symbol.should == 'EUR'
|
130
137
|
contract.local_symbol.should == 'EUR.USD'
|
131
|
-
contract.market_name.should == 'EUR.USD'
|
132
|
-
contract.trading_class.should == 'EUR.USD'
|
133
|
-
contract.long_name.should == 'European Monetary Union euro'
|
134
|
-
contract.industry.should == ''
|
135
|
-
contract.category.should == ''
|
136
|
-
contract.subcategory.should == ''
|
137
138
|
contract.expiry.should == ''
|
138
139
|
contract.exchange.should == 'IDEALPRO'
|
139
140
|
contract.con_id.should be_an Integer
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
141
|
+
|
142
|
+
detail.market_name.should == 'EUR.USD'
|
143
|
+
detail.trading_class.should == 'EUR.USD'
|
144
|
+
detail.long_name.should == 'European Monetary Union euro'
|
145
|
+
detail.industry.should == ''
|
146
|
+
detail.category.should == ''
|
147
|
+
detail.subcategory.should == ''
|
148
|
+
detail.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
149
|
+
detail.liquid_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
150
|
+
detail.valid_exchanges.should =~ /IDEALPRO/
|
151
|
+
detail.order_types.should be_a String
|
152
|
+
detail.price_magnifier.should == 1
|
153
|
+
detail.min_tick.should be <= 0.0001
|
146
154
|
end
|
147
155
|
end # Request Forex data
|
148
156
|
|
@@ -168,24 +176,26 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
168
176
|
|
169
177
|
it 'receives Contract Data with extended fields' do
|
170
178
|
contract = subject.contract
|
171
|
-
|
179
|
+
detail = subject.contract_detail
|
172
180
|
|
181
|
+
contract.symbol.should == 'YM'
|
173
182
|
contract.local_symbol.should =~ /YM/
|
174
|
-
contract.market_name.should == 'YM'
|
175
|
-
contract.trading_class.should == 'YM'
|
176
|
-
contract.long_name.should == 'Mini Sized Dow Jones Industrial Average $5'
|
177
|
-
contract.industry.should == ''
|
178
|
-
contract.category.should == ''
|
179
|
-
contract.subcategory.should == ''
|
180
183
|
contract.expiry.should =~ Regexp.new(IB::Symbols.next_expiry)
|
181
184
|
contract.exchange.should == 'ECBOT'
|
182
185
|
contract.con_id.should be_an Integer
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
186
|
+
|
187
|
+
detail.market_name.should == 'YM'
|
188
|
+
detail.trading_class.should == 'YM'
|
189
|
+
detail.long_name.should == 'Mini Sized Dow Jones Industrial Average $5'
|
190
|
+
detail.industry.should == ''
|
191
|
+
detail.category.should == ''
|
192
|
+
detail.subcategory.should == ''
|
193
|
+
detail.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
194
|
+
detail.liquid_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
195
|
+
detail.valid_exchanges.should =~ /ECBOT/
|
196
|
+
detail.order_types.should be_a String
|
197
|
+
detail.price_magnifier.should == 1
|
198
|
+
detail.min_tick.should == 1
|
189
199
|
end
|
190
200
|
end # Request Forex data
|
191
201
|
end # Contract Data
|
@@ -17,7 +17,7 @@ describe 'Request Fundamental Data',
|
|
17
17
|
:contract => @contract,
|
18
18
|
:report_type => 'snapshot' # 'estimates', 'finstat'
|
19
19
|
|
20
|
-
@ib.wait_for :FundamentalData,
|
20
|
+
@ib.wait_for :FundamentalData, 10 # sec
|
21
21
|
end
|
22
22
|
|
23
23
|
after(:all) do
|
@@ -32,7 +32,7 @@ describe 'Request Fundamental Data',
|
|
32
32
|
its(:request_id) { should == 456 }
|
33
33
|
its(:data) { should be_a String }
|
34
34
|
|
35
|
-
it 'responds with XML with
|
35
|
+
it 'responds with XML with relevant data' do
|
36
36
|
require 'xmlsimple'
|
37
37
|
data_xml = XmlSimple.xml_in(subject.data, 'ForceArray' => false) #, 'ContentKey' => 'content')
|
38
38
|
name = data_xml["CoIDs"]["CoID"].find {|tag| tag['Type'] == 'CompanyName'}['content']
|
@@ -61,10 +61,10 @@ describe 'Attached Orders', :connected => true, :integration => true do
|
|
61
61
|
:side => :sell,
|
62
62
|
:tif => tif,
|
63
63
|
:order_type => attach_type,
|
64
|
-
:parent_id => @
|
64
|
+
:parent_id => @local_id_placed
|
65
65
|
|
66
|
-
@
|
67
|
-
@
|
66
|
+
@local_id_attached = @ib.place_order @attached_order, @contract
|
67
|
+
@local_id_after = @ib.next_local_id
|
68
68
|
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 3], 4
|
69
69
|
end
|
70
70
|
|
@@ -25,9 +25,9 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
25
25
|
|
26
26
|
after(:all) { close_connection }
|
27
27
|
|
28
|
-
it 'changes client`s
|
29
|
-
@
|
30
|
-
@ib.
|
28
|
+
it 'changes client`s next_local_id' do
|
29
|
+
@local_id_placed.should == @local_id_before
|
30
|
+
@ib.next_local_id.should == @local_id_before + 1
|
31
31
|
end
|
32
32
|
|
33
33
|
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
@@ -23,9 +23,9 @@ describe 'Orders', :connected => true, :integration => true do
|
|
23
23
|
@ib.received[:OrderStatus].should be_empty
|
24
24
|
end
|
25
25
|
|
26
|
-
it 'still changes client`s
|
27
|
-
@
|
28
|
-
@ib.
|
26
|
+
it 'still changes client`s next_local_id' do
|
27
|
+
@local_id_placed.should == @local_id_before
|
28
|
+
@ib.next_local_id.should == @local_id_before + 1
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'received :Alert message' do
|
@@ -52,9 +52,9 @@ describe 'Orders', :connected => true, :integration => true do
|
|
52
52
|
|
53
53
|
after(:all) { close_connection }
|
54
54
|
|
55
|
-
it 'changes client`s
|
56
|
-
@
|
57
|
-
@ib.
|
55
|
+
it 'changes client`s next_local_id' do
|
56
|
+
@local_id_placed.should == @local_id_before
|
57
|
+
@ib.next_local_id.should == @local_id_before + 1
|
58
58
|
end
|
59
59
|
|
60
60
|
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
@@ -103,8 +103,8 @@ describe 'Orders', :connected => true, :integration => true do
|
|
103
103
|
|
104
104
|
it { @ib.received[:Alert].should have_exactly(1).alert_message }
|
105
105
|
|
106
|
-
it 'does not increase client`s
|
107
|
-
@ib.
|
106
|
+
it 'does not increase client`s next_local_id further' do
|
107
|
+
@ib.next_local_id.should == @local_id_after
|
108
108
|
end
|
109
109
|
|
110
110
|
it 'does not receive Order messages' do
|
@@ -21,10 +21,6 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
21
21
|
:total_quantity => 20000,
|
22
22
|
:limit_price => 2,
|
23
23
|
:action => 'BUY'
|
24
|
-
#:all_or_none => 1,
|
25
|
-
#:fa_profile => 2,
|
26
|
-
#:percent_offset => 3,
|
27
|
-
#:clearing_account => 'z',
|
28
24
|
#:what_if => true
|
29
25
|
|
30
26
|
@ib.wait_for(5, :ExecutionData, :OpenOrder) do
|
@@ -35,12 +31,12 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
35
31
|
|
36
32
|
after(:all) do
|
37
33
|
clean_connection # Clear logs and message collector
|
38
|
-
@ib.cancel_order @
|
34
|
+
@ib.cancel_order @local_id_placed # Just in case...
|
39
35
|
end
|
40
36
|
|
41
|
-
it 'changes client`s
|
42
|
-
@
|
43
|
-
@ib.
|
37
|
+
it 'changes client`s next_local_id' do
|
38
|
+
@local_id_placed = @local_id_before
|
39
|
+
@ib.next_local_id.should == @local_id_before + 1
|
44
40
|
end
|
45
41
|
|
46
42
|
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
@@ -78,12 +74,12 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
78
74
|
|
79
75
|
after(:all) do
|
80
76
|
clean_connection # Clear logs and message collector
|
81
|
-
@ib.cancel_order @
|
77
|
+
@ib.cancel_order @local_id_placed # Just in case...
|
82
78
|
end
|
83
79
|
|
84
|
-
it 'changes client`s
|
85
|
-
@
|
86
|
-
@ib.
|
80
|
+
it 'changes client`s next_local_id' do
|
81
|
+
@local_id_placed = @local_id_before
|
82
|
+
@ib.next_local_id.should == @local_id_before + 1
|
87
83
|
end
|
88
84
|
|
89
85
|
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
@@ -9,8 +9,8 @@ shared_examples_for 'Received single id' do
|
|
9
9
|
|
10
10
|
it 'receives next valid for Order placement' do
|
11
11
|
subject.should be_an IB::Messages::Incoming::NextValidId
|
12
|
-
subject.
|
13
|
-
@id[:at_connect] ||= subject.
|
12
|
+
subject.local_id.should be_an Integer
|
13
|
+
@id[:at_connect] ||= subject.local_id # just assign once
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'logs next valid order id' do
|
@@ -24,7 +24,7 @@ shared_examples_for 'Received single id after request' do
|
|
24
24
|
it_behaves_like 'Received single id'
|
25
25
|
|
26
26
|
it 'no new id is generated by this request' do
|
27
|
-
subject.
|
27
|
+
subject.local_id.should == @id[:at_connect]
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'does not receive :OpenOrderEnd message' do
|
data/spec/message_helper.rb
CHANGED