ib-ruby 0.7.11 → 0.7.12
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/VERSION +1 -1
- data/db/migrate/121_add_order_states.rb +6 -6
- data/db/migrate/141_add_combo_legs.rb +7 -6
- data/lib/ib-ruby/models/bag.rb +2 -7
- data/lib/ib-ruby/models/combo_leg.rb +8 -4
- data/lib/ib-ruby/models/contract.rb +23 -16
- data/lib/ib-ruby/models/model.rb +3 -3
- data/lib/ib-ruby/models/model_properties.rb +50 -50
- data/lib/ib-ruby/models/option.rb +1 -1
- data/spec/db_helper.rb +57 -54
- data/spec/ib-ruby/models/bag_spec.rb +38 -51
- data/spec/ib-ruby/models/bar_spec.rb +36 -35
- data/spec/ib-ruby/models/combo_leg_spec.rb +108 -31
- data/spec/ib-ruby/models/contract_detail_spec.rb +39 -47
- data/spec/ib-ruby/models/contract_spec.rb +57 -67
- data/spec/ib-ruby/models/execution_spec.rb +53 -56
- data/spec/ib-ruby/models/option_spec.rb +48 -48
- data/spec/ib-ruby/models/order_spec.rb +93 -95
- data/spec/ib-ruby/models/order_state_spec.rb +43 -56
- data/spec/ib-ruby/models/underlying_spec.rb +18 -25
- data/spec/integration/contract_info_spec.rb +4 -0
- data/spec/model_helper.rb +77 -32
- data/spec/test.rb +61 -0
- metadata +14 -34
@@ -1,66 +1,59 @@
|
|
1
1
|
require 'model_helper'
|
2
2
|
|
3
|
-
describe IB::Models::Option
|
4
|
-
|
5
|
-
let(:props) do
|
6
|
-
{:symbol => 'AAPL',
|
7
|
-
:expiry => '201301',
|
8
|
-
:strike => 600.5,
|
9
|
-
:right => :put,
|
10
|
-
}
|
11
|
-
end
|
3
|
+
describe IB::Models::Option,
|
4
|
+
:human => "<Option: AAPL 201301 put 600.5 SMART >",
|
12
5
|
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
:errors => {:right => ["should be put or call"],
|
7
|
+
:strike => ["must be greater than 0"],
|
8
|
+
},
|
16
9
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
:props => {:symbol => 'AAPL',
|
11
|
+
:expiry => '201301',
|
12
|
+
:strike => 600.5,
|
13
|
+
:right => :put,
|
14
|
+
},
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
:assigns => {
|
17
|
+
:local_symbol =>
|
18
|
+
{['AAPL 130119C00500000',
|
19
|
+
:'AAPL 130119C00500000'] => 'AAPL 130119C00500000',
|
20
|
+
'BAR'=> /invalid OSI code/},
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
22
|
+
:expiry =>
|
23
|
+
{[200609, '200609'] => '200609',
|
24
|
+
[20060913, '20060913'] => '20060913',
|
25
|
+
[:foo, 2006, 42, 'bar'] => /should be YYYYMM or YYYYMMDD/},
|
33
26
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
27
|
+
:sec_type =>
|
28
|
+
{['OPT', :option] => :option,
|
29
|
+
IB::CODES[:sec_type].reject { |k, _| k == :option }.to_a =>
|
30
|
+
/should be an option/},
|
38
31
|
|
39
|
-
|
40
|
-
|
32
|
+
:right =>
|
33
|
+
{["PUT", "put", "P", "p", :put] => :put,
|
34
|
+
["CALL", "call", "C", "c", :call] => :call,
|
35
|
+
['', '0', '?', :none, :foo, 'BAR', 42] => /should be put or call/},
|
41
36
|
|
42
|
-
|
43
|
-
|
37
|
+
:exchange => string_upcase_assigns.merge(
|
38
|
+
[:smart, 'SMART', 'smArt'] => 'SMART'),
|
44
39
|
|
45
|
-
|
40
|
+
:primary_exchange =>string_upcase_assigns.merge(
|
41
|
+
[:SMART, 'SMART'] => /should not be SMART/),
|
46
42
|
|
47
|
-
|
43
|
+
:multiplier => to_i_assigns,
|
48
44
|
|
49
|
-
|
50
|
-
{['AAPL 130119C00500000', :'AAPL 130119C00500000'] => 'AAPL 130119C00500000',
|
51
|
-
'BAR'=> /invalid OSI code/},
|
52
|
-
|
53
|
-
:strike => {[0, -30.0] => /must be greater than 0/},
|
54
|
-
}
|
55
|
-
end
|
45
|
+
:symbol => string_assigns,
|
56
46
|
|
57
|
-
|
58
|
-
|
59
|
-
it_behaves_like 'Model instantiated empty'
|
60
|
-
end
|
47
|
+
:strike => {[0, -30.0] => /must be greater than 0/},
|
48
|
+
} do # AKA IB::Option
|
61
49
|
|
62
|
-
it_behaves_like 'Model'
|
63
50
|
it_behaves_like 'Self-equal Model'
|
51
|
+
it_behaves_like 'Model with invalid defaults'
|
52
|
+
|
53
|
+
it 'has class name shortcut' do
|
54
|
+
IB::Option.should == IB::Models::Option
|
55
|
+
IB::Option.new.should == IB::Models::Option.new
|
56
|
+
end
|
64
57
|
|
65
58
|
context 'properly initiated' do
|
66
59
|
subject { IB::Option.new props }
|
@@ -86,6 +79,13 @@ describe IB::Models::Option do # AKA IB::Option
|
|
86
79
|
end
|
87
80
|
end
|
88
81
|
|
82
|
+
it 'correctly validates OSI symbol' do
|
83
|
+
o = IB::Option.new props
|
84
|
+
o.should be_valid
|
85
|
+
o.local_symbol = "AAPL 130119C00500000"
|
86
|
+
o.should be_valid
|
87
|
+
end
|
88
|
+
|
89
89
|
context '.from_osi class builder' do
|
90
90
|
subject { IB::Option.from_osi 'AAPL130119C00500000' }
|
91
91
|
|
@@ -1,98 +1,96 @@
|
|
1
1
|
require 'model_helper'
|
2
2
|
|
3
|
-
describe IB::Models::Order
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
3
|
+
describe IB::Models::Order,
|
4
|
+
:props =>
|
5
|
+
{:local_id => 23,
|
6
|
+
:order_ref => 'Test',
|
7
|
+
:client_id => 1111,
|
8
|
+
:perm_id => 173276893,
|
9
|
+
:parent_id => 0,
|
10
|
+
:side => :buy,
|
11
|
+
:order_type => :market_if_touched,
|
12
|
+
:limit_price => 0.1,
|
13
|
+
:quantity => 100,
|
14
|
+
:tif => :good_till_cancelled,
|
15
|
+
:open_close => :close,
|
16
|
+
:oca_group => '',
|
17
|
+
:oca_type => :reduce_no_block,
|
18
|
+
:origin => :firm,
|
19
|
+
:designated_location => "WHATEVER",
|
20
|
+
:exempt_code => 123,
|
21
|
+
:delta_neutral_order_type => :market,
|
22
|
+
:transmit => false,
|
23
|
+
:outside_rth => true,
|
24
|
+
:what_if => true,
|
25
|
+
:not_held => true},
|
26
|
+
|
27
|
+
# TODO: :presents => { Object => "Formatted"}
|
28
|
+
:human => "<Order: Test MIT GTC buy 100 New 0.1 #23/173276893 from 1111>",
|
29
|
+
|
30
|
+
:errors => {:side =>["should be buy/sell/short"]},
|
31
|
+
|
32
|
+
:assigns =>
|
33
|
+
{[:order_type, :delta_neutral_order_type] => codes_and_values_for(:order_type),
|
34
|
+
|
35
|
+
:open_close =>
|
36
|
+
{[42, nil, 'Foo', :bar] => /should be same.open.close.unknown/,
|
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
|
+
|
43
|
+
[:what_if, :not_held, :outside_rth, :hidden, :transmit, :block_order,
|
44
|
+
:sweep_to_fill, :override_percentage_constraints, :all_or_none,
|
45
|
+
:etrade_only, :firm_quote_only, :opt_out_smart_routing, :scale_auto_reset,
|
46
|
+
:scale_random_percent] => boolean_assigns,
|
47
|
+
|
48
|
+
[:local_id, :perm_id, :parent_id] => numeric_or_nil_assigns,
|
49
|
+
},
|
50
|
+
|
51
|
+
:aliases =>
|
52
|
+
{[:side, :action] => buy_sell_short_assigns,
|
53
|
+
[:quantity, :total_quantity] => numeric_or_nil_assigns,
|
54
|
+
},
|
55
|
+
|
56
|
+
:collections =>
|
57
|
+
{:order_states =>[{:status => :Foo},
|
58
|
+
{:status => 'Bar'},],
|
59
|
+
|
60
|
+
:executions =>
|
61
|
+
[{:local_id => 23,
|
62
|
+
:client_id => 1111,
|
63
|
+
:perm_id => 173276893,
|
64
|
+
:exchange => "IDEALPRO",
|
65
|
+
:exec_id => "0001f4e8.4f5d48f1.01.01",
|
66
|
+
:price => 0.1,
|
67
|
+
:average_price => 0.1,
|
68
|
+
:shares => 40,
|
69
|
+
:cumulative_quantity => 40,
|
70
|
+
:side => :buy,
|
71
|
+
:time => "20120312 15:41:09"},
|
72
|
+
|
73
|
+
{:local_id => 23,
|
74
|
+
:client_id => 1111,
|
75
|
+
:perm_id => 173276893,
|
76
|
+
:exchange => "IDEALPRO",
|
77
|
+
:exec_id => "0001f4e8.4f5d48f1.01.02",
|
78
|
+
:price => 0.1,
|
79
|
+
:average_price => 0.1,
|
80
|
+
:shares => 60,
|
81
|
+
:cumulative_quantity => 100,
|
82
|
+
:side => :buy,
|
83
|
+
:time => "20120312 15:41:10"}]
|
84
|
+
} do
|
48
85
|
|
49
|
-
|
50
|
-
|
51
|
-
:etrade_only, :firm_quote_only, :opt_out_smart_routing, :scale_auto_reset,
|
52
|
-
:scale_random_percent] => boolean_assigns,
|
53
|
-
|
54
|
-
[:local_id, :perm_id, :parent_id] => numeric_or_nil_assigns,
|
55
|
-
}
|
56
|
-
end
|
57
|
-
|
58
|
-
let(:aliases) do
|
59
|
-
{[:side, :action] => buy_sell_short_assigns,
|
60
|
-
[:quantity, :total_quantity] => numeric_or_nil_assigns,
|
61
|
-
}
|
62
|
-
end
|
86
|
+
it_behaves_like 'Self-equal Model'
|
87
|
+
it_behaves_like 'Model with invalid defaults'
|
63
88
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
:executions => [IB::Execution.new(:local_id => 23,
|
69
|
-
:client_id => 1111,
|
70
|
-
:perm_id => 173276893,
|
71
|
-
:exchange => "IDEALPRO",
|
72
|
-
:exec_id => "0001f4e8.4f5d48f1.01.01",
|
73
|
-
:price => 0.1,
|
74
|
-
:average_price => 0.1,
|
75
|
-
:shares => 40,
|
76
|
-
:cumulative_quantity => 40,
|
77
|
-
:side => :buy,
|
78
|
-
:time => "20120312 15:41:09"),
|
79
|
-
IB::Execution.new(:local_id => 23,
|
80
|
-
:client_id => 1111,
|
81
|
-
:perm_id => 173276893,
|
82
|
-
:exchange => "IDEALPRO",
|
83
|
-
:exec_id => "0001f4e8.4f5d48f1.01.02",
|
84
|
-
:price => 0.1,
|
85
|
-
:average_price => 0.1,
|
86
|
-
:shares => 60,
|
87
|
-
:cumulative_quantity => 100,
|
88
|
-
:side => :buy,
|
89
|
-
:time => "20120312 15:41:10")]
|
90
|
-
}
|
89
|
+
it 'has class name shortcut' do
|
90
|
+
IB::Order.should == IB::Models::Order
|
91
|
+
IB::Order.new.should == IB::Models::Order.new
|
91
92
|
end
|
92
93
|
|
93
|
-
it_behaves_like 'Model'
|
94
|
-
it_behaves_like 'Self-equal Model'
|
95
|
-
|
96
94
|
context 'Order associations' do
|
97
95
|
after(:all) { DatabaseCleaner.clean }
|
98
96
|
|
@@ -129,12 +127,12 @@ describe IB::Models::Order do
|
|
129
127
|
subject.maint_margin.should be_nil
|
130
128
|
subject.equity_with_loan.should be_nil
|
131
129
|
# Properties arriving via OrderStatus message
|
132
|
-
subject.filled.should
|
133
|
-
subject.remaining.should
|
134
|
-
subject.price.should
|
135
|
-
subject.last_fill_price.should
|
136
|
-
subject.average_price.should
|
137
|
-
subject.average_fill_price.should
|
130
|
+
subject.filled.should == 0
|
131
|
+
subject.remaining.should == 0
|
132
|
+
subject.price.should == 0
|
133
|
+
subject.last_fill_price.should == 0
|
134
|
+
subject.average_price.should == 0
|
135
|
+
subject.average_fill_price.should == 0
|
138
136
|
subject.why_held.should be_nil
|
139
137
|
# Testing Order state
|
140
138
|
subject.should be_new
|
@@ -1,77 +1,64 @@
|
|
1
1
|
require 'model_helper'
|
2
2
|
|
3
|
-
describe IB::Models::OrderState
|
3
|
+
describe IB::Models::OrderState,
|
4
|
+
:props =>
|
5
|
+
{:local_id => 23,
|
6
|
+
:perm_id => 173276893,
|
7
|
+
:client_id => 1111,
|
8
|
+
:parent_id => 0,
|
9
|
+
:filled => 3,
|
10
|
+
:remaining => 2,
|
11
|
+
:last_fill_price => 0.5,
|
12
|
+
:average_fill_price => 0.55,
|
13
|
+
:why_held => 'child',
|
14
|
+
|
15
|
+
:init_margin => 500.0,
|
16
|
+
:maint_margin => 500.0,
|
17
|
+
:equity_with_loan => 750.0,
|
18
|
+
:commission_currency => 'USD',
|
19
|
+
:commission => 1.2,
|
20
|
+
:min_commission => 1,
|
21
|
+
:max_commission => 1.5,
|
22
|
+
:status => 'PreSubmitted',
|
23
|
+
:warning_text => 'Oh noes!',
|
24
|
+
},
|
25
|
+
:human =>
|
26
|
+
"<OrderState: PreSubmitted #23/173276893 from 1111 filled 3/2 at 0.5/0.55 margin 500.0/500.0 equity 750.0 fee 1.2 why_held child warning Oh noes!>",
|
27
|
+
:errors =>
|
28
|
+
{:status => ["must not be empty"],
|
29
|
+
},
|
30
|
+
:assigns =>
|
31
|
+
{[:status] =>
|
32
|
+
{[nil, ''] => /must not be empty/,
|
33
|
+
['Zorro', :Zorro] => 'Zorro'},
|
34
|
+
|
35
|
+
:local_id => numeric_or_nil_assigns,
|
36
|
+
},
|
37
|
+
:aliases =>
|
38
|
+
{[:price, :last_fill_price] => float_or_nil_assigns,
|
39
|
+
[:average_price, :average_fill_price] => float_or_nil_assigns,
|
40
|
+
} do
|
4
41
|
|
5
|
-
|
6
|
-
|
7
|
-
:perm_id => 173276893,
|
8
|
-
:client_id => 1111,
|
9
|
-
:parent_id => 0,
|
10
|
-
:filled => 3,
|
11
|
-
:remaining => 2,
|
12
|
-
:last_fill_price => 0.5,
|
13
|
-
:average_fill_price => 0.55,
|
14
|
-
:why_held => 'child',
|
15
|
-
|
16
|
-
:init_margin => 500.0,
|
17
|
-
:maint_margin => 500.0,
|
18
|
-
:equity_with_loan => 750.0,
|
19
|
-
:commission_currency => 'USD',
|
20
|
-
:commission => 1.2,
|
21
|
-
:min_commission => 1,
|
22
|
-
:max_commission => 1.5,
|
23
|
-
:status => 'PreSubmitted',
|
24
|
-
:warning_text => 'Oh noes!',
|
25
|
-
}
|
26
|
-
end
|
27
|
-
|
28
|
-
# TODO: :presents => { Object => "Formatted"}
|
29
|
-
let(:human) do
|
30
|
-
"<OrderState: PreSubmitted #23/173276893 from 1111 filled 3/2 at 0.5/0.55 margin 500.0/500.0 equity 750.0 fee 1.2 why_held child warning Oh noes!>"
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:errors) do
|
34
|
-
{:status => ["must not be empty"],
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
let(:assigns) do
|
39
|
-
{[:status] =>
|
40
|
-
{[nil, ''] => /must not be empty/,
|
41
|
-
['Zorro', :Zorro] => 'Zorro'},
|
42
|
-
|
43
|
-
:local_id => numeric_or_nil_assigns,
|
44
|
-
}
|
45
|
-
end
|
42
|
+
it_behaves_like 'Self-equal Model'
|
43
|
+
it_behaves_like 'Model with invalid defaults'
|
46
44
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
}
|
45
|
+
it 'has class name shortcut' do
|
46
|
+
IB::OrderState.should == IB::Models::OrderState
|
47
|
+
IB::OrderState.new.should == IB::Models::OrderState.new
|
51
48
|
end
|
52
49
|
|
53
|
-
it_behaves_like 'Model'
|
54
|
-
it_behaves_like 'Self-equal Model'
|
55
|
-
|
56
50
|
context '#update_missing' do
|
57
51
|
let(:nil_state) { IB::OrderState.new(:filled => nil, :remaining => nil,
|
58
52
|
:price => nil, :average_price => nil) }
|
59
53
|
context 'updating with Hash' do
|
60
|
-
|
61
54
|
subject { nil_state.update_missing(props) }
|
62
|
-
|
63
55
|
it_behaves_like 'Model instantiated with properties'
|
64
|
-
|
65
56
|
end
|
66
57
|
|
67
58
|
context 'updating with Model' do
|
68
|
-
|
69
59
|
subject { nil_state.update_missing(IB::OrderState.new(props)) }
|
70
|
-
|
71
60
|
it_behaves_like 'Model instantiated with properties'
|
72
|
-
|
73
61
|
end
|
74
|
-
|
75
62
|
end
|
76
63
|
|
77
64
|
it 'has extra test methods' do
|
@@ -1,36 +1,29 @@
|
|
1
1
|
require 'model_helper'
|
2
2
|
|
3
|
-
describe IB::Models::Underlying
|
3
|
+
describe IB::Models::Underlying,
|
4
|
+
:props =>
|
5
|
+
{:con_id => 234567,
|
6
|
+
:delta => 0.55,
|
7
|
+
:price => 20.5,
|
8
|
+
},
|
4
9
|
|
5
|
-
|
6
|
-
{:con_id => 234567,
|
7
|
-
:delta => 0.55,
|
8
|
-
:price => 20.5,
|
9
|
-
}
|
10
|
-
end
|
10
|
+
:human => /<Underlying: con_id: 234567 .*delta: 0.55 price: 20.5.*>/,
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
:errors =>
|
13
|
+
{:delta => ['is not a number'],
|
14
|
+
:price => ['is not a number'],
|
15
|
+
},
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
:price => ['is not a number'],
|
19
|
-
}
|
20
|
-
end
|
17
|
+
:assigns =>
|
18
|
+
{[:con_id, :delta, :price] => numeric_assigns,
|
21
19
|
|
22
|
-
|
23
|
-
{[:con_id, :delta, :price] => numeric_assigns,
|
24
|
-
}
|
25
|
-
end
|
20
|
+
} do # AKA IB::Underlying
|
26
21
|
|
27
|
-
it_behaves_like 'Model'
|
28
22
|
it_behaves_like 'Self-equal Model'
|
23
|
+
it_behaves_like 'Model with invalid defaults'
|
29
24
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
it_behaves_like 'Self-equal Model'
|
25
|
+
it 'has class name shortcut' do
|
26
|
+
IB::Underlying.should == IB::Models::Underlying
|
27
|
+
IB::Underlying.new.should == IB::Models::Underlying.new
|
34
28
|
end
|
35
|
-
|
36
29
|
end # describe IB::Contract
|
@@ -29,6 +29,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
29
29
|
msg = @ib.received[:ContractData].first
|
30
30
|
msg.request_id.should == 111
|
31
31
|
msg.contract.should == @contract
|
32
|
+
msg.contract.should be_valid
|
32
33
|
end
|
33
34
|
|
34
35
|
it 'receives Contract Data with extended fields' do
|
@@ -79,6 +80,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
79
80
|
it 'receives Contract Data for requested contract' do
|
80
81
|
subject.request_id.should == 123
|
81
82
|
subject.contract.should == @contract
|
83
|
+
subject.contract.should be_valid
|
82
84
|
end
|
83
85
|
|
84
86
|
it 'receives Contract Data with extended fields' do
|
@@ -127,6 +129,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
127
129
|
it 'receives Contract Data for requested contract' do
|
128
130
|
subject.request_id.should == 135
|
129
131
|
subject.contract.should == @contract
|
132
|
+
subject.contract.should be_valid
|
130
133
|
end
|
131
134
|
|
132
135
|
it 'receives Contract Data with extended fields' do
|
@@ -172,6 +175,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
172
175
|
it 'receives Contract Data for requested contract' do
|
173
176
|
subject.request_id.should == 147
|
174
177
|
subject.contract.should == @contract
|
178
|
+
subject.contract.should be_valid
|
175
179
|
end
|
176
180
|
|
177
181
|
it 'receives Contract Data with extended fields' do
|