ib-ruby 0.7.4 → 0.7.6

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.
Files changed (93) hide show
  1. data/.gitignore +3 -0
  2. data/HISTORY +8 -0
  3. data/README.md +2 -2
  4. data/Rakefile +15 -0
  5. data/TODO +7 -2
  6. data/VERSION +1 -1
  7. data/bin/account_info +1 -1
  8. data/bin/cancel_orders +1 -1
  9. data/bin/contract_details +1 -1
  10. data/bin/depth_of_market +1 -1
  11. data/bin/fa_accounts +1 -1
  12. data/bin/fundamental_data +42 -0
  13. data/bin/historic_data +1 -1
  14. data/bin/historic_data_cli +1 -1
  15. data/bin/list_orders +1 -2
  16. data/bin/market_data +1 -1
  17. data/bin/option_data +1 -1
  18. data/bin/place_combo_order +1 -1
  19. data/bin/place_order +1 -1
  20. data/bin/template +1 -4
  21. data/bin/tick_data +2 -2
  22. data/bin/time_and_sales +1 -1
  23. data/lib/ib-ruby.rb +4 -0
  24. data/lib/ib-ruby/connection.rb +50 -34
  25. data/lib/ib-ruby/constants.rb +232 -37
  26. data/lib/ib-ruby/db.rb +25 -0
  27. data/lib/ib-ruby/extensions.rb +51 -1
  28. data/lib/ib-ruby/messages/abstract_message.rb +0 -8
  29. data/lib/ib-ruby/messages/incoming.rb +18 -493
  30. data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
  31. data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
  32. data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
  33. data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
  34. data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
  35. data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
  36. data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
  37. data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
  38. data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
  39. data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
  40. data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
  41. data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
  42. data/lib/ib-ruby/messages/outgoing.rb +25 -223
  43. data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
  44. data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
  45. data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
  46. data/lib/ib-ruby/models.rb +4 -0
  47. data/lib/ib-ruby/models/bar.rb +31 -14
  48. data/lib/ib-ruby/models/combo_leg.rb +48 -23
  49. data/lib/ib-ruby/models/contracts.rb +2 -2
  50. data/lib/ib-ruby/models/contracts/bag.rb +11 -7
  51. data/lib/ib-ruby/models/contracts/contract.rb +90 -66
  52. data/lib/ib-ruby/models/contracts/option.rb +16 -7
  53. data/lib/ib-ruby/models/execution.rb +34 -18
  54. data/lib/ib-ruby/models/model.rb +15 -7
  55. data/lib/ib-ruby/models/model_properties.rb +101 -44
  56. data/lib/ib-ruby/models/order.rb +176 -187
  57. data/lib/ib-ruby/models/order_state.rb +99 -0
  58. data/lib/ib-ruby/symbols/forex.rb +10 -10
  59. data/lib/ib-ruby/symbols/futures.rb +6 -6
  60. data/lib/ib-ruby/symbols/stocks.rb +3 -3
  61. data/spec/account_helper.rb +4 -5
  62. data/spec/combo_helper.rb +4 -4
  63. data/spec/db.rb +18 -0
  64. data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
  65. data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
  66. data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
  67. data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
  68. data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
  69. data/spec/ib-ruby/models/bag_spec.rb +97 -0
  70. data/spec/ib-ruby/models/bar_spec.rb +45 -0
  71. data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
  72. data/spec/ib-ruby/models/contract_spec.rb +134 -170
  73. data/spec/ib-ruby/models/execution_spec.rb +35 -50
  74. data/spec/ib-ruby/models/option_spec.rb +127 -0
  75. data/spec/ib-ruby/models/order_spec.rb +89 -68
  76. data/spec/ib-ruby/models/order_state_spec.rb +55 -0
  77. data/spec/integration/contract_info_spec.rb +4 -6
  78. data/spec/integration/fundamental_data_spec.rb +41 -0
  79. data/spec/integration/historic_data_spec.rb +4 -4
  80. data/spec/integration/market_data_spec.rb +1 -3
  81. data/spec/integration/orders/attached_spec.rb +8 -10
  82. data/spec/integration/orders/combo_spec.rb +2 -2
  83. data/spec/integration/orders/execution_spec.rb +0 -1
  84. data/spec/integration/orders/placement_spec.rb +1 -3
  85. data/spec/integration/orders/valid_ids_spec.rb +1 -2
  86. data/spec/message_helper.rb +1 -1
  87. data/spec/model_helper.rb +211 -0
  88. data/spec/order_helper.rb +44 -37
  89. data/spec/spec_helper.rb +36 -23
  90. data/spec/v.rb +7 -0
  91. data/tasks/doc.rake +1 -1
  92. metadata +116 -12
  93. 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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:forex],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:future],
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 => SECURITY_TYPES[:stock],
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 => SECURITY_TYPES[:stock],
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 => SECURITY_TYPES[:stock],
25
+ :sec_type => :stock,
26
26
  :description => "Non-existent stock"),
27
27
  }
28
28
  end
@@ -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 :AccountDownloadEnd
20
- @ib.send_message :RequestAccountData, :subscribe => false
21
- raise "Unable to verify IB PAPER ACCOUNT" unless @ib.received?(:AccountValue)
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[:AccountValue].first.account_name
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
- # Create new Combo contract
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