ib-ruby 0.7.0 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +8 -0
- data/README.md +24 -4
- data/TODO +8 -8
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +1 -1
- data/bin/contract_details +1 -1
- data/bin/depth_of_market +1 -1
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +1 -1
- data/bin/list_orders +5 -2
- data/bin/market_data +1 -1
- data/bin/option_data +2 -2
- data/bin/place_combo_order +3 -3
- data/bin/place_order +2 -2
- data/bin/template +2 -2
- data/bin/tick_data +2 -1
- data/bin/time_and_sales +2 -4
- data/lib/ib-ruby/messages/incoming/open_order.rb +9 -0
- data/lib/ib-ruby/models/order.rb +0 -1
- data/spec/README.md +28 -20
- data/spec/TODO +10 -0
- data/spec/ib-ruby/messages/incoming_spec.rb +1 -1
- data/spec/integration/orders/combo_spec.rb +50 -4
- data/spec/integration/orders/execution_spec.rb +4 -4
- data/spec/integration/orders/open_order +19 -0
- data/spec/order_helper.rb +19 -21
- data/spec/spec_helper.rb +1 -1
- metadata +4 -2
data/HISTORY
CHANGED
data/README.md
CHANGED
@@ -24,10 +24,10 @@ the same machine as TWS.
|
|
24
24
|
As a rule of thumb, most recent version of ib-ruby gem only supports latest versions
|
25
25
|
of TWS/Gateway API. Older versions of API are supported by previous gem versions:
|
26
26
|
|
27
|
-
ib-ruby gem TWS version API version
|
28
|
-
0.5.21 918-920 965
|
29
|
-
0.6.1 921-923 966
|
30
|
-
0.7.1 924+ 967
|
27
|
+
ib-ruby gem TWS version API version
|
28
|
+
0.5.21 918-920 965
|
29
|
+
0.6.1 921-923 966
|
30
|
+
0.7.1 924+ 967
|
31
31
|
|
32
32
|
## INSTALLATION:
|
33
33
|
|
@@ -92,6 +92,26 @@ The sample scripts in `bin` directory provide examples of how common tasks
|
|
92
92
|
can be achieved using ib-ruby. You may also want to look into `spec/integration`
|
93
93
|
directory for more scenarios and examples of handling IB messages.
|
94
94
|
|
95
|
+
## RUNNING TESTS:
|
96
|
+
|
97
|
+
The gem comes with a spec suit that may be used to test ib-ruby compatibility
|
98
|
+
with your specific TWS/Gateway installation. The test suit should be run ONLY
|
99
|
+
against your IB paper trading account. Running it against live account may result
|
100
|
+
in financial losses.
|
101
|
+
|
102
|
+
In order to run tests, you should set up your IB paper trading connection parameters
|
103
|
+
in 'spec/spec_helper' file. Modify account_name, host and port under section
|
104
|
+
'Your IB PAPER ACCOUNT'. Do not change the client_id.
|
105
|
+
|
106
|
+
Before running tests, you need to start your TWS/Gateway and allow API connection.
|
107
|
+
You should not have any open/pending orders on your IB paper trading account prior
|
108
|
+
to running tests, otherwise some tests will fail. Use 'bin/cancel_orders' script for
|
109
|
+
bulk cancelling of open orders before running tests as needed.
|
110
|
+
|
111
|
+
You can easily create your own tests following the guide in 'spec/README'.
|
112
|
+
Help the development! See 'spec/TODO' for the list of use cases/scenarios
|
113
|
+
that still need to be tested.
|
114
|
+
|
95
115
|
## LICENSE:
|
96
116
|
|
97
117
|
This software is available under the LGPL.
|
data/TODO
CHANGED
@@ -12,15 +12,9 @@ http://finance.groups.yahoo.com/group/TWSAPI/message/25413
|
|
12
12
|
|
13
13
|
5. IB Connection reconnects gracefully in case if TWS disconnects/reconnects
|
14
14
|
|
15
|
-
6.
|
15
|
+
6. @received_at timestamp in messages
|
16
16
|
|
17
|
-
7.
|
18
|
-
|
19
|
-
8. Collect all messages in Connection#received_messages
|
20
|
-
|
21
|
-
9. Flow handlers: Connection#wait_for / Connection#received?
|
22
|
-
|
23
|
-
10. Create integration tests for more use cases (spec/README)
|
17
|
+
7. Create integration tests for more use cases (spec/README)
|
24
18
|
|
25
19
|
|
26
20
|
Done:
|
@@ -29,6 +23,12 @@ Done:
|
|
29
23
|
|
30
24
|
2. IB#subscribe should accept regexes.
|
31
25
|
|
26
|
+
3. Compatibility with for API v.966, 967
|
27
|
+
|
28
|
+
4. Collect all received messages in Connection#received[:type] by default
|
29
|
+
|
30
|
+
5. Flow handlers: Connection#wait_for / Connection#received?
|
31
|
+
|
32
32
|
Ideas for future:
|
33
33
|
|
34
34
|
1. Decouple Broker-specific Adapter from universal high-level messaging layer
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.2
|
data/bin/account_info
CHANGED
@@ -12,7 +12,7 @@ require 'bundler/setup'
|
|
12
12
|
require 'ib-ruby'
|
13
13
|
|
14
14
|
# First, connect to IB TWS.
|
15
|
-
ib = IB::Connection.new :client_id => 1112
|
15
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
16
16
|
|
17
17
|
# Set log level
|
18
18
|
log.level = Logger::FATAL
|
data/bin/cancel_orders
CHANGED
@@ -13,7 +13,7 @@ require 'bundler/setup'
|
|
13
13
|
require 'ib-ruby'
|
14
14
|
|
15
15
|
# First, connect to IB TWS.
|
16
|
-
ib = IB::Connection.new :client_id => 1112
|
16
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
17
17
|
|
18
18
|
# Subscribe to TWS alerts/errors and order-related messages
|
19
19
|
ib.subscribe(:Alert, :OpenOrder, :OrderStatus, :OpenOrderEnd) { |msg| puts msg.to_human }
|
data/bin/contract_details
CHANGED
@@ -18,7 +18,7 @@ require 'ib-ruby'
|
|
18
18
|
144 => IB::Symbols::Stocks[:wrong]}
|
19
19
|
|
20
20
|
# Connect to IB TWS.
|
21
|
-
ib = IB::Connection.new :client_id => 1112
|
21
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
22
22
|
|
23
23
|
# Subscribe to TWS alerts/errors
|
24
24
|
ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
|
data/bin/depth_of_market
CHANGED
@@ -20,7 +20,7 @@ require 'ib-ruby'
|
|
20
20
|
}
|
21
21
|
|
22
22
|
# First, connect to IB TWS.
|
23
|
-
ib = IB::Connection.new :client_id => 1112
|
23
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
24
24
|
|
25
25
|
# Subscribe to TWS alerts/errors
|
26
26
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/historic_data
CHANGED
@@ -19,7 +19,7 @@ require 'ib-ruby'
|
|
19
19
|
}
|
20
20
|
|
21
21
|
# Connect to IB TWS.
|
22
|
-
ib = IB::Connection.new :client_id => 1112
|
22
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
23
23
|
|
24
24
|
# Subscribe to TWS alerts/errors
|
25
25
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/historic_data_cli
CHANGED
@@ -133,7 +133,7 @@ DATE_FORMAT = (opt["dateformat"] && opt["dateformat"].to_i) || 1
|
|
133
133
|
PORT = (opt["port"] && opt["port"]) || '4001'
|
134
134
|
|
135
135
|
# First, connect to IB TWS.
|
136
|
-
ib = IB::Connection.new :client_id => 1112
|
136
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
137
137
|
|
138
138
|
# Subscribe to TWS alerts/errors
|
139
139
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/list_orders
CHANGED
@@ -9,10 +9,11 @@ $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
|
9
9
|
|
10
10
|
require 'rubygems'
|
11
11
|
require 'bundler/setup'
|
12
|
+
require 'pp'
|
12
13
|
require 'ib-ruby'
|
13
14
|
|
14
|
-
#
|
15
|
-
ib = IB::Connection.new :client_id => 0
|
15
|
+
# Connect to IB as 0 (TWS) to retrieve all Orders, including TWS-generated ones
|
16
|
+
ib = IB::Connection.new :client_id => 0 #, :port => 7496 # TWS
|
16
17
|
|
17
18
|
# Subscribe to TWS alerts/errors and order-related messages
|
18
19
|
@counter = 0
|
@@ -22,9 +23,11 @@ ib.subscribe(:Alert, :OrderStatus, :OpenOrderEnd) { |msg| puts msg.to_human }
|
|
22
23
|
ib.subscribe(:OpenOrder) do |msg|
|
23
24
|
@counter += 1
|
24
25
|
puts "#{@counter}: #{msg.to_human}"
|
26
|
+
pp msg.order
|
25
27
|
end
|
26
28
|
|
27
29
|
ib.send_message :RequestAllOpenOrders
|
28
30
|
|
29
31
|
# Wait for IB to respond to our request
|
30
32
|
ib.wait_for :OpenOrderEnd
|
33
|
+
sleep 1 # Let printer do the job
|
data/bin/market_data
CHANGED
@@ -18,7 +18,7 @@ require 'ib-ruby'
|
|
18
18
|
789 => IB::Symbols::Forex[:usdcad]}
|
19
19
|
|
20
20
|
# First, connect to IB TWS.
|
21
|
-
ib = IB::Connection.new :client_id => 1112
|
21
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
22
22
|
|
23
23
|
## Subscribe to TWS alerts/errors
|
24
24
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/option_data
CHANGED
@@ -18,8 +18,8 @@ require 'ib-ruby'
|
|
18
18
|
17 => IB::Symbols::Options[:spy75],
|
19
19
|
19 => IB::Symbols::Options[:spy100]}
|
20
20
|
|
21
|
-
# First, connect to IB TWS.
|
22
|
-
ib = IB::Connection.new :client_id => 1112
|
21
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
22
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
23
23
|
|
24
24
|
## Subscribe to TWS alerts/errors
|
25
25
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/place_combo_order
CHANGED
@@ -39,12 +39,12 @@ def butterfly symbol, expiry, right, *strikes
|
|
39
39
|
end
|
40
40
|
|
41
41
|
|
42
|
-
# First, connect to IB TWS.
|
43
|
-
|
44
|
-
@ib.wait_for :NextValidId
|
42
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
43
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
45
44
|
|
46
45
|
# Subscribe to TWS alerts/errors and order-related messages
|
47
46
|
@ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
|
47
|
+
@ib.wait_for :NextValidId
|
48
48
|
|
49
49
|
# Create multi-legged option Combo using utility method above
|
50
50
|
combo = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
data/bin/place_order
CHANGED
@@ -11,8 +11,8 @@ require 'rubygems'
|
|
11
11
|
require 'bundler/setup'
|
12
12
|
require 'ib-ruby'
|
13
13
|
|
14
|
-
# First, connect to IB TWS.
|
15
|
-
ib = IB::Connection.new :client_id => 1112
|
14
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
15
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
16
16
|
|
17
17
|
# Subscribe to TWS alerts/errors and order-related messages
|
18
18
|
ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
|
data/bin/template
CHANGED
@@ -10,8 +10,8 @@ require 'rubygems'
|
|
10
10
|
require 'bundler/setup'
|
11
11
|
require 'ib-ruby'
|
12
12
|
|
13
|
-
#
|
14
|
-
ib = IB::Connection.new :client_id => 1112
|
13
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
14
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
15
15
|
|
16
16
|
# Subscribe to TWS alerts/errors
|
17
17
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
data/bin/tick_data
CHANGED
@@ -16,7 +16,8 @@ contract = IB::Models::Contract.new :symbol=> 'AAPL',
|
|
16
16
|
:sec_type=> IB::SECURITY_TYPES[:stock],
|
17
17
|
:description=> "Some stock"
|
18
18
|
|
19
|
-
|
19
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
20
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
20
21
|
|
21
22
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
22
23
|
ib.subscribe(:TickGeneric, :TickString, :TickPrice, :TickSize) { |msg| puts msg.inspect }
|
data/bin/time_and_sales
CHANGED
@@ -20,14 +20,12 @@ require 'ib-ruby'
|
|
20
20
|
# To determine when the timeout has passed.
|
21
21
|
@last_msg_time = Time.now.to_i + 2
|
22
22
|
|
23
|
-
#
|
24
|
-
ib = IB::Connection.new :client_id => 1112
|
23
|
+
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
24
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
25
25
|
|
26
26
|
# Subscribe to TWS alerts/errors
|
27
27
|
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
28
28
|
|
29
|
-
MIN_SIZE = 0
|
30
|
-
|
31
29
|
# This method filters out non-:last type events, and filters out any sale < MIN_SIZE.
|
32
30
|
# Note that we have to look the ticker id of each incoming message
|
33
31
|
# up in local memory to figure out what it's for.
|
data/lib/ib-ruby/models/order.rb
CHANGED
@@ -475,7 +475,6 @@ module IB
|
|
475
475
|
aux_price == other.aux_price &&
|
476
476
|
outside_rth == other.outside_rth &&
|
477
477
|
origin == other.origin &&
|
478
|
-
transmit == other.transmit &&
|
479
478
|
designated_location == other.designated_location &&
|
480
479
|
exempt_code == other.exempt_code &&
|
481
480
|
what_if == other.what_if &&
|
data/spec/README.md
CHANGED
@@ -2,33 +2,41 @@
|
|
2
2
|
|
3
3
|
Pattern for writing integration specs is like this:
|
4
4
|
|
5
|
-
1. You define your user scenario (such as: subscribe for
|
5
|
+
1. You define your user scenario (such as: subscribe for FUTURES market data).
|
6
6
|
|
7
7
|
2. You find out experimentally, what messages should be sent to IB to accomplish it,
|
8
8
|
and what messages are sent by IB in return.
|
9
9
|
|
10
|
-
3. You start writing spec, requiring 'integration_helper'.
|
10
|
+
3. You start writing spec, requiring 'integration_helper'. Don't forget to
|
11
|
+
'verify_account'! Running tests against live IB account can be pretty painful.
|
11
12
|
|
12
|
-
4.
|
13
|
-
|
14
|
-
and placed into @received Hash, keyed by message type.
|
13
|
+
4. Establish connection in a top-level before(:all) block. Wait for IB to deliver
|
14
|
+
initial messages/data, for example using '@ib.wait_for :NextValidId' idiom.
|
15
15
|
|
16
|
-
5.
|
16
|
+
5. Now, you set up your context and send appropriate request messages to IB. Once
|
17
|
+
messages are sent, you need to give the server time to respond. The proper way
|
18
|
+
to do it is by '@ib.wait_for' specific message type that indicates that your
|
19
|
+
request was answered. For example, if you send :RequestOpenOrders, then received
|
20
|
+
:OpenOrdersEnd will be a sign that your request was processed. Usually, you
|
21
|
+
wait_for in a context before(:all) block.
|
17
22
|
|
18
|
-
6.
|
19
|
-
|
23
|
+
6. It is now time to examine what responses you've got from IB and see if they meet
|
24
|
+
your expectations. All messages received frem IB are caught and placed into
|
25
|
+
@ib.received Hash, keyed by message type. The Hash has following structure:
|
26
|
+
{:MessageType1 => [msg1, msg2, msg3...], :MessageType2 => [msg1, msg2, msg3...] }.
|
20
27
|
|
21
|
-
7.
|
22
|
-
|
28
|
+
7. If you created @ib Connection with mock_logger, all log entries produced by IB
|
29
|
+
will be also caught and placed into log_entries Array.
|
23
30
|
|
24
|
-
8.
|
31
|
+
8. Your examples can thus test the content of @ib.received Hash to see what messages
|
32
|
+
were received, or log_entries Array to see what was logged.
|
25
33
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
9. When done with this context, you call 'close_connection' helper in a top-level
|
35
|
+
after(:all) block to get rid of your active connection.
|
36
|
+
|
37
|
+
10. If you reuse the connection between contexts and requests, it is recommended to
|
38
|
+
call 'clean_connection' in after block to remove old content from @ib.received Hash,
|
39
|
+
or otherwise manually clean it to remove old/not needed messages from it.
|
40
|
+
|
41
|
+
Help the development!
|
42
|
+
See 'spec/TODO' file for list of scenarios that still need to be tested.
|
data/spec/TODO
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
TODO: Add more scenarios:
|
2
|
+
|
3
|
+
1. RealTimeBars
|
4
|
+
2. BondContractData
|
5
|
+
3. RequestScannerParameters + RequestScannerSubscription
|
6
|
+
4. RequestFundamentalData
|
7
|
+
5. ExerciseOptions
|
8
|
+
6. RequestMarketData + special tick list
|
9
|
+
7. RequestNewsBulletins
|
10
|
+
8. RequestImpliedVolatility / RequestOptionPrice
|
@@ -7,7 +7,7 @@ shared_examples_for 'Alert message' do
|
|
7
7
|
its(:message_type) { should == :Alert }
|
8
8
|
its(:message_id) { should == 4 }
|
9
9
|
its(:version) { should == 2 }
|
10
|
-
its(:data) {
|
10
|
+
its(:data) { should_not be_empty }
|
11
11
|
its(:error_id) { should == -1 }
|
12
12
|
its(:code) { should == 2104 }
|
13
13
|
its(:message) { should =~ /Market data farm connection is OK/ }
|
@@ -28,7 +28,7 @@ def butterfly symbol, expiry, right, *strikes
|
|
28
28
|
:legs => legs
|
29
29
|
end
|
30
30
|
|
31
|
-
describe "Combo Order", :connected => true, :integration => true do
|
31
|
+
describe "Combo Order", :connected => true, :integration => true, :slow => true do
|
32
32
|
|
33
33
|
before(:all) { verify_account }
|
34
34
|
|
@@ -38,14 +38,60 @@ describe "Combo Order", :connected => true, :integration => true do
|
|
38
38
|
@ib.wait_for :NextValidId
|
39
39
|
@ib.clear_received # to avoid conflict with pre-existing Orders
|
40
40
|
|
41
|
-
@
|
41
|
+
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
42
42
|
|
43
|
-
place_order @
|
44
|
-
@ib.wait_for
|
43
|
+
place_order @contract, :limit_price => 0.01 #, :what_if => true
|
44
|
+
@ib.wait_for :OpenOrder, :OrderStatus, 5
|
45
45
|
end
|
46
46
|
|
47
47
|
after(:all) { close_connection }
|
48
48
|
|
49
49
|
it_behaves_like 'Placed Order'
|
50
50
|
end # Limit
|
51
|
+
|
52
|
+
context "Limit with attached takeprofit" do
|
53
|
+
before(:all) do
|
54
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
55
|
+
@ib.wait_for :NextValidId
|
56
|
+
@ib.clear_received # to avoid conflict with pre-existing Orders
|
57
|
+
|
58
|
+
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
59
|
+
|
60
|
+
place_order @contract, :limit_price => 0.01, :transmit => false
|
61
|
+
@ib.wait_for :OpenOrder, :OrderStatus, 2
|
62
|
+
end
|
63
|
+
|
64
|
+
after(:all) { close_connection }
|
65
|
+
|
66
|
+
it 'does not transmit original Order just yet' do
|
67
|
+
@ib.received[:OpenOrder].should have_exactly(0).order_message
|
68
|
+
@ib.received[:OrderStatus].should have_exactly(0).status_message
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'Attaching takeprofit' do
|
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, :OrderStatus, 5
|
82
|
+
end
|
83
|
+
|
84
|
+
it_behaves_like 'Placed Order'
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'When original Order cancels' do
|
88
|
+
it 'attached takeprofit is cancelled implicitely' do
|
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
|
51
96
|
end # Combo Orders
|
97
|
+
|
@@ -50,7 +50,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
50
50
|
it { @ib.received[:ExecutionDataEnd].should be_empty }
|
51
51
|
|
52
52
|
it 'receives filled OpenOrder' do
|
53
|
-
order_should_be 'Filled'
|
53
|
+
order_should_be 'Filled'
|
54
54
|
msg = @ib.received[:OpenOrder].last
|
55
55
|
msg.order.commission.should == 2.5
|
56
56
|
end
|
@@ -60,7 +60,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'receives OrderStatus with fill details' do
|
63
|
-
status_should_be 'Filled'
|
63
|
+
status_should_be 'Filled'
|
64
64
|
end
|
65
65
|
end # Placing BUY
|
66
66
|
|
@@ -92,7 +92,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
92
92
|
it { @ib.received[:ExecutionData].should have_exactly(1).execution_data }
|
93
93
|
|
94
94
|
it 'receives filled OpenOrder' do
|
95
|
-
order_should_be 'Filled'
|
95
|
+
order_should_be 'Filled'
|
96
96
|
msg = @ib.received[:OpenOrder].last
|
97
97
|
msg.order.commission.should == 2.5
|
98
98
|
end
|
@@ -102,7 +102,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
|
|
102
102
|
end
|
103
103
|
|
104
104
|
it 'receives OrderStatus with fill details' do
|
105
|
-
status_should_be 'Filled'
|
105
|
+
status_should_be 'Filled'
|
106
106
|
end
|
107
107
|
end # Placing SELL
|
108
108
|
|
@@ -77,3 +77,22 @@ This is just a dump file to compare received order messages:
|
|
77
77
|
:why_held=>""},
|
78
78
|
@socket=nil>]
|
79
79
|
|
80
|
+
Original Combo: Attached Auto Combo Limit:
|
81
|
+
|
82
|
+
<Order: LMT DAY BUY 100 PreSubmitted 0.01 2: <Order: LMT DAY SELL 100 PreSubmitted 1.01
|
83
|
+
id: 3/173276893 from: 1111/DU118180>> id: 0/173276895 from: 0/DU118180>>
|
84
|
+
#<IB::Models::Order:0xfa0 #<IB::Models::Order:0x102c
|
85
|
+
@action="BUY", @action="SELL",
|
86
|
+
@client_id=1111, @client_id=0, # Attached via TWS
|
87
|
+
@created_at=Fri Mar 23 09:09:16 +0400 2012, @created_at=Fri Mar 23 09:09:16 +0400 2012,
|
88
|
+
@limit_price=0.01, @limit_price=1.01,
|
89
|
+
@oca_group="", @oca_group="173276893",
|
90
|
+
@oca_type=3, @oca_type=3,
|
91
|
+
@order_id=3, @order_id=0,
|
92
|
+
@order_type="LMT", @order_type="LMT",
|
93
|
+
@parent_id=0, @parent_id=3,
|
94
|
+
@perm_id=173276893, @perm_id=173276895,
|
95
|
+
@status="PreSubmitted", @status="PreSubmitted",
|
96
|
+
@tif="DAY", @tif="DAY",
|
97
|
+
@total_quantity=100, @total_quantity=100,
|
98
|
+
@what_if=false> @what_if=false>
|
data/spec/order_helper.rb
CHANGED
@@ -6,7 +6,7 @@ shared_examples_for 'Placed Order' do
|
|
6
6
|
|
7
7
|
it 'changes client`s next_order_id' do
|
8
8
|
@order_id_placed.should == @order_id_before
|
9
|
-
@ib.next_order_id.should
|
9
|
+
@ib.next_order_id.should be >= @order_id_before
|
10
10
|
end
|
11
11
|
|
12
12
|
it { @ib.received[:OpenOrder].should have_at_least(1).order_message }
|
@@ -30,10 +30,11 @@ shared_examples_for 'Placed Order' do
|
|
30
30
|
@ib.next_order_id.should == @order_id_after
|
31
31
|
end
|
32
32
|
|
33
|
-
it { @ib.received[:OpenOrder].should
|
34
|
-
it { @ib.received[:OrderStatus].should
|
33
|
+
it { @ib.received[:OpenOrder].should have_at_least(1).order_message }
|
34
|
+
it { @ib.received[:OrderStatus].should have_at_least(1).status_message }
|
35
35
|
it { @ib.received[:OpenOrderEnd].should have_exactly(1).order_end_message }
|
36
|
-
|
36
|
+
|
37
|
+
#it { @ib.received[:Alert].should have_exactly(0).alert_messages }
|
37
38
|
|
38
39
|
it 'receives OpenOrder and OrderStatus for placed order' do
|
39
40
|
order_should_be /Submitted/
|
@@ -44,7 +45,7 @@ shared_examples_for 'Placed Order' do
|
|
44
45
|
context "Cancelling placed order" do
|
45
46
|
before(:all) do
|
46
47
|
@ib.cancel_order @order_id_placed
|
47
|
-
@ib.wait_for :OrderStatus, :Alert
|
48
|
+
@ib.wait_for [:OrderStatus, 2], :Alert
|
48
49
|
end
|
49
50
|
|
50
51
|
after(:all) { clean_connection } # Clear logs and message collector
|
@@ -57,8 +58,8 @@ shared_examples_for 'Placed Order' do
|
|
57
58
|
@ib.received?(:OpenOrder).should be_false
|
58
59
|
end
|
59
60
|
|
60
|
-
it { @ib.received[:OrderStatus].should
|
61
|
-
it { @ib.received[:Alert].should
|
61
|
+
it { @ib.received[:OrderStatus].should have_at_least(1).status_message }
|
62
|
+
it { @ib.received[:Alert].should have_at_least(1).alert_message }
|
62
63
|
|
63
64
|
it 'receives cancellation Order Status' do
|
64
65
|
status_should_be /Cancel/ # Cancelled / PendingCancel
|
@@ -86,24 +87,18 @@ def place_order contract, opts
|
|
86
87
|
@order_id_after = @ib.next_order_id
|
87
88
|
end
|
88
89
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
when String
|
94
|
-
item.status.should == status
|
90
|
+
def status_should_be status
|
91
|
+
msg = @ib.received[:OrderStatus].find do |msg|
|
92
|
+
msg.order_id == @order_id_placed &&
|
93
|
+
status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
|
95
94
|
end
|
96
|
-
|
97
|
-
|
98
|
-
def status_should_be status, index=0
|
99
|
-
msg = @ib.received[:OrderStatus][index]
|
95
|
+
msg.should_not be_nil
|
100
96
|
msg.should be_an IB::Messages::Incoming::OrderStatus
|
101
97
|
msg.order_id.should == @order_id_placed
|
102
98
|
msg.perm_id.should be_an Integer
|
103
99
|
msg.client_id.should == OPTS[:connection][:client_id]
|
104
100
|
msg.parent_id.should == 0
|
105
101
|
msg.why_held.should == ''
|
106
|
-
check_status msg, status
|
107
102
|
|
108
103
|
if @contract == IB::Symbols::Forex[:eurusd]
|
109
104
|
msg.filled.should == 20000
|
@@ -119,13 +114,16 @@ def status_should_be status, index=0
|
|
119
114
|
end
|
120
115
|
end
|
121
116
|
|
122
|
-
def order_should_be status
|
123
|
-
msg = @ib.received[:OpenOrder]
|
117
|
+
def order_should_be status
|
118
|
+
msg = @ib.received[:OpenOrder].find do |msg|
|
119
|
+
msg.order_id == @order_id_placed &&
|
120
|
+
status.is_a?(Regexp) ? msg.status =~ status : msg.status == status
|
121
|
+
end
|
122
|
+
msg.should_not be_nil
|
124
123
|
msg.should be_an IB::Messages::Incoming::OpenOrder
|
125
124
|
msg.order.should == @order
|
126
125
|
msg.contract.should == @contract
|
127
126
|
msg.order.order_id.should == @order_id_placed
|
128
|
-
check_status msg.order, status
|
129
127
|
end
|
130
128
|
|
131
129
|
def execution_should_be side, opts={}
|
data/spec/spec_helper.rb
CHANGED
@@ -41,6 +41,6 @@ else
|
|
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
43
|
:host => '10.211.55.2', # Where your TWS/gateway is located, likely 'localhost'
|
44
|
-
:port=> 4001 # 4001 for Gateway, 7496 for TWS GUI
|
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.2
|
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-03-
|
14
|
+
date: 2012-03-23 00:00:00 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- spec/order_helper.rb
|
120
120
|
- spec/README.md
|
121
121
|
- spec/spec_helper.rb
|
122
|
+
- spec/TODO
|
122
123
|
- spec/ib-ruby/connection_spec.rb
|
123
124
|
- spec/ib-ruby/messages/incoming_spec.rb
|
124
125
|
- spec/ib-ruby/messages/outgoing_spec.rb
|
@@ -184,6 +185,7 @@ test_files:
|
|
184
185
|
- spec/order_helper.rb
|
185
186
|
- spec/README.md
|
186
187
|
- spec/spec_helper.rb
|
188
|
+
- spec/TODO
|
187
189
|
- spec/ib-ruby/connection_spec.rb
|
188
190
|
- spec/ib-ruby/messages/incoming_spec.rb
|
189
191
|
- spec/ib-ruby/messages/outgoing_spec.rb
|