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,44 @@
1
+ require 'message_helper'
2
+
3
+ # The API can receive frozen market data from Trader Workstation. Frozen market
4
+ # data is the last data recorded in our system. During normal trading hours,
5
+ # the API receives real-time market data. If you use this function, you are
6
+ # telling TWS to automatically switch to frozen market data AFTER the close.
7
+ # Then, before the opening of the next trading day, market data will automatically
8
+ # switch back to real-time market data.
9
+ # :market_data_type = 1 for real-time streaming, 2 for frozen market data
10
+
11
+ describe "Request Market Data Type", :connected => true, :integration => true do
12
+
13
+ before(:all) do
14
+ verify_account
15
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
16
+ end
17
+
18
+ after(:all) { close_connection }
19
+
20
+ context "switching to real_time streaming after-hours" do
21
+ before(:all) do
22
+ @ib.send_message :RequestMarketDataType, :market_data_type => :real_time
23
+ @ib.wait_for 2 # sec
24
+ end
25
+
26
+ after(:all) { clean_connection }
27
+
28
+ it 'just works' do
29
+ end
30
+ end
31
+
32
+ context "switching to frozen market data after-hours" do
33
+ before(:all) do
34
+ @ib.send_message :RequestMarketDataType, :market_data_type => :frozen
35
+ @ib.wait_for 2 # sec
36
+ end
37
+
38
+ after(:all) { clean_connection }
39
+
40
+ it 'just works' do
41
+ end
42
+ end
43
+
44
+ end # Request Market Data Type
@@ -0,0 +1,97 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::Contracts::Bag do # AKA IB::Bag
4
+
5
+ let(:props) do
6
+ {:symbol => 'GOOG',
7
+ :exchange => 'SMART',
8
+ :currency => 'USD',
9
+ :legs => [IB::ComboLeg.new(:con_id => 81032967, :weight => 1),
10
+ IB::ComboLeg.new(:con_id => 81032968, :weight => -2),
11
+ IB::ComboLeg.new(:con_id => 81032973, :weight => 1)]
12
+ }
13
+ end
14
+
15
+ let(:human) do
16
+ "<Bag: GOOG SMART USD legs: 81032967|1,81032968|-2,81032973|1 >"
17
+ end
18
+
19
+ let(:defaults) do
20
+ {:sec_type => :bag,
21
+ :con_id => 0,
22
+ :strike => 0,
23
+ :min_tick => 0,
24
+ :include_expired => false,
25
+ :created_at => Time,
26
+ }
27
+ end
28
+
29
+ let(:errors) do
30
+ {:legs => ["legs cannot be empty"],
31
+ }
32
+ end
33
+
34
+ let(:assigns) do
35
+ {:expiry =>
36
+ {[nil, ''] => '',
37
+ [20060913, '20060913', 200609, '200609', :foo, 2006, 42, 'bar'] =>
38
+ /should be blank/},
39
+
40
+ :sec_type =>
41
+ {['BAG', :bag] => :bag,
42
+ IB::CODES[:sec_type].reject { |k, v,| k == :bag }.to_a =>
43
+ /should be a bag/},
44
+
45
+ :right =>
46
+ {['?', :none, '', '0'] => :none,
47
+ ["PUT", :put, "CALL", "C", :call, :foo, 'BAR', 42] =>
48
+ /should be none/},
49
+
50
+ :exchange =>
51
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
52
+ [:smart, 'SMART', 'smArt'] => 'SMART'},
53
+
54
+ :primary_exchange =>
55
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
56
+ [:SMART, 'SMART'] => /should not be SMART/},
57
+
58
+ [:symbol, :local_symbol] =>
59
+ {['AAPL', :AAPL] => 'AAPL'},
60
+
61
+ :multiplier => {['123', 123] => 123},
62
+
63
+ [:under_con_id, :min_tick, :coupon] => {123 => 123}
64
+ }
65
+ end
66
+
67
+ context 'using shortest class name without properties' do
68
+ subject { IB::Bag.new }
69
+ it_behaves_like 'Model instantiated empty'
70
+ end
71
+
72
+ it_behaves_like 'Model'
73
+ it_behaves_like 'Self-equal Model'
74
+
75
+ context 'properly initiated' do
76
+ subject { IB::Bag.new props }
77
+
78
+ it_behaves_like 'Contract'
79
+
80
+ it 'has extra legs_description accessor' do
81
+ subject.legs_description.should == "81032967|1,81032968|-2,81032973|1"
82
+ end
83
+ end
84
+
85
+ it 'correctly defines Contract type (sec_type) for Bag contract' do
86
+ [IB::Contract.new(:sec_type => :bag),
87
+ IB::Contract.new(:sec_type => 'BAG'),
88
+ IB::Bag.new
89
+ ].each do |contract|
90
+ contract.should be_bag
91
+ contract.should_not be_bond
92
+ contract.should_not be_stock
93
+ contract.should_not be_option
94
+ end
95
+ end
96
+
97
+ end # describe IB::Bag
@@ -0,0 +1,45 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::Bar do # AKA IB::Bar
4
+
5
+ let(:props) do
6
+ {:open => 1.31,
7
+ :high => 1.35,
8
+ :low => 1.30,
9
+ :close => 1.33,
10
+ :wap => 1.32,
11
+ :volume => 20000,
12
+ :has_gaps => true,
13
+ :trades => 50,
14
+ :time => "20120312 15:41:09",
15
+ }
16
+ end
17
+
18
+ let(:defaults) do
19
+ {:created_at => Time,
20
+ }
21
+ end
22
+
23
+ let(:errors) do
24
+ {:close => ["is not a number"],
25
+ :high => ["is not a number"],
26
+ :low => ["is not a number"],
27
+ :open => ["is not a number"],
28
+ :volume => ["is not a number"]}
29
+ end
30
+
31
+ let(:assigns) do
32
+ {:has_gaps => {[1, true] => true, [0, false] => false},
33
+
34
+ [:open, :high, :low, :close, :volume] =>
35
+ {[:foo, 'BAR', nil] => /is not a number/}
36
+ }
37
+ end
38
+
39
+ let(:human) do
40
+ "<Bar: 20120312 15:41:09 wap 1.32 OHLC 1.31 1.35 1.3 1.33 trades 50 vol 20000 gaps true>"
41
+ end
42
+
43
+ it_behaves_like 'Model'
44
+
45
+ end # describe IB::Bar
@@ -1,55 +1,71 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
2
 
3
3
  describe IB::Models::ComboLeg do
4
4
 
5
- let(:properties) do
6
- {:con_id => 123,
7
- :ratio=> 1234,
8
- :action => 'BUY',
9
- :exchange => 'BLAH',
10
- :open_close => IB::ComboLeg::OPEN,
11
- :short_sale_slot => 1,
12
- :designated_location => 'BLEH',
13
- :exempt_code => 12}
5
+ let(:props) do
6
+ {:con_id => 81032967,
7
+ :ratio => 2,
8
+ :action => :buy,
9
+ :exchange => 'CBOE',
10
+ :open_close => :open,
11
+ :short_sale_slot => :broker,
12
+ :designated_location => nil,
13
+ :exempt_code => -1}
14
14
  end
15
15
 
16
- context "instantiation" do
17
- context 'empty without properties' do
18
- subject { IB::ComboLeg.new }
16
+ let(:human) do
17
+ "<ComboLeg: buy 2 con_id 81032967 at CBOE>"
18
+ end
19
19
 
20
- it { should_not be_nil }
21
- its(:con_id) {should == 0}
22
- its(:open_close) {should == 0}
23
- its(:short_sale_slot) {should == 0}
24
- its(:designated_location) {should == ''}
25
- its(:exempt_code) {should == -1}
20
+ let(:defaults) do
21
+ {:con_id => 0,
22
+ :open_close => :same,
23
+ :designated_location => '',
24
+ :exempt_code => -1,
25
+ :exchange => 'SMART', # Unless SMART, Order modification fails
26
+ :created_at => Time,
27
+ }
28
+ end
26
29
 
27
- its(:created_at) {should be_a Time}
28
- end
30
+ let(:errors) do
31
+ {:ratio => ["is not a number"],
32
+ :side => ["should be buy/sell/short"]}
33
+ end
34
+
35
+ let(:assigns) do
36
+ {:open_close =>
37
+ {['SAME', 'same', 'S', 's', :same, 0, '0'] => :same,
38
+ ['OPEN', 'open', 'O', 'o', :open, 1, '1'] => :open,
39
+ ['CLOSE', 'close', 'C', 'c', :close, 2, '2'] => :close,
40
+ ['UNKNOWN', 'unknown', 'U', 'u', :unknown, 3, '3'] => :unknown,
41
+ [42, nil, 'Foo', :bar] => /should be same.open.close.unknown/},
42
+
43
+ :side =>
44
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
45
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell,
46
+ ['SSHORT', 'Short', 'short', :SHORT, :short, 'T', :T] => :short,
47
+ ['SSHORTX', 'Shortextemt', 'shortx', :short_exempt, 'X', :X] => :short_exempt,
48
+ [42, nil, 'ASK', :foo] => /should be buy.sell.short/},
49
+
50
+ :designated_location =>
51
+ {[42, 'FOO', :bar] => /should be blank or orders will be rejected/},
52
+ }
53
+ end
29
54
 
30
- context 'with properties' do
31
- subject { IB::ComboLeg.new properties }
55
+ it_behaves_like 'Model'
56
+ it_behaves_like 'Self-equal Model'
32
57
 
33
- it 'sets properties right' do
34
- properties.each do |name, value|
35
- subject.send(name).should == value
36
- end
37
- end
58
+ context "serialization" do
59
+ subject { IB::ComboLeg.new props }
38
60
 
39
- context 'essential properties are still set, even if not given explicitely' do
40
- its(:created_at) {should be_a Time}
41
- end
61
+ it "serializes short" do
62
+ subject.serialize.should == [81032967, 2, "BUY", "CBOE"]
42
63
  end
43
64
 
44
- it 'allows setting attributes' do
45
- expect {
46
- x = IB::ComboLeg.new
47
- properties.each do |name, value|
48
- subject.send("#{name}=", value)
49
- subject.send(name).should == value
50
- end
51
- }.to_not raise_error
65
+ it "serializes extended" do
66
+ subject.serialize(:extended).should ==
67
+ [81032967, 2, "BUY", "CBOE", 1, 1, nil, -1]
52
68
  end
53
- end #instantiation
69
+ end #serialization
54
70
 
55
71
  end # describe IB::Models::Contract::ComboLeg
@@ -1,216 +1,180 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
+ require 'combo_helper'
2
3
 
3
4
  describe IB::Models::Contracts::Contract do # AKA IB::Contract
4
5
 
5
- let(:properties) do
6
- {:symbol => "TEST",
7
- :sec_type => IB::SECURITY_TYPES[:stock],
8
- :expiry => '200609',
9
- :strike => 1234,
10
- :right => "PUT",
11
- :multiplier => 123,
12
- :exchange => "SMART",
13
- :currency => "USD",
14
- :local_symbol => "baz"}
6
+ let(:props) do
7
+ {:symbol => 'AAPL',
8
+ :sec_type => :option,
9
+ :expiry => '201301',
10
+ :strike => 600,
11
+ :right => :put,
12
+ :multiplier => 10,
13
+ :exchange => 'SMART',
14
+ :currency => 'USD',
15
+ :local_symbol => 'AAPL 130119C00500000'}
15
16
  end
16
17
 
17
- context "instantiation" do
18
- context 'using fully qualified class name without properties' do
19
- subject { IB::Models::Contract.new }
20
-
21
- it { should_not be_nil }
22
- its(:con_id) { should == 0 }
23
- its(:strike) { should == 0 }
24
- its(:sec_type) { should be_nil }
25
- its(:created_at) { should be_a Time }
26
- its(:include_expired) { should == false }
27
- end
28
-
29
- context 'using short class name without properties' do
30
- subject { IB::Contract.new }
31
-
32
- it { should_not be_nil }
33
- its(:con_id) { should == 0 }
34
- its(:strike) { should == 0 }
35
- its(:sec_type) { should be_nil }
36
- its(:created_at) { should be_a Time }
37
- its(:include_expired) { should == false }
38
- end
39
-
40
- context 'with properties' do
41
- subject { IB::Contract.new properties }
18
+ let(:human) do
19
+ "<Contract: AAPL option 201301 put 600 SMART USD>"
20
+ end
42
21
 
43
- it 'sets properties right' do
44
- properties.each do |name, value|
45
- subject.send(name).should == value
46
- end
47
- end
22
+ let(:defaults) do
23
+ {:con_id => 0,
24
+ :strike => 0,
25
+ :min_tick => 0,
26
+ :coupon => 0,
27
+ :callable => false,
28
+ :puttable => false,
29
+ :convertible => false,
30
+ :next_option_partial => false,
31
+ :include_expired => false,
32
+ :created_at => Time,
33
+ }
34
+ end
48
35
 
49
- context 'essential properties are still set, even if not given explicitely' do
50
- its(:con_id) { should == 0 }
51
- its(:created_at) { should be_a Time }
52
- its(:include_expired) { should == false }
53
- end
54
- end
36
+ let(:errors) do
37
+ {:sec_type => ["should be valid security type"],
38
+ }
39
+ end
55
40
 
56
- context "ContractDetails properties" do
57
- let(:detailed_properties) do
58
- {:under_con_id => 123,
59
- :min_tick=> 1234,
60
- :callable => true,
61
- :puttable => true,
62
- :coupon => 12345,
63
- :convertible => true,
64
- :next_option_partial => true}
65
- end
41
+ let(:assigns) do
42
+ {:expiry =>
43
+ {[200609, '200609'] => '200609',
44
+ [20060913, '20060913'] => '20060913',
45
+ [:foo, 2006, 42, 'bar'] => /should be YYYYMM or YYYYMMDD/},
66
46
 
67
- context 'empty without properties' do
68
- subject { IB::Contract.new }
69
-
70
- its(:summary) { should == subject }
71
- its(:under_con_id) { should == 0 }
72
- its(:min_tick) { should == 0 }
73
- its(:callable) { should == false }
74
- its(:puttable) { should == false }
75
- its(:coupon) { should == 0 }
76
- its(:convertible) { should == false }
77
- its(:next_option_partial) { should == false }
78
- its(:created_at) { should be_a Time }
79
- end
47
+ :sec_type => codes_and_values_for(:sec_type).
48
+ merge([:foo, 'BAR', 42] => /should be valid security type/),
80
49
 
81
- context 'with properties' do
82
- subject { IB::Contract.new detailed_properties }
50
+ :right =>
51
+ {["PUT", "put", "P", "p", :put] => :put,
52
+ ["CALL", "call", "C", "c", :call] => :call,
53
+ ['', '0', '?', :none] => :none,
54
+ [:foo, 'BAR', 42] => /should be put, call or none/},
83
55
 
84
- its(:summary) { should == subject }
85
- its(:created_at) { should be_a Time }
56
+ :exchange =>
57
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
58
+ [:smart, 'SMART', 'smArt'] => 'SMART'},
86
59
 
87
- it 'sets properties right' do
88
- detailed_properties.each do |name, value|
89
- subject.send(name).should == value
90
- end
91
- end
92
- end
93
- end #instantiation
94
-
95
- it 'allows setting attributes' do
96
- expect {
97
- x = IB::Contract.new
98
- properties.each do |name, value|
99
- subject.send("#{name}=", value)
100
- subject.send(name).should == value
101
- end
102
- x.expiry = 200609
103
- x.expiry.should == '200609'
104
- }.to_not raise_error
105
- end
60
+ :primary_exchange =>
61
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
62
+ [:SMART, 'SMART'] => /should not be SMART/},
106
63
 
107
- it 'allows setting ContractDetails attributes' do
108
- x = IB::Contract.new
109
- expect {
110
- x.callable = true
111
- x.puttable = true
112
- x.convertible = true
113
- x.under_con_id = 321
114
- x.min_tick = 123
115
- x.next_option_partial = true
116
- }.to_not raise_error
117
-
118
- x.callable.should == true
119
- x.puttable.should == true
120
- x.convertible.should == true
121
- x.under_con_id.should == 321
122
- x.min_tick.should == 123
123
- x.next_option_partial.should == true
124
- end
64
+ :multiplier => {['123', 123] => 123},
125
65
 
126
- it 'converts multiplier to int' do
127
- expect { @contract = IB::Contract.new(:multiplier => '123') }.to_not raise_error
128
- expect { @contract.multiplier = '123' }.to_not raise_error
129
- @contract.multiplier.should == 123
130
- end
66
+ [:under_con_id, :min_tick, :coupon] => {123 => 123},
131
67
 
132
- it 'raises on wrong security type' do
133
- expect { IB::Contract.new(:sec_type => "asdf") }.to raise_error ArgumentError
68
+ [:callable, :puttable, :convertible, :next_option_partial] =>
69
+ {[1, true] => true, [0, false] => false},
70
+ }
71
+ end
134
72
 
135
- expect { IB::Contract.new.sec_type = "asdf" }.to raise_error ArgumentError
136
- end
73
+ it_behaves_like 'Model'
74
+ it_behaves_like 'Self-equal Model'
137
75
 
138
- it 'accepts pre-determined security types' do
139
- IB::SECURITY_TYPES.values.each do |type|
140
- expect { IB::Contract.new(:sec_type => type) }.to_not raise_error
76
+ context 'testing for Contract type (sec_type)' do
141
77
 
142
- expect { IB::Contract.new.sec_type = type }.to_not raise_error
78
+ it 'correctly defines Contract type (sec_type) for Option contract' do
79
+ [IB::Contract.new(:sec_type => :option),
80
+ IB::Contract.new(:sec_type => 'OPT'),
81
+ IB::Option.new
82
+ ].each do |contract|
83
+ contract.should_not be_bag
84
+ contract.should_not be_bond
85
+ contract.should_not be_stock
86
+ contract.should be_option
143
87
  end
144
88
  end
145
89
 
146
- it 'raises on wrong expiry' do
147
- expect { IB::Contract.new(:expiry => "foo") }.to raise_error ArgumentError
148
-
149
- expect { IB::Contract.new.expiry = "foo" }.to raise_error ArgumentError
90
+ it 'correctly defines Contract type for Bag Contracts' do
91
+ [IB::Contract.new(:sec_type => :bag),
92
+ IB::Contract.new(:sec_type => 'BAG'),
93
+ IB::Bag.new
94
+ ].each do |contract|
95
+ contract.should be_bag
96
+ contract.should_not be_bond
97
+ contract.should_not be_stock
98
+ contract.should_not be_option
99
+ end
150
100
  end
151
101
 
152
- it 'accepts correct expiry' do
153
- expect { IB::Contract.new(:expiry => "200607") }.to_not raise_error
154
-
155
- expect { IB::Contract.new.expiry = "200607" }.to_not raise_error
156
-
157
- expect { IB::Contract.new(:expiry => 200607) }.to_not raise_error
158
-
159
- expect {
160
- x = IB::Contract.new
161
- x.expiry = 200607
162
- x.expiry.should == "200607" # converted to a string
163
- }.to_not raise_error
102
+ it 'correctly defines Contract type for Bag Contracts' do
103
+ [IB::Contract.new(:sec_type => :stock),
104
+ IB::Contract.new(:sec_type => 'STK'),
105
+ ].each do |contract|
106
+ contract.should_not be_bag
107
+ contract.should_not be_bond
108
+ contract.should be_stock
109
+ contract.should_not be_option
110
+ end
164
111
  end
165
112
 
166
- it 'raises on incorrect right (option type)' do
167
- expect { IB::Contract.new(:right => "foo") }.to raise_error ArgumentError
168
- expect { IB::Contract.new.right = "foo" }.to raise_error ArgumentError
113
+ it 'correctly defines Contract type for Bond Contracts' do
114
+ [IB::Contract.new(:sec_type => :bond),
115
+ IB::Contract.new(:sec_type => 'BOND'),
116
+ ].each do |contract|
117
+ contract.should_not be_bag
118
+ contract.should be_bond
119
+ contract.should_not be_stock
120
+ contract.should_not be_option
121
+ end
169
122
  end
170
123
 
171
- it 'accepts all correct values for right (option type)' do
172
- ["PUT", "put", "P", "p"].each do |right|
173
- expect { @contract = IB::Contract.new(:right => right) }.to_not raise_error
174
- @contract.right.should == "PUT"
124
+ end
175
125
 
176
- expect { @contract.right = right }.to_not raise_error
177
- @contract.right.should == "PUT"
178
- end
126
+ context 'using shorter class name without properties' do
127
+ subject { IB::Models::Contract.new }
128
+ it_behaves_like 'Model instantiated empty'
129
+ it_behaves_like 'Self-equal Model'
130
+ it_behaves_like 'Contract'
131
+ end
179
132
 
180
- ["CALL", "call", "C", "c"].each do |right|
181
- expect { @contract = IB::Contract.new(:right => right) }.to_not raise_error
182
- @contract.right.should == "CALL"
133
+ context 'using shortest class name without properties' do
134
+ subject { IB::Contract.new }
135
+ it_behaves_like 'Model instantiated empty'
136
+ it_behaves_like 'Self-equal Model'
137
+ it_behaves_like 'Contract'
138
+ end
183
139
 
184
- expect { @contract.right = right }.to_not raise_error
185
- @contract.right.should == "CALL"
186
- end
140
+ context "serialization" do
141
+ before(:all) do
142
+ @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
143
+ @ib.wait_for :ManagedAccounts
144
+ @combo = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
145
+ close_connection
187
146
  end
188
- end #instantiation
189
147
 
190
- context "serialization" do
191
- subject { IB::Contract.new properties }
148
+ subject { IB::Contract.new props }
192
149
 
193
150
  it "serializes long" do
194
151
  subject.serialize_long.should ==
195
- ["TEST", IB::SECURITY_TYPES[:stock], "200609", 1234, "PUT", 123, "SMART", nil, "USD", "baz"]
152
+ ["AAPL", "OPT", "201301", 600, "P", 10, "SMART", nil, "USD", "AAPL 130119C00500000"]
196
153
  end
197
154
 
198
155
  it "serializes short" do
199
156
  subject.serialize_short.should ==
200
- ["TEST", IB::SECURITY_TYPES[:stock], "200609", 1234, "PUT", 123, "SMART", "USD", "baz"]
157
+ ["AAPL", "OPT", "201301", 600, "P", 10, "SMART", "USD", "AAPL 130119C00500000"]
201
158
  end
202
- end #serialization
203
-
204
- context 'equality' do
205
- subject { IB::Contract.new properties }
206
159
 
207
- it 'be self-equal ' do
208
- should == subject
160
+ it "serializes combo (BAG) contracts for Order placement" do
161
+ @combo.serialize_long(:con_id, :sec_id).should ==
162
+ [0, "GOOG", "BAG", nil, 0.0, "", nil, "SMART", nil, "USD", nil, nil, nil]
209
163
  end
210
164
 
211
- it 'be equal to object with the same properties' do
212
- should == IB::Contract.new(properties)
165
+ it 'also serializes attached combo legs' do
166
+ subject.serialize_legs.should == []
167
+ subject.serialize_legs(:extended).should == []
168
+
169
+ @combo.serialize_legs.should ==
170
+ [3, 81032967, 1, "BUY", "SMART", 81032968, 2, "SELL", "SMART", 81032973, 1, "BUY", "SMART"]
171
+
172
+ @combo.serialize_legs(:extended).should ==
173
+ [3, 81032967, 1, "BUY", "SMART", 0, 0, "", -1,
174
+ 81032968, 2, "SELL", "SMART", 0, 0, "", -1,
175
+ 81032973, 1, "BUY", "SMART", 0, 0, "", -1]
213
176
  end
214
- end
177
+ end #serialization
178
+
215
179
 
216
180
  end # describe IB::Contract