ib-ruby 0.7.4 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/HISTORY +8 -0
- data/README.md +2 -2
- data/Rakefile +15 -0
- data/TODO +7 -2
- 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/fa_accounts +1 -1
- data/bin/fundamental_data +42 -0
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +1 -1
- data/bin/list_orders +1 -2
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +1 -1
- data/bin/place_order +1 -1
- data/bin/template +1 -4
- data/bin/tick_data +2 -2
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +4 -0
- data/lib/ib-ruby/connection.rb +50 -34
- data/lib/ib-ruby/constants.rb +232 -37
- data/lib/ib-ruby/db.rb +25 -0
- data/lib/ib-ruby/extensions.rb +51 -1
- data/lib/ib-ruby/messages/abstract_message.rb +0 -8
- data/lib/ib-ruby/messages/incoming.rb +18 -493
- data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
- data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
- data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
- data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
- data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
- data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
- data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
- data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
- data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
- data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
- data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
- data/lib/ib-ruby/messages/outgoing.rb +25 -223
- data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
- data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
- data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
- data/lib/ib-ruby/models.rb +4 -0
- data/lib/ib-ruby/models/bar.rb +31 -14
- data/lib/ib-ruby/models/combo_leg.rb +48 -23
- data/lib/ib-ruby/models/contracts.rb +2 -2
- data/lib/ib-ruby/models/contracts/bag.rb +11 -7
- data/lib/ib-ruby/models/contracts/contract.rb +90 -66
- data/lib/ib-ruby/models/contracts/option.rb +16 -7
- data/lib/ib-ruby/models/execution.rb +34 -18
- data/lib/ib-ruby/models/model.rb +15 -7
- data/lib/ib-ruby/models/model_properties.rb +101 -44
- data/lib/ib-ruby/models/order.rb +176 -187
- data/lib/ib-ruby/models/order_state.rb +99 -0
- data/lib/ib-ruby/symbols/forex.rb +10 -10
- data/lib/ib-ruby/symbols/futures.rb +6 -6
- data/lib/ib-ruby/symbols/stocks.rb +3 -3
- data/spec/account_helper.rb +4 -5
- data/spec/combo_helper.rb +4 -4
- data/spec/db.rb +18 -0
- data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
- data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
- data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
- data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
- data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
- data/spec/ib-ruby/models/bag_spec.rb +97 -0
- data/spec/ib-ruby/models/bar_spec.rb +45 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
- data/spec/ib-ruby/models/contract_spec.rb +134 -170
- data/spec/ib-ruby/models/execution_spec.rb +35 -50
- data/spec/ib-ruby/models/option_spec.rb +127 -0
- data/spec/ib-ruby/models/order_spec.rb +89 -68
- data/spec/ib-ruby/models/order_state_spec.rb +55 -0
- data/spec/integration/contract_info_spec.rb +4 -6
- data/spec/integration/fundamental_data_spec.rb +41 -0
- data/spec/integration/historic_data_spec.rb +4 -4
- data/spec/integration/market_data_spec.rb +1 -3
- data/spec/integration/orders/attached_spec.rb +8 -10
- data/spec/integration/orders/combo_spec.rb +2 -2
- data/spec/integration/orders/execution_spec.rb +0 -1
- data/spec/integration/orders/placement_spec.rb +1 -3
- data/spec/integration/orders/valid_ids_spec.rb +1 -2
- data/spec/message_helper.rb +1 -1
- data/spec/model_helper.rb +211 -0
- data/spec/order_helper.rb +44 -37
- data/spec/spec_helper.rb +36 -23
- data/spec/v.rb +7 -0
- data/tasks/doc.rake +1 -1
- metadata +116 -12
- data/spec/integration/orders/open_order +0 -98
@@ -0,0 +1,99 @@
|
|
1
|
+
module IB
|
2
|
+
module Models
|
3
|
+
|
4
|
+
# OrderState represents dynamic (changeable) info about a single Order,
|
5
|
+
# isolating these changes and making Order essentially immutable
|
6
|
+
class OrderState < Model.for(:order_state)
|
7
|
+
include ModelProperties
|
8
|
+
|
9
|
+
#p column_names
|
10
|
+
# has_one :order
|
11
|
+
|
12
|
+
# Properties arriving via OpenOrder message
|
13
|
+
prop :init_margin, # Float: The impact the order would have on your initial margin.
|
14
|
+
:maint_margin, # Float: The impact the order would have on your maintenance margin.
|
15
|
+
:equity_with_loan, # Float: The impact the order would have on your equity
|
16
|
+
:commission, # double: Shows the commission amount on the order.
|
17
|
+
:min_commission, # The possible min range of the actual order commission.
|
18
|
+
:max_commission, # The possible max range of the actual order commission.
|
19
|
+
:commission_currency, # String: Shows the currency of the commission.
|
20
|
+
:warning_text # String: Displays a warning message if warranted.
|
21
|
+
|
22
|
+
# Properties arriving via OrderStatus message:
|
23
|
+
prop :filled, # int
|
24
|
+
:remaining, # int
|
25
|
+
:average_fill_price, # double
|
26
|
+
:last_fill_price, # double
|
27
|
+
:why_held # String: comma-separated list of reasons for order to be held.
|
28
|
+
|
29
|
+
# Properties arriving in both messages:
|
30
|
+
prop :order_id, # int: Order id associated with client (volatile).
|
31
|
+
:perm_id, # int: TWS permanent id, remains the same over TWS sessions.
|
32
|
+
:client_id, # int: The id of the client that placed this order.
|
33
|
+
:parent_id, # int: The order ID of the parent (original) order, used
|
34
|
+
:status # String: Displays the order status. Possible values include:
|
35
|
+
# - PendingSubmit - indicates that you have transmitted the order, but
|
36
|
+
# have not yet received confirmation that it has been accepted by the
|
37
|
+
# order destination. NOTE: This order status is NOT sent back by TWS
|
38
|
+
# and should be explicitly set by YOU when an order is submitted.
|
39
|
+
# - PendingCancel - indicates that you have sent a request to cancel
|
40
|
+
# the order but have not yet received cancel confirmation from the
|
41
|
+
# order destination. At this point, your order cancel is not confirmed.
|
42
|
+
# You may still receive an execution while your cancellation request
|
43
|
+
# is pending. NOTE: This order status is not sent back by TWS and
|
44
|
+
# should be explicitly set by YOU when an order is canceled.
|
45
|
+
# - PreSubmitted - indicates that a simulated order type has been
|
46
|
+
# accepted by the IB system and that this order has yet to be elected.
|
47
|
+
# The order is held in the IB system until the election criteria are
|
48
|
+
# met. At that time the order is transmitted to the order destination
|
49
|
+
# as specified.
|
50
|
+
# - Submitted - indicates that your order has been accepted at the order
|
51
|
+
# destination and is working.
|
52
|
+
# - Cancelled - indicates that the balance of your order has been
|
53
|
+
# confirmed canceled by the IB system. This could occur unexpectedly
|
54
|
+
# when IB or the destination has rejected your order.
|
55
|
+
# - ApiCancelled - canceled via API
|
56
|
+
# - Filled - indicates that the order has been completely filled.
|
57
|
+
# - Inactive - indicates that the order has been accepted by the system
|
58
|
+
# (simulated orders) or an exchange (native orders) but that currently
|
59
|
+
# the order is inactive due to system, exchange or other issues.
|
60
|
+
|
61
|
+
prop :tester
|
62
|
+
|
63
|
+
validates_numericality_of :order_id, :perm_id, :client_id, :only_integer => true
|
64
|
+
|
65
|
+
DEFAULT_PROPS = {:status => 'New'} # Starting new Orders with this status
|
66
|
+
|
67
|
+
# Comparison
|
68
|
+
def == other
|
69
|
+
other && other.is_a?(OrderState) &&
|
70
|
+
status == other.status &&
|
71
|
+
order_id == other.order_id &&
|
72
|
+
perm_id == other.perm_id &&
|
73
|
+
client_id == other.client_id &&
|
74
|
+
filled == other.filled &&
|
75
|
+
remaining == other.remaining &&
|
76
|
+
last_fill_price == other.last_fill_price &&
|
77
|
+
init_margin == other.init_margin &&
|
78
|
+
maint_margin == other.maint_margin &&
|
79
|
+
equity_with_loan == other.equity_with_loan &&
|
80
|
+
why_held == other.why_held &&
|
81
|
+
warning_text == other.warning_text &&
|
82
|
+
commission == other.commission
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_human
|
86
|
+
"<OrderState: #{status} ##{order_id}/#{perm_id} from #{client_id}" +
|
87
|
+
(filled ? " filled #{filled}/#{remaining}" : '') +
|
88
|
+
(last_fill_price ? " at #{last_fill_price}/#{average_fill_price}" : '') +
|
89
|
+
(init_margin ? " margin #{init_margin}/#{maint_margin}" : '') +
|
90
|
+
(equity_with_loan ? " equity #{equity_with_loan}" : '') +
|
91
|
+
(commission && commission > 0 ? " fee #{commission}" : "") +
|
92
|
+
(why_held ? " why_held #{why_held}" : '') +
|
93
|
+
((warning_text && warning_text != '') ? " warning #{warning_text}" : '') + ">"
|
94
|
+
end
|
95
|
+
|
96
|
+
alias to_s to_human
|
97
|
+
end # class Order
|
98
|
+
end # module Models
|
99
|
+
end # module IB
|
@@ -10,61 +10,61 @@ module IB
|
|
10
10
|
:audusd => IB::Contract.new(:symbol => "AUD",
|
11
11
|
:exchange => "IDEALPRO",
|
12
12
|
:currency => "USD",
|
13
|
-
:sec_type =>
|
13
|
+
:sec_type => :forex,
|
14
14
|
:description => "AUDUSD"),
|
15
15
|
|
16
16
|
:gbpusd => IB::Contract.new(:symbol => "GBP",
|
17
17
|
:exchange => "IDEALPRO",
|
18
18
|
:currency => "USD",
|
19
|
-
:sec_type =>
|
19
|
+
:sec_type => :forex,
|
20
20
|
:description => "GBPUSD"),
|
21
21
|
|
22
22
|
:euraud => IB::Contract.new(:symbol => "EUR",
|
23
23
|
:exchange => "IDEALPRO",
|
24
24
|
:currency => "AUD",
|
25
|
-
:sec_type =>
|
25
|
+
:sec_type => :forex,
|
26
26
|
:description => "EURAUD"),
|
27
27
|
|
28
28
|
:eurgbp => IB::Contract.new(:symbol => "EUR",
|
29
29
|
:exchange => "IDEALPRO",
|
30
30
|
:currency => "GBP",
|
31
|
-
:sec_type =>
|
31
|
+
:sec_type => :forex,
|
32
32
|
:description => "EURGBP"),
|
33
33
|
|
34
34
|
:eurjpy => IB::Contract.new(:symbol => "EUR",
|
35
35
|
:exchange => "IDEALPRO",
|
36
36
|
:currency => "JPY",
|
37
|
-
:sec_type =>
|
37
|
+
:sec_type => :forex,
|
38
38
|
:description => "EURJPY"),
|
39
39
|
|
40
40
|
:eurusd => IB::Contract.new(:symbol => "EUR",
|
41
41
|
:exchange => "IDEALPRO",
|
42
42
|
:currency => "USD",
|
43
|
-
:sec_type =>
|
43
|
+
:sec_type => :forex,
|
44
44
|
:description => "EURUSD"),
|
45
45
|
|
46
46
|
:eurcad => IB::Contract.new(:symbol => "EUR",
|
47
47
|
:exchange => "IDEALPRO",
|
48
48
|
:currency => "CAD",
|
49
|
-
:sec_type =>
|
49
|
+
:sec_type => :forex,
|
50
50
|
:description => "EURCAD"),
|
51
51
|
|
52
52
|
:usdchf => IB::Contract.new(:symbol => "USD",
|
53
53
|
:exchange => "IDEALPRO",
|
54
54
|
:currency => "CHF",
|
55
|
-
:sec_type =>
|
55
|
+
:sec_type => :forex,
|
56
56
|
:description => "USDCHF"),
|
57
57
|
|
58
58
|
:usdcad => IB::Contract.new(:symbol => "USD",
|
59
59
|
:exchange => "IDEALPRO",
|
60
60
|
:currency => "CAD",
|
61
|
-
:sec_type =>
|
61
|
+
:sec_type => :forex,
|
62
62
|
:description => "USDCAD"),
|
63
63
|
|
64
64
|
:usdjpy => IB::Contract.new(:symbol => "USD",
|
65
65
|
:exchange => "IDEALPRO",
|
66
66
|
:currency => "JPY",
|
67
|
-
:sec_type =>
|
67
|
+
:sec_type => :forex,
|
68
68
|
:description => "USDJPY")
|
69
69
|
}
|
70
70
|
end
|
@@ -66,14 +66,14 @@ module IB
|
|
66
66
|
:expiry => next_expiry,
|
67
67
|
:exchange => "ECBOT",
|
68
68
|
:currency => "USD",
|
69
|
-
:sec_type =>
|
69
|
+
:sec_type => :future,
|
70
70
|
:description => "Mini Dow Jones Industrial"),
|
71
71
|
|
72
72
|
:es => IB::Contract.new(:symbol => "ES",
|
73
73
|
:expiry => next_expiry,
|
74
74
|
:exchange => "GLOBEX",
|
75
75
|
:currency => "USD",
|
76
|
-
:sec_type =>
|
76
|
+
:sec_type => :future,
|
77
77
|
:multiplier => 50,
|
78
78
|
:description => "E-Mini S&P 500"),
|
79
79
|
|
@@ -81,7 +81,7 @@ module IB
|
|
81
81
|
:expiry => next_expiry,
|
82
82
|
:exchange => "GLOBEX",
|
83
83
|
:currency => "USD",
|
84
|
-
:sec_type =>
|
84
|
+
:sec_type => :future,
|
85
85
|
:multiplier => 62500,
|
86
86
|
:description => "British Pounds"),
|
87
87
|
|
@@ -89,7 +89,7 @@ module IB
|
|
89
89
|
:expiry => next_expiry,
|
90
90
|
:exchange => "GLOBEX",
|
91
91
|
:currency => "USD",
|
92
|
-
:sec_type =>
|
92
|
+
:sec_type => :future,
|
93
93
|
:multiplier => 12500,
|
94
94
|
:description => "Euro FX"),
|
95
95
|
|
@@ -97,7 +97,7 @@ module IB
|
|
97
97
|
:expiry => next_expiry,
|
98
98
|
:exchange => "GLOBEX",
|
99
99
|
:currency => "USD",
|
100
|
-
:sec_type =>
|
100
|
+
:sec_type => :future,
|
101
101
|
:multiplier => 12500000,
|
102
102
|
:description => "Japanese Yen"),
|
103
103
|
|
@@ -105,7 +105,7 @@ module IB
|
|
105
105
|
:expiry => next_expiry,
|
106
106
|
:exchange => "HKFE",
|
107
107
|
:currency => "HKD",
|
108
|
-
:sec_type =>
|
108
|
+
:sec_type => :future,
|
109
109
|
:multiplier => 50,
|
110
110
|
:description => "Hang Seng Index")
|
111
111
|
}
|
@@ -11,18 +11,18 @@ module IB
|
|
11
11
|
{:wfc => IB::Contract.new(:symbol => "WFC",
|
12
12
|
:exchange => "NYSE",
|
13
13
|
:currency => "USD",
|
14
|
-
:sec_type =>
|
14
|
+
:sec_type => :stock,
|
15
15
|
:description => "Wells Fargo"),
|
16
16
|
|
17
17
|
:aapl => IB::Contract.new(:symbol => "AAPL",
|
18
18
|
:currency => "USD",
|
19
|
-
:sec_type =>
|
19
|
+
:sec_type => :stock,
|
20
20
|
:description => "Apple Inc."),
|
21
21
|
|
22
22
|
:wrong => IB::Contract.new(:symbol => "QEEUUE",
|
23
23
|
:exchange => "NYSE",
|
24
24
|
:currency => "USD",
|
25
|
-
:sec_type =>
|
25
|
+
:sec_type => :stock,
|
26
26
|
:description => "Non-existent stock"),
|
27
27
|
}
|
28
28
|
end
|
data/spec/account_helper.rb
CHANGED
@@ -14,13 +14,12 @@ def verify_account
|
|
14
14
|
raise "Please configure IB PAPER ACCOUNT in spec/spec_helper.rb" unless account
|
15
15
|
|
16
16
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
17
|
-
@ib.send_message :RequestAccountData, :subscribe => true
|
18
17
|
|
19
|
-
@ib.wait_for :
|
20
|
-
@ib.
|
21
|
-
raise "Unable to verify IB PAPER ACCOUNT" unless @ib.received?(:
|
18
|
+
@ib.wait_for :ManagedAccounts, 5
|
19
|
+
puts @ib.received.map { |type, msg| [" #{type}:", msg.map(&:to_human)] }
|
20
|
+
raise "Unable to verify IB PAPER ACCOUNT" unless @ib.received?(:ManagedAccounts)
|
22
21
|
|
23
|
-
received = @ib.received[:
|
22
|
+
received = @ib.received[:ManagedAccounts].first.accounts_list
|
24
23
|
raise "Connected to wrong account #{received}, expected #{account}" if account != received
|
25
24
|
|
26
25
|
close_connection
|
data/spec/combo_helper.rb
CHANGED
@@ -2,16 +2,16 @@ require 'integration_helper'
|
|
2
2
|
|
3
3
|
# Define butterfly
|
4
4
|
def butterfly symbol, expiry, right, *strikes
|
5
|
-
unless @ib && @ib.connected?
|
6
|
-
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
7
|
-
end
|
5
|
+
raise 'Unable to create butterfly, no connection' unless @ib && @ib.connected?
|
8
6
|
|
9
7
|
legs = strikes.zip([1, -2, 1]).map do |strike, weight|
|
8
|
+
|
10
9
|
# Create contract
|
11
10
|
contract = IB::Option.new :symbol => symbol,
|
12
11
|
:expiry => expiry,
|
13
12
|
:right => right,
|
14
13
|
:strike => strike
|
14
|
+
|
15
15
|
# Find out contract's con_id
|
16
16
|
@ib.clear_received :ContractData, :ContractDataEnd
|
17
17
|
@ib.send_message :RequestContractData, :id => strike, :contract => contract
|
@@ -22,7 +22,7 @@ def butterfly symbol, expiry, right, *strikes
|
|
22
22
|
IB::ComboLeg.new :con_id => con_id, :weight => weight
|
23
23
|
end
|
24
24
|
|
25
|
-
#
|
25
|
+
# Return butterfly Combo
|
26
26
|
IB::Bag.new :symbol => symbol,
|
27
27
|
:currency => "USD", # Only US options in combo Contracts
|
28
28
|
:exchange => "SMART",
|
data/spec/db.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
puts 'To run specs with database backend (ActiveRecord), use:'
|
2
|
+
puts '$ rspec -rdb spec'
|
3
|
+
|
4
|
+
require 'yaml'
|
5
|
+
require 'pathname'
|
6
|
+
require 'ib-ruby/db'
|
7
|
+
require 'database_cleaner'
|
8
|
+
|
9
|
+
# Load DB config, determine correct environment
|
10
|
+
db_file = Pathname.new(__FILE__).realpath.dirname + '../db/config.yml'
|
11
|
+
raise "Unable to find DB config file: #{db_file}" unless db_file.exist?
|
12
|
+
|
13
|
+
env = RUBY_PLATFORM =~ /java/ ? 'test-jruby' : 'test'
|
14
|
+
db_config = YAML::load_file(db_file)[env]
|
15
|
+
|
16
|
+
# Establish connection to test DB
|
17
|
+
IB::DB.connect db_config
|
18
|
+
|
@@ -39,6 +39,7 @@ describe IB::Messages::Incoming do
|
|
39
39
|
before(:all) do
|
40
40
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
41
41
|
@ib.wait_for :Alert
|
42
|
+
pending 'No Alert received upon connect!' unless @ib.received? :Alert
|
42
43
|
end
|
43
44
|
|
44
45
|
after(:all) { close_connection }
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'order_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'OpenOrder message' do
|
4
|
+
it { should be_an IB::Messages::Incoming::OpenOrder }
|
5
|
+
its(:message_type) { should == :OpenOrder }
|
6
|
+
its(:message_id) { should == 5 }
|
7
|
+
its(:version) { should == 28 }
|
8
|
+
its(:data) { should_not be_empty }
|
9
|
+
its(:order_id) { should be_an Integer }
|
10
|
+
its(:status) { should =~ /Submit/ }
|
11
|
+
its(:to_human) { should =~
|
12
|
+
/<OpenOrder: <Contract: WFC stock NYSE USD> <Order: LMT DAY buy 100 .*Submit.* 9.13 #\d+\/\d+ from 1111/ }
|
13
|
+
|
14
|
+
it 'has proper contract accessor' do
|
15
|
+
c = subject.contract
|
16
|
+
c.should be_an IB::Contract
|
17
|
+
c.symbol.should == 'WFC'
|
18
|
+
c.exchange.should == 'NYSE'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has proper order accessor' do
|
22
|
+
o = subject.order
|
23
|
+
o.should be_an IB::Order
|
24
|
+
o.client_id.should == 1111
|
25
|
+
o.parent_id.should == 0
|
26
|
+
o.order_id.should be_an Integer
|
27
|
+
o.perm_id.should be_an Integer
|
28
|
+
o.order_type.should == :limit
|
29
|
+
o.tif.should == :day
|
30
|
+
o.status.should =~ /Submit/
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'has proper order_state accessor' do
|
34
|
+
os = subject.order_state
|
35
|
+
os.order_id.should be_an Integer
|
36
|
+
os.perm_id.should be_an Integer
|
37
|
+
os.client_id.should == 1111
|
38
|
+
os.parent_id.should == 0
|
39
|
+
os.status.should =~ /Submit/
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'has class accessors as well' do
|
43
|
+
subject.class.message_id.should == 5
|
44
|
+
subject.class.version.should == [23, 28] # Two message versions supported
|
45
|
+
subject.class.message_type.should == :OpenOrder
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe IB::Messages::Incoming::OpenOrder do
|
51
|
+
|
52
|
+
context 'Instantiated with data Hash' do
|
53
|
+
subject do
|
54
|
+
IB::Messages::Incoming::OpenOrder.new :version => 28,
|
55
|
+
:order =>
|
56
|
+
{:order_id => 1313,
|
57
|
+
:perm_id => 172323928,
|
58
|
+
:client_id => 1111,
|
59
|
+
:parent_id => 0,
|
60
|
+
:side => :buy,
|
61
|
+
:order_type => :limit,
|
62
|
+
:limit_price => 9.13,
|
63
|
+
:total_quantity => 100,
|
64
|
+
},
|
65
|
+
:order_state =>
|
66
|
+
{:order_id => 1313,
|
67
|
+
:perm_id => 172323928,
|
68
|
+
:client_id => 1111,
|
69
|
+
:parent_id => 0,
|
70
|
+
:status => 'PreSubmitted',
|
71
|
+
},
|
72
|
+
:contract =>
|
73
|
+
{:symbol => 'WFC',
|
74
|
+
:exchange => 'NYSE',
|
75
|
+
:currency => 'USD',
|
76
|
+
:sec_type => :stock
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
it_behaves_like 'OpenOrder message'
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'received from IB' do
|
84
|
+
before(:all) do
|
85
|
+
verify_account
|
86
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
87
|
+
@ib.wait_for :NextValidId
|
88
|
+
place_order IB::Symbols::Stocks[:wfc]
|
89
|
+
@ib.wait_for :OpenOrder
|
90
|
+
end
|
91
|
+
|
92
|
+
after(:all) { close_connection } # implicitly cancels order
|
93
|
+
|
94
|
+
subject { @ib.received[:OpenOrder].first }
|
95
|
+
|
96
|
+
it_behaves_like 'OpenOrder message'
|
97
|
+
|
98
|
+
#it 'has extended order_state attributes' do
|
99
|
+
end
|
100
|
+
end # describe IB::Messages:Incoming
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'order_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'OrderStatus message' do
|
4
|
+
it { should be_an IB::Messages::Incoming::OrderStatus }
|
5
|
+
its(:message_type) { should == :OrderStatus }
|
6
|
+
its(:message_id) { should == 3 }
|
7
|
+
its(:version) { should == 6 }
|
8
|
+
its(:data) { should_not be_empty }
|
9
|
+
its(:order_id) { should be_an Integer }
|
10
|
+
its(:status) { should =~ /Submit/ }
|
11
|
+
its(:to_human) { should =~
|
12
|
+
/<OrderStatus: <OrderState: .*Submit.* #\d+\/\d+ from 1111 filled 0\/100/ }
|
13
|
+
|
14
|
+
it 'has proper order_state accessor' do
|
15
|
+
os = subject.order_state
|
16
|
+
os.order_id.should be_an Integer
|
17
|
+
os.perm_id.should be_an Integer
|
18
|
+
os.client_id.should == 1111
|
19
|
+
os.parent_id.should == 0
|
20
|
+
os.filled.should == 0
|
21
|
+
os.remaining.should == 100
|
22
|
+
os.average_fill_price.should == 0.0
|
23
|
+
os.last_fill_price.should == 0.0
|
24
|
+
os.status.should =~ /Submit/
|
25
|
+
os.why_held.should =~ /child|/
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'has class accessors as well' do
|
29
|
+
subject.class.message_id.should == 3
|
30
|
+
subject.class.version.should == 6
|
31
|
+
subject.class.message_type.should == :OrderStatus
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe IB::Messages::Incoming::OrderStatus do
|
37
|
+
|
38
|
+
context 'Instantiated with data Hash' do
|
39
|
+
subject do
|
40
|
+
IB::Messages::Incoming::OrderStatus.new :version => 6,
|
41
|
+
:order_state =>
|
42
|
+
{:order_id => 1313,
|
43
|
+
:perm_id => 172323928,
|
44
|
+
:client_id => 1111,
|
45
|
+
:parent_id => 0,
|
46
|
+
:status => 'PreSubmitted',
|
47
|
+
:filled => 0,
|
48
|
+
:remaining => 100,
|
49
|
+
:average_fill_price => 0.0,
|
50
|
+
:last_fill_price => 0.0,
|
51
|
+
:why_held => 'child'}
|
52
|
+
end
|
53
|
+
|
54
|
+
it_behaves_like 'OrderStatus message'
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'received from IB' do
|
58
|
+
before(:all) do
|
59
|
+
verify_account
|
60
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
61
|
+
@ib.wait_for :NextValidId
|
62
|
+
clean_connection
|
63
|
+
place_order IB::Symbols::Stocks[:wfc]
|
64
|
+
@ib.wait_for :OrderStatus, 6
|
65
|
+
end
|
66
|
+
|
67
|
+
after(:all) { close_connection } # implicitly cancels order
|
68
|
+
|
69
|
+
subject { @ib.received[:OrderStatus].first }
|
70
|
+
|
71
|
+
it_behaves_like 'OrderStatus message'
|
72
|
+
end
|
73
|
+
|
74
|
+
end # describe IB::Messages:Incoming
|