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
File without changes
|
@@ -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 '
|
1
|
+
require 'model_helper'
|
2
2
|
|
3
3
|
describe IB::Models::ComboLeg do
|
4
4
|
|
5
|
-
let(:
|
6
|
-
{:con_id =>
|
7
|
-
:ratio=>
|
8
|
-
:action =>
|
9
|
-
:exchange => '
|
10
|
-
:open_close =>
|
11
|
-
:short_sale_slot =>
|
12
|
-
:designated_location =>
|
13
|
-
:exempt_code =>
|
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
|
-
|
17
|
-
|
18
|
-
|
16
|
+
let(:human) do
|
17
|
+
"<ComboLeg: buy 2 con_id 81032967 at CBOE>"
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
55
|
+
it_behaves_like 'Model'
|
56
|
+
it_behaves_like 'Self-equal Model'
|
32
57
|
|
33
|
-
|
34
|
-
|
35
|
-
subject.send(name).should == value
|
36
|
-
end
|
37
|
-
end
|
58
|
+
context "serialization" do
|
59
|
+
subject { IB::ComboLeg.new props }
|
38
60
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
61
|
+
it "serializes short" do
|
62
|
+
subject.serialize.should == [81032967, 2, "BUY", "CBOE"]
|
42
63
|
end
|
43
64
|
|
44
|
-
it
|
45
|
-
|
46
|
-
|
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 #
|
69
|
+
end #serialization
|
54
70
|
|
55
71
|
end # describe IB::Models::Contract::ComboLeg
|
@@ -1,216 +1,180 @@
|
|
1
|
-
require '
|
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(:
|
6
|
-
{:symbol =>
|
7
|
-
:sec_type =>
|
8
|
-
:expiry => '
|
9
|
-
:strike =>
|
10
|
-
:right =>
|
11
|
-
:multiplier =>
|
12
|
-
:exchange =>
|
13
|
-
:currency =>
|
14
|
-
:local_symbol =>
|
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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
36
|
+
let(:errors) do
|
37
|
+
{:sec_type => ["should be valid security type"],
|
38
|
+
}
|
39
|
+
end
|
55
40
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
68
|
-
|
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
|
-
|
82
|
-
|
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
|
-
|
85
|
-
|
56
|
+
:exchange =>
|
57
|
+
{[:cboe, 'cboE', 'CBOE'] => 'CBOE',
|
58
|
+
[:smart, 'SMART', 'smArt'] => 'SMART'},
|
86
59
|
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
133
|
-
|
68
|
+
[:callable, :puttable, :convertible, :next_option_partial] =>
|
69
|
+
{[1, true] => true, [0, false] => false},
|
70
|
+
}
|
71
|
+
end
|
134
72
|
|
135
|
-
|
136
|
-
|
73
|
+
it_behaves_like 'Model'
|
74
|
+
it_behaves_like 'Self-equal Model'
|
137
75
|
|
138
|
-
|
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
|
-
|
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 '
|
147
|
-
|
148
|
-
|
149
|
-
|
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 '
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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 '
|
167
|
-
|
168
|
-
|
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
|
-
|
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
|
-
|
177
|
-
|
178
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
185
|
-
|
186
|
-
|
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
|
-
|
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
|
-
["
|
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
|
-
["
|
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
|
208
|
-
should ==
|
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 '
|
212
|
-
should ==
|
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
|