ib-ruby 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/README.md +60 -30
- data/TODO +1 -0
- data/VERSION +1 -1
- data/bin/account_info +1 -4
- data/bin/cancel_orders +0 -3
- data/bin/contract_details +2 -5
- data/bin/depth_of_market +1 -4
- data/bin/fa_accounts +22 -0
- data/bin/historic_data +1 -4
- data/bin/historic_data_cli +0 -4
- data/bin/list_orders +2 -6
- data/bin/market_data +1 -4
- data/bin/option_data +2 -5
- data/bin/place_combo_order +17 -22
- data/bin/place_order +6 -10
- data/bin/tick_data +6 -9
- data/bin/time_and_sales +2 -5
- data/lib/ib-ruby/connection.rb +10 -5
- data/lib/ib-ruby/messages/incoming/open_order.rb +15 -13
- data/lib/ib-ruby/messages/incoming/ticks.rb +1 -1
- data/lib/ib-ruby/messages/incoming.rb +18 -18
- data/lib/ib-ruby/messages/outgoing.rb +2 -2
- data/lib/ib-ruby/messages.rb +3 -7
- data/lib/ib-ruby/models/{contract → contracts}/bag.rb +5 -8
- data/lib/ib-ruby/models/contracts/contract.rb +296 -0
- data/lib/ib-ruby/models/{contract → contracts}/option.rb +2 -4
- data/lib/ib-ruby/models/contracts.rb +27 -0
- data/lib/ib-ruby/models/execution.rb +1 -1
- data/lib/ib-ruby/models/order.rb +6 -17
- data/lib/ib-ruby/models.rb +9 -7
- data/lib/ib-ruby/symbols/forex.rb +50 -50
- data/lib/ib-ruby/symbols/futures.rb +47 -47
- data/lib/ib-ruby/symbols/options.rb +23 -23
- data/lib/ib-ruby/symbols/stocks.rb +14 -14
- data/lib/ib-ruby.rb +17 -9
- data/spec/README.md +6 -0
- data/spec/account_helper.rb +1 -1
- data/spec/combo_helper.rb +31 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +4 -4
- data/spec/ib-ruby/models/contract_spec.rb +37 -26
- data/spec/ib-ruby/models/execution_spec.rb +5 -5
- data/spec/ib-ruby/models/order_spec.rb +16 -16
- data/spec/integration/contract_info_spec.rb +8 -10
- data/spec/integration/historic_data_spec.rb +1 -1
- data/spec/integration/market_data_spec.rb +5 -5
- data/spec/integration/orders/attached_spec.rb +87 -0
- data/spec/integration/orders/combo_spec.rb +52 -65
- data/spec/integration/orders/placement_spec.rb +8 -8
- data/spec/order_helper.rb +97 -28
- data/spec/spec_helper.rb +2 -2
- metadata +12 -5
- data/lib/ib-ruby/models/contract.rb +0 -308
@@ -13,8 +13,8 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
13
13
|
context "Request Stock data" do
|
14
14
|
|
15
15
|
before(:all) do
|
16
|
-
@contract = IB::
|
17
|
-
|
16
|
+
@contract = IB::Contract.new :symbol => 'AAPL',
|
17
|
+
:sec_type => IB::SECURITY_TYPES[:stock]
|
18
18
|
@ib.send_message :RequestContractData, :id => 111, :contract => @contract
|
19
19
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
20
20
|
end
|
@@ -61,10 +61,8 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
61
61
|
context "Request Option contract data" do
|
62
62
|
|
63
63
|
before(:all) do
|
64
|
-
@contract = IB::
|
65
|
-
|
66
|
-
:right => "CALL",
|
67
|
-
:strike => 500
|
64
|
+
@contract = IB::Option.new :symbol => "AAPL", :expiry => "201301",
|
65
|
+
:right => "CALL", :strike => 500
|
68
66
|
@ib.send_message :RequestContractData, :id => 123, :contract => @contract
|
69
67
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
70
68
|
end
|
@@ -107,10 +105,10 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
107
105
|
context "Request Forex contract data" do
|
108
106
|
|
109
107
|
before(:all) do
|
110
|
-
@contract = IB::
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
@contract = IB::Contract.new :symbol => 'EUR', # EURUSD pair
|
109
|
+
:currency => "USD",
|
110
|
+
:exchange => "IDEALPRO",
|
111
|
+
:sec_type => IB::SECURITY_TYPES[:forex]
|
114
112
|
@ib.send_message :RequestContractData, :id => 135, :contract => @contract
|
115
113
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
116
114
|
end
|
@@ -55,7 +55,7 @@ describe 'Request Historic Data', :connected => true, :integration => true do
|
|
55
55
|
subject.results.should be_an Array
|
56
56
|
subject.results.size.should == subject.count
|
57
57
|
subject.results.each do |bar|
|
58
|
-
bar.should be_an IB::
|
58
|
+
bar.should be_an IB::Bar
|
59
59
|
bar.time.should =~ /\d{8} *\d\d:\d\d:\d\d/
|
60
60
|
bar.open.should be_a Float
|
61
61
|
bar.high.should be_a Float
|
@@ -12,11 +12,11 @@ describe 'Request Market Data', :connected => true, :integration => true do
|
|
12
12
|
context 'US Stocks market', :if => :us_trading_hours do
|
13
13
|
before(:all) do
|
14
14
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
15
|
-
@contract = IB::
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
@contract = IB::Contract.new(:symbol => 'AAPL',
|
16
|
+
:exchange => "Smart",
|
17
|
+
:currency => "USD",
|
18
|
+
:sec_type => IB::SECURITY_TYPES[:stock],
|
19
|
+
:description => "Apple"
|
20
20
|
)
|
21
21
|
@ib.send_message :RequestMarketData, :id => 456, :contract => @contract
|
22
22
|
@ib.wait_for :TickSize, :TickString, 3 # sec
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'order_helper'
|
2
|
+
require 'combo_helper'
|
3
|
+
|
4
|
+
#OPTS[:silent] = false
|
5
|
+
|
6
|
+
def define_contracts
|
7
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
8
|
+
@contracts = {
|
9
|
+
:stock => IB::Symbols::Stocks[:wfc],
|
10
|
+
:butterfly => butterfly('GOOG', '201301', 'CALL', 500, 510, 520)
|
11
|
+
}
|
12
|
+
close_connection
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'Attached Orders', :connected => true, :integration => true do
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
verify_account
|
19
|
+
define_contracts
|
20
|
+
end
|
21
|
+
|
22
|
+
# Testing different combinations of Parent + Attached Orders:
|
23
|
+
[
|
24
|
+
#[:stock, 100, 'DAY', 'LMT', 9.13, 20.0], # Parent + takeprofit target
|
25
|
+
[:stock, 100, 'DAY', 'STP', 9.13, 0.0, 8.0], # Parent + stoploss
|
26
|
+
[:stock, 100, 'GTC', 'LMT', 9.13, 20.0], # GTC Parent + target
|
27
|
+
[:butterfly, 10, 'DAY', 'LMT', 0.05, 1.0], # Combo Parent + target
|
28
|
+
#[:butterfly, 10, 'GTC', 'LMT', 0.05, 1.0], # GTC Combo Parent + target
|
29
|
+
[:butterfly, 100, 'GTC', 'STPLMT', 0.05, 0.05, 1.0], # GTC Combo Parent + stoplimit target
|
30
|
+
|
31
|
+
].each do |(contract, qty, tif, attach_type, limit_price, attach_price, aux_price)|
|
32
|
+
context "#{tif} BUY (#{contract}) limit order with attached #{attach_type} SELL" do
|
33
|
+
let(:contract_type) { contract }
|
34
|
+
|
35
|
+
before(:all) do
|
36
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
37
|
+
@ib.wait_for :NextValidId
|
38
|
+
@ib.clear_received # to avoid conflict with pre-existing Orders
|
39
|
+
|
40
|
+
#p [contract, qty, tif, attach_type, limit_price, attach_price, aux_price]
|
41
|
+
@contract = @contracts[contract]
|
42
|
+
place_order @contract,
|
43
|
+
:total_quantity => qty,
|
44
|
+
:limit_price => limit_price,
|
45
|
+
:tif => tif,
|
46
|
+
:transmit => false
|
47
|
+
|
48
|
+
@ib.wait_for :OpenOrder, :OrderStatus, 2
|
49
|
+
end
|
50
|
+
|
51
|
+
after(:all) { close_connection }
|
52
|
+
|
53
|
+
it 'does not transmit original Order before attach' do
|
54
|
+
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
55
|
+
@ib.received[:OrderStatus].should have_exactly(0).status_message
|
56
|
+
end
|
57
|
+
|
58
|
+
context "Attaching #{attach_type} order" do
|
59
|
+
before(:all) do
|
60
|
+
@attached_order = IB::Order.new :total_quantity => qty,
|
61
|
+
:limit_price => attach_price,
|
62
|
+
:aux_price => aux_price || 0,
|
63
|
+
:action => 'SELL',
|
64
|
+
:tif => tif,
|
65
|
+
:order_type => attach_type,
|
66
|
+
:parent_id => @order_id_placed
|
67
|
+
|
68
|
+
@order_id_attached = @ib.place_order @attached_order, @contract
|
69
|
+
@order_id_after = @ib.next_order_id
|
70
|
+
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 3], 4
|
71
|
+
end
|
72
|
+
|
73
|
+
it_behaves_like 'Placed Order'
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'When original Order cancels' do
|
77
|
+
it 'attached takeprofit is cancelled implicitly' do
|
78
|
+
@ib.send_message :RequestOpenOrders
|
79
|
+
@ib.wait_for :OpenOrderEnd
|
80
|
+
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
81
|
+
@ib.received[:OrderStatus].should have_exactly(0).status_message
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end # Orders
|
@@ -1,55 +1,67 @@
|
|
1
1
|
require 'order_helper'
|
2
|
+
require 'combo_helper'
|
2
3
|
|
3
4
|
#OPTS[:silent] = false
|
4
5
|
|
5
|
-
def butterfly symbol, expiry, right, *strikes
|
6
|
-
raise 'No Connection!' unless @ib && @ib.connected?
|
7
|
-
|
8
|
-
legs = strikes.zip([1, -2, 1]).map do |strike, weight|
|
9
|
-
# Create contract
|
10
|
-
contract = IB::Models::Contract::Option.new :symbol => symbol,
|
11
|
-
:expiry => expiry,
|
12
|
-
:right => right,
|
13
|
-
:strike => strike
|
14
|
-
# Find out contract's con_id
|
15
|
-
@ib.clear_received :ContractData, :ContractDataEnd
|
16
|
-
@ib.send_message :RequestContractData, :id => strike, :contract => contract
|
17
|
-
@ib.wait_for :ContractDataEnd, 3
|
18
|
-
con_id = @ib.received[:ContractData].last.contract.con_id
|
19
|
-
|
20
|
-
# Create Comboleg from con_id and weight
|
21
|
-
IB::Models::ComboLeg.new :con_id => con_id, :weight => weight
|
22
|
-
end
|
23
|
-
|
24
|
-
# Create new Combo contract
|
25
|
-
IB::Models::Contract::Bag.new :symbol => symbol,
|
26
|
-
:currency => "USD", # Only US options in combo Contracts
|
27
|
-
:exchange => "SMART",
|
28
|
-
:legs => legs
|
29
|
-
end
|
30
|
-
|
31
6
|
describe "Combo Order", :connected => true, :integration => true, :slow => true do
|
32
7
|
|
8
|
+
let(:contract_type) { :butterfly }
|
9
|
+
|
33
10
|
before(:all) { verify_account }
|
34
11
|
|
35
|
-
context
|
12
|
+
context 'What-if order' do
|
36
13
|
before(:all) do
|
37
14
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
38
15
|
@ib.wait_for :NextValidId
|
39
|
-
@ib.clear_received # to avoid conflict with pre-existing Orders
|
40
16
|
|
41
17
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
42
18
|
|
43
|
-
place_order @contract,
|
44
|
-
|
19
|
+
place_order @contract,
|
20
|
+
:limit_price => 0.01,
|
21
|
+
:total_quantity => 10,
|
22
|
+
:what_if => true
|
23
|
+
|
24
|
+
@ib.wait_for :OpenOrder, 8
|
45
25
|
end
|
46
26
|
|
47
27
|
after(:all) { close_connection }
|
48
28
|
|
49
|
-
|
50
|
-
|
29
|
+
it 'changes client`s next_order_id' do
|
30
|
+
@order_id_placed.should == @order_id_before
|
31
|
+
@ib.next_order_id.should == @order_id_before + 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
35
|
+
it { @ib.received[:OrderStatus].should have_exactly(0).status_messages }
|
36
|
+
|
37
|
+
it 'responds with margin info' do
|
38
|
+
order_should_be /PreSubmitted/
|
39
|
+
order = @ib.received[:OpenOrder].first.order
|
40
|
+
order.what_if.should == true
|
41
|
+
order.equity_with_loan.should be_a Float
|
42
|
+
order.init_margin.should be_a Float
|
43
|
+
order.maint_margin.should be_a Float
|
44
|
+
order.equity_with_loan.should be > 0
|
45
|
+
order.init_margin.should be > 0
|
46
|
+
order.maint_margin.should be > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'responds with commission info',
|
50
|
+
:pending => 'API Bug: No commission in what_if for Combo orders' do
|
51
|
+
order = @ib.received[:OpenOrder].first.order
|
52
|
+
order.commission.should be_a Float
|
53
|
+
order.commission.should be > 1
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'is not actually being placed though' do
|
57
|
+
@ib.clear_received
|
58
|
+
@ib.send_message :RequestOpenOrders
|
59
|
+
@ib.wait_for :OpenOrderEnd
|
60
|
+
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
61
|
+
end
|
62
|
+
end
|
51
63
|
|
52
|
-
context "Limit
|
64
|
+
context "Limit" do # , :if => :us_trading_hours
|
53
65
|
before(:all) do
|
54
66
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
55
67
|
@ib.wait_for :NextValidId
|
@@ -57,41 +69,16 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
57
69
|
|
58
70
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
59
71
|
|
60
|
-
place_order @contract,
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
after(:all) { close_connection }
|
72
|
+
place_order @contract,
|
73
|
+
:limit_price => 0.01,
|
74
|
+
:total_quantity => 10
|
65
75
|
|
66
|
-
|
67
|
-
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
68
|
-
@ib.received[:OrderStatus].should have_exactly(0).status_message
|
76
|
+
@ib.wait_for [:OpenOrder, 2], [:OrderStatus, 2], 6
|
69
77
|
end
|
70
78
|
|
71
|
-
|
72
|
-
before(:all) do
|
73
|
-
@attached_order = IB::Models::Order.new :total_quantity => 100,
|
74
|
-
:limit_price => 0.5,
|
75
|
-
:action => 'SELL',
|
76
|
-
:order_type => 'LMT',
|
77
|
-
:parent_id => @order_id_placed
|
78
|
-
|
79
|
-
@order_id_attached = @ib.place_order @attached_order, @contract
|
80
|
-
@order_id_after = @ib.next_order_id
|
81
|
-
@ib.wait_for [:OpenOrder, 2], [:OrderStatus, 2], 8
|
82
|
-
end
|
83
|
-
|
84
|
-
it_behaves_like 'Placed Order'
|
85
|
-
end
|
79
|
+
after(:all) { close_connection }
|
86
80
|
|
87
|
-
|
88
|
-
|
89
|
-
@ib.send_message :RequestOpenOrders
|
90
|
-
@ib.wait_for :OpenOrderEnd
|
91
|
-
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
92
|
-
@ib.received[:OrderStatus].should have_exactly(0).status_message
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end # Attached
|
81
|
+
it_behaves_like 'Placed Order'
|
82
|
+
end # Limit
|
96
83
|
end # Combo Orders
|
97
84
|
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
|
3
3
|
#OPTS[:silent] = false
|
4
|
+
|
4
5
|
describe 'Orders', :connected => true, :integration => true do
|
6
|
+
let(:contract_type) { :stock }
|
5
7
|
|
6
8
|
before(:all) { verify_account }
|
7
9
|
|
@@ -60,7 +62,7 @@ describe 'Orders', :connected => true, :integration => true do
|
|
60
62
|
it { @ib.received[:OpenOrder].should have_at_least(1).open_order_message }
|
61
63
|
it { @ib.received[:OrderStatus].should have_exactly(0).status_messages }
|
62
64
|
|
63
|
-
it '
|
65
|
+
it 'responds with margin and commission info' do
|
64
66
|
order_should_be /PreSubmitted/
|
65
67
|
order = @ib.received[:OpenOrder].first.order
|
66
68
|
order.what_if.should == true
|
@@ -74,7 +76,7 @@ describe 'Orders', :connected => true, :integration => true do
|
|
74
76
|
order.commission.should be > 1
|
75
77
|
end
|
76
78
|
|
77
|
-
it 'is not actually
|
79
|
+
it 'is not actually being placed though' do
|
78
80
|
@ib.clear_received
|
79
81
|
@ib.send_message :RequestOpenOrders
|
80
82
|
@ib.wait_for :OpenOrderEnd
|
@@ -82,14 +84,12 @@ describe 'Orders', :connected => true, :integration => true do
|
|
82
84
|
end
|
83
85
|
end
|
84
86
|
|
85
|
-
context 'Off-market
|
87
|
+
context 'Off-market limit' do
|
86
88
|
before(:all) do
|
87
89
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
88
90
|
@ib.wait_for :NextValidId
|
89
|
-
|
90
|
-
|
91
|
-
:limit_price => 9.13 # Set acceptable price
|
92
|
-
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2]
|
91
|
+
place_order IB::Symbols::Stocks[:wfc], :limit_price => 9.13 # Acceptable price
|
92
|
+
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2], 10
|
93
93
|
end
|
94
94
|
|
95
95
|
after(:all) { close_connection }
|
@@ -120,5 +120,5 @@ describe 'Orders', :connected => true, :integration => true do
|
|
120
120
|
alert.message.should =~ /Can't find order with id =/
|
121
121
|
end
|
122
122
|
end # Cancelling
|
123
|
-
end # Off-market
|
123
|
+
end # Off-market limit
|
124
124
|
end # Orders
|
data/spec/order_helper.rb
CHANGED
@@ -9,12 +9,14 @@ shared_examples_for 'Placed Order' do
|
|
9
9
|
@ib.next_order_id.should be >= @order_id_before
|
10
10
|
end
|
11
11
|
|
12
|
-
it
|
13
|
-
|
12
|
+
it 'receives all appropriate response messages' do
|
13
|
+
@ib.received[:OpenOrder].should have_at_least(1).order_message
|
14
|
+
@ib.received[:OrderStatus].should have_at_least(1).status_message
|
15
|
+
end
|
14
16
|
|
15
17
|
it 'receives confirmation of Order submission' do
|
16
|
-
order_should_be /
|
17
|
-
status_should_be /
|
18
|
+
order_should_be /Submit/ # ()Pre)Submitted
|
19
|
+
status_should_be /Submit/
|
18
20
|
end
|
19
21
|
end # Placing
|
20
22
|
|
@@ -30,22 +32,79 @@ shared_examples_for 'Placed Order' do
|
|
30
32
|
@ib.next_order_id.should == @order_id_after
|
31
33
|
end
|
32
34
|
|
33
|
-
it
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
it 'receives all appropriate response messages' do
|
36
|
+
@ib.received[:OpenOrder].should have_at_least(1).order_message
|
37
|
+
@ib.received[:OrderStatus].should have_at_least(1).status_message
|
38
|
+
@ib.received[:OpenOrderEnd].should have_exactly(1).order_end_message
|
39
|
+
end
|
38
40
|
|
39
|
-
it 'receives OpenOrder and OrderStatus for placed order' do
|
41
|
+
it 'receives OpenOrder and OrderStatus for placed order(s)' do
|
40
42
|
order_should_be /Submitted/
|
41
43
|
status_should_be /Submitted/
|
44
|
+
|
45
|
+
if @attached_order
|
46
|
+
if contract_type == :butterfly && @attached_order.tif == 'GTC'
|
47
|
+
pending 'API Bug: Attached DAY orders not working for butterflies!'
|
48
|
+
else
|
49
|
+
order_should_be /Submit/, @attached_order
|
50
|
+
end
|
51
|
+
end
|
42
52
|
end
|
43
53
|
end # Retrieving
|
44
54
|
|
55
|
+
context "Modifying Order" do
|
56
|
+
before(:all) do
|
57
|
+
if defined?(contract_type) && contract_type == :butterfly
|
58
|
+
pending 'API Bug: Order modification not working for butterflies!'
|
59
|
+
else
|
60
|
+
# Modification only works for non-attached, non-combo orders
|
61
|
+
@order.total_quantity = 200
|
62
|
+
@order.limit_price += 0.05
|
63
|
+
@order.transmit = true
|
64
|
+
@ib.modify_order @order, @contract
|
65
|
+
|
66
|
+
if @attached_order
|
67
|
+
# Modify attached order, if any
|
68
|
+
@attached_order.limit_price *= 1.5
|
69
|
+
@attached_order.tif = 'GTC'
|
70
|
+
@ib.modify_order @attached_order, @contract
|
71
|
+
end
|
72
|
+
end
|
73
|
+
@ib.send_message :RequestOpenOrders
|
74
|
+
@ib.wait_for :OpenOrderEnd, 6 #sec
|
75
|
+
end
|
76
|
+
|
77
|
+
after(:all) { clean_connection } # Clear logs and message collector
|
78
|
+
|
79
|
+
it 'does not increase client`s next_order_id further' do
|
80
|
+
@ib.next_order_id.should == @order_id_after
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'receives all appropriate response messages' do
|
84
|
+
@ib.received[:OpenOrder].should have_at_least(1).order_message
|
85
|
+
@ib.received[:OrderStatus].should have_at_least(1).status_message
|
86
|
+
@ib.received[:OpenOrderEnd].should have_exactly(1).order_end_message
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'modifies the placed order(s)' do
|
90
|
+
@contract.should == @ib.received[:OpenOrder].first.contract
|
91
|
+
order_should_be /Submit/
|
92
|
+
status_should_be /Submit/
|
93
|
+
|
94
|
+
if @attached_order
|
95
|
+
if contract_type == :butterfly && @attached_order.tif == 'GTC'
|
96
|
+
pending 'API Bug: Attached DAY orders not working for butterflies!'
|
97
|
+
else
|
98
|
+
order_should_be /Submit/, @attached_order
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end # Modifying
|
103
|
+
|
45
104
|
context "Cancelling placed order" do
|
46
105
|
before(:all) do
|
47
106
|
@ib.cancel_order @order_id_placed
|
48
|
-
@ib.wait_for [:OrderStatus,
|
107
|
+
@ib.wait_for [:OrderStatus, 3], :Alert
|
49
108
|
end
|
50
109
|
|
51
110
|
after(:all) { clean_connection } # Clear logs and message collector
|
@@ -54,15 +113,26 @@ shared_examples_for 'Placed Order' do
|
|
54
113
|
@ib.next_order_id.should == @order_id_after
|
55
114
|
end
|
56
115
|
|
57
|
-
it '
|
58
|
-
@ib.received?
|
116
|
+
it 'only receives OpenOrder message with PendingCancel' do
|
117
|
+
if @ib.received? :OpenOrder
|
118
|
+
order_should_be /PendingCancel/
|
119
|
+
end
|
59
120
|
end
|
60
121
|
|
61
|
-
it
|
62
|
-
|
122
|
+
it 'receives all appropriate response messages' do
|
123
|
+
@ib.received[:OrderStatus].should have_at_least(1).status_message
|
124
|
+
@ib.received[:Alert].should have_at_least(1).alert_message
|
125
|
+
end
|
63
126
|
|
64
127
|
it 'receives cancellation Order Status' do
|
65
128
|
status_should_be /Cancel/ # Cancelled / PendingCancel
|
129
|
+
if @attached_order
|
130
|
+
if contract_type == :butterfly && @attached_order.tif == 'GTC'
|
131
|
+
pending 'API Bug: Attached DAY orders not working for butterflies!'
|
132
|
+
else
|
133
|
+
status_should_be /Cancel/, @attached_order
|
134
|
+
end
|
135
|
+
end
|
66
136
|
end
|
67
137
|
|
68
138
|
it 'receives Order cancelled Alert' do
|
@@ -73,34 +143,34 @@ shared_examples_for 'Placed Order' do
|
|
73
143
|
end # Cancelling
|
74
144
|
end
|
75
145
|
|
76
|
-
|
77
146
|
### Helpers for placing and verifying orders
|
78
147
|
|
79
148
|
def place_order contract, opts
|
80
149
|
@contract = contract
|
81
|
-
@order = IB::
|
82
|
-
|
83
|
-
|
84
|
-
|
150
|
+
@order = IB::Order.new({:total_quantity => 100,
|
151
|
+
:limit_price => 9.13,
|
152
|
+
:action => 'BUY',
|
153
|
+
:order_type => 'LMT'}.merge(opts))
|
85
154
|
@order_id_before = @ib.next_order_id
|
86
155
|
@order_id_placed = @ib.place_order @order, @contract
|
87
156
|
@order_id_after = @ib.next_order_id
|
88
157
|
end
|
89
158
|
|
90
|
-
def status_should_be status
|
159
|
+
def status_should_be status, order=@order
|
91
160
|
msg = @ib.received[:OrderStatus].find do |msg|
|
92
|
-
msg.order_id ==
|
161
|
+
msg.order_id == order.order_id &&
|
93
162
|
status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
|
94
163
|
end
|
95
164
|
msg.should_not be_nil
|
96
165
|
msg.should be_an IB::Messages::Incoming::OrderStatus
|
97
|
-
msg.order_id.should ==
|
166
|
+
msg.order_id.should == order.order_id
|
98
167
|
msg.perm_id.should be_an Integer
|
99
168
|
msg.client_id.should == OPTS[:connection][:client_id]
|
100
|
-
msg.parent_id.should == 0
|
169
|
+
msg.parent_id.should == 0 unless @attached_order
|
101
170
|
msg.why_held.should == ''
|
102
171
|
|
103
172
|
if @contract == IB::Symbols::Forex[:eurusd]
|
173
|
+
# We know that this order filled for sure
|
104
174
|
msg.filled.should == 20000
|
105
175
|
msg.remaining.should == 0
|
106
176
|
msg.average_fill_price.should be > 1
|
@@ -114,16 +184,15 @@ def status_should_be status
|
|
114
184
|
end
|
115
185
|
end
|
116
186
|
|
117
|
-
def order_should_be status
|
187
|
+
def order_should_be status, order=@order
|
118
188
|
msg = @ib.received[:OpenOrder].find do |msg|
|
119
|
-
msg.order_id ==
|
189
|
+
msg.order_id == order.order_id &&
|
120
190
|
status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
|
121
191
|
end
|
122
192
|
msg.should_not be_nil
|
123
193
|
msg.should be_an IB::Messages::Incoming::OpenOrder
|
124
|
-
msg.order.should ==
|
194
|
+
msg.order.should == order
|
125
195
|
msg.contract.should == @contract
|
126
|
-
msg.order.order_id.should == @order_id_placed
|
127
196
|
end
|
128
197
|
|
129
198
|
def execution_should_be side, opts={}
|
data/spec/spec_helper.rb
CHANGED
@@ -40,7 +40,7 @@ else
|
|
40
40
|
OPTS[:connection] =
|
41
41
|
{:account_name => 'DU118180', # Your IB PAPER ACCOUNT, tests will only run against it
|
42
42
|
:client_id => 1111, # Just an arbitrary id
|
43
|
-
:host => '10.211.55.2', #
|
44
|
-
:port => 4001 #
|
43
|
+
:host => '10.211.55.2', # Where your TWS/gateway is located, likely '127.0.0.1'
|
44
|
+
:port => 4001 # 4001 for Gateway, 7496 for TWS GUI
|
45
45
|
}
|
46
46
|
end
|
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.4
|
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-
|
14
|
+
date: 2012-04-04 00:00:00 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -55,6 +55,7 @@ executables:
|
|
55
55
|
- cancel_orders
|
56
56
|
- contract_details
|
57
57
|
- depth_of_market
|
58
|
+
- fa_accounts
|
58
59
|
- historic_data
|
59
60
|
- historic_data_cli
|
60
61
|
- list_orders
|
@@ -74,6 +75,7 @@ files:
|
|
74
75
|
- bin/cancel_orders
|
75
76
|
- bin/contract_details
|
76
77
|
- bin/depth_of_market
|
78
|
+
- bin/fa_accounts
|
77
79
|
- bin/historic_data
|
78
80
|
- bin/historic_data_cli
|
79
81
|
- bin/list_orders
|
@@ -102,18 +104,20 @@ files:
|
|
102
104
|
- lib/ib-ruby/messages/incoming/ticks.rb
|
103
105
|
- lib/ib-ruby/models/bar.rb
|
104
106
|
- lib/ib-ruby/models/combo_leg.rb
|
105
|
-
- lib/ib-ruby/models/
|
107
|
+
- lib/ib-ruby/models/contracts.rb
|
106
108
|
- lib/ib-ruby/models/execution.rb
|
107
109
|
- lib/ib-ruby/models/model.rb
|
108
110
|
- lib/ib-ruby/models/model_properties.rb
|
109
111
|
- lib/ib-ruby/models/order.rb
|
110
|
-
- lib/ib-ruby/models/
|
111
|
-
- lib/ib-ruby/models/contract
|
112
|
+
- lib/ib-ruby/models/contracts/bag.rb
|
113
|
+
- lib/ib-ruby/models/contracts/contract.rb
|
114
|
+
- lib/ib-ruby/models/contracts/option.rb
|
112
115
|
- lib/ib-ruby/symbols/forex.rb
|
113
116
|
- lib/ib-ruby/symbols/futures.rb
|
114
117
|
- lib/ib-ruby/symbols/options.rb
|
115
118
|
- lib/ib-ruby/symbols/stocks.rb
|
116
119
|
- spec/account_helper.rb
|
120
|
+
- spec/combo_helper.rb
|
117
121
|
- spec/integration_helper.rb
|
118
122
|
- spec/message_helper.rb
|
119
123
|
- spec/order_helper.rb
|
@@ -133,6 +137,7 @@ files:
|
|
133
137
|
- spec/integration/historic_data_spec.rb
|
134
138
|
- spec/integration/market_data_spec.rb
|
135
139
|
- spec/integration/option_data_spec.rb
|
140
|
+
- spec/integration/orders/attached_spec.rb
|
136
141
|
- spec/integration/orders/combo_spec.rb
|
137
142
|
- spec/integration/orders/execution_spec.rb
|
138
143
|
- spec/integration/orders/open_order
|
@@ -180,6 +185,7 @@ specification_version: 3
|
|
180
185
|
summary: Ruby Implementation of the Interactive Brokers TWS API
|
181
186
|
test_files:
|
182
187
|
- spec/account_helper.rb
|
188
|
+
- spec/combo_helper.rb
|
183
189
|
- spec/integration_helper.rb
|
184
190
|
- spec/message_helper.rb
|
185
191
|
- spec/order_helper.rb
|
@@ -199,6 +205,7 @@ test_files:
|
|
199
205
|
- spec/integration/historic_data_spec.rb
|
200
206
|
- spec/integration/market_data_spec.rb
|
201
207
|
- spec/integration/option_data_spec.rb
|
208
|
+
- spec/integration/orders/attached_spec.rb
|
202
209
|
- spec/integration/orders/combo_spec.rb
|
203
210
|
- spec/integration/orders/execution_spec.rb
|
204
211
|
- spec/integration/orders/open_order
|