ib-ruby 0.7.0 → 0.7.2
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/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
|