ib-ruby 0.7.11 → 0.7.12
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.
- 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
|