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
@@ -13,8 +13,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
13
13
|
context "Request Stock data" do
|
14
14
|
|
15
15
|
before(:all) do
|
16
|
-
@contract = IB::Contract.new :symbol => 'AAPL',
|
17
|
-
:sec_type => IB::SECURITY_TYPES[:stock]
|
16
|
+
@contract = IB::Contract.new :symbol => 'AAPL', :sec_type => :stock
|
18
17
|
@ib.send_message :RequestContractData, :id => 111, :contract => @contract
|
19
18
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
20
19
|
end
|
@@ -52,8 +51,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
52
51
|
contract.order_types.should be_a String
|
53
52
|
contract.price_magnifier.should == 1
|
54
53
|
contract.min_tick.should be <= 0.01
|
55
|
-
|
56
|
-
contract.expiry.should be_nil
|
54
|
+
contract.expiry.should == ''
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end # Stock
|
@@ -108,7 +106,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
108
106
|
@contract = IB::Contract.new :symbol => 'EUR', # EURUSD pair
|
109
107
|
:currency => "USD",
|
110
108
|
:exchange => "IDEALPRO",
|
111
|
-
:sec_type =>
|
109
|
+
:sec_type => :forex
|
112
110
|
@ib.send_message :RequestContractData, :id => 135, :contract => @contract
|
113
111
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
114
112
|
end
|
@@ -136,7 +134,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
136
134
|
contract.industry.should == ''
|
137
135
|
contract.category.should == ''
|
138
136
|
contract.subcategory.should == ''
|
139
|
-
contract.expiry.should
|
137
|
+
contract.expiry.should == ''
|
140
138
|
contract.exchange.should == 'IDEALPRO'
|
141
139
|
contract.con_id.should be_an Integer
|
142
140
|
contract.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'integration_helper'
|
2
|
+
|
3
|
+
describe 'Request Fundamental Data',
|
4
|
+
:connected => true, :integration => true, :reuters => true do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
verify_account
|
8
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
9
|
+
|
10
|
+
@contract = IB::Contract.new :symbol => 'IBM',
|
11
|
+
:exchange => 'NYSE',
|
12
|
+
:currency => 'USD',
|
13
|
+
:sec_type => 'STK'
|
14
|
+
|
15
|
+
@ib.send_message :RequestFundamentalData,
|
16
|
+
:id => 456,
|
17
|
+
:contract => @contract,
|
18
|
+
:report_type => 'snapshot' # 'estimates', 'finstat'
|
19
|
+
|
20
|
+
@ib.wait_for :FundamentalData, 6 # sec
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:all) do
|
24
|
+
close_connection
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { @ib.received[:FundamentalData].first }
|
28
|
+
|
29
|
+
it { @ib.received[:FundamentalData].should have_at_least(1).data_message }
|
30
|
+
|
31
|
+
it { should be_an IB::Messages::Incoming::FundamentalData }
|
32
|
+
its(:request_id) { should == 456 }
|
33
|
+
its(:data) { should be_a String }
|
34
|
+
|
35
|
+
it 'responds with XML with relevand data' do
|
36
|
+
require 'xmlsimple'
|
37
|
+
data_xml = XmlSimple.xml_in(subject.data, 'ForceArray' => false) #, 'ContentKey' => 'content')
|
38
|
+
name = data_xml["CoIDs"]["CoID"].find {|tag| tag['Type'] == 'CompanyName'}['content']
|
39
|
+
name.should =~ /International Business Machines/
|
40
|
+
end
|
41
|
+
end
|
@@ -7,7 +7,7 @@ describe 'Request Historic Data', :connected => true, :integration => true do
|
|
7
7
|
:end_date_time => Time.now.to_ib,
|
8
8
|
:duration => '1 D',
|
9
9
|
:bar_size => '15 mins',
|
10
|
-
:
|
10
|
+
:data_type => :trades,
|
11
11
|
:format_date => 1}
|
12
12
|
before(:all) do
|
13
13
|
verify_account
|
@@ -26,10 +26,10 @@ describe 'Request Historic Data', :connected => true, :integration => true do
|
|
26
26
|
end.to raise_error /bar_size must be one of/
|
27
27
|
end
|
28
28
|
|
29
|
-
it 'raises if incorrect
|
29
|
+
it 'raises if incorrect data_type' do
|
30
30
|
expect do
|
31
|
-
@ib.send_message :RequestHistoricalData, CORRECT_OPTS.merge(:
|
32
|
-
end.to raise_error /:
|
31
|
+
@ib.send_message :RequestHistoricalData, CORRECT_OPTS.merge(:data_type => :nonsense)
|
32
|
+
end.to raise_error /:data_type must be one of/
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'integration_helper'
|
2
|
-
#!/usr/bin/env ruby
|
3
2
|
|
4
3
|
require 'ib-ruby'
|
5
4
|
|
6
|
-
#OPTS[:silent] = false
|
7
5
|
describe 'Request Market Data', :connected => true, :integration => true do
|
8
6
|
|
9
7
|
require 'ib-ruby'
|
@@ -15,7 +13,7 @@ describe 'Request Market Data', :connected => true, :integration => true do
|
|
15
13
|
@contract = IB::Contract.new(:symbol => 'AAPL',
|
16
14
|
:exchange => "Smart",
|
17
15
|
:currency => "USD",
|
18
|
-
:sec_type =>
|
16
|
+
:sec_type => :stock,
|
19
17
|
:description => "Apple"
|
20
18
|
)
|
21
19
|
@ib.send_message :RequestMarketData, :id => 456, :contract => @contract
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
require 'combo_helper'
|
3
3
|
|
4
|
-
#OPTS[:silent] = false
|
5
|
-
|
6
4
|
def define_contracts
|
7
5
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
8
6
|
@contracts = {
|
@@ -21,12 +19,12 @@ describe 'Attached Orders', :connected => true, :integration => true do
|
|
21
19
|
|
22
20
|
# Testing different combinations of Parent + Attached Orders:
|
23
21
|
[
|
24
|
-
|
25
|
-
[:stock, 100, 'DAY', 'STP', 9.13, 0.0, 8.0], # Parent + stoploss
|
26
|
-
[:stock, 100, 'GTC', 'LMT', 9.13, 20.0], # GTC Parent + target
|
22
|
+
[:stock, 100, 'DAY', 'LMT', 9.13, 20.0], # Parent + takeprofit target
|
23
|
+
#[:stock, 100, 'DAY', 'STP', 9.13, 0.0, 8.0], # Parent + stoploss
|
24
|
+
#[:stock, 100, 'GTC', 'LMT', 9.13, 20.0], # GTC Parent + target
|
27
25
|
[:butterfly, 10, 'DAY', 'LMT', 0.05, 1.0], # Combo Parent + target
|
28
|
-
|
29
|
-
|
26
|
+
#[:butterfly, 10, 'GTC', 'LMT', 0.05, 1.0], # GTC Combo Parent + target
|
27
|
+
#[:butterfly, 100, 'GTC', 'STPLMT', 0.05, 0.05, 1.0], # GTC Combo Parent + stoplimit target
|
30
28
|
|
31
29
|
].each do |(contract, qty, tif, attach_type, limit_price, attach_price, aux_price)|
|
32
30
|
context "#{tif} BUY (#{contract}) limit order with attached #{attach_type} SELL" do
|
@@ -57,10 +55,10 @@ describe 'Attached Orders', :connected => true, :integration => true do
|
|
57
55
|
|
58
56
|
context "Attaching #{attach_type} order" do
|
59
57
|
before(:all) do
|
60
|
-
@attached_order = IB::Order.new :
|
61
|
-
:limit_price => attach_price,
|
58
|
+
@attached_order = IB::Order.new :limit_price => attach_price,
|
62
59
|
:aux_price => aux_price || 0,
|
63
|
-
:
|
60
|
+
:total_quantity => qty,
|
61
|
+
:side => :sell,
|
64
62
|
:tif => tif,
|
65
63
|
:order_type => attach_type,
|
66
64
|
:parent_id => @order_id_placed
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
require 'combo_helper'
|
3
3
|
|
4
|
-
#OPTS[:silent] = false
|
5
|
-
|
6
4
|
describe "Combo Order", :connected => true, :integration => true, :slow => true do
|
7
5
|
|
8
6
|
let(:contract_type) { :butterfly }
|
@@ -17,6 +15,7 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
17
15
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
18
16
|
|
19
17
|
place_order @contract,
|
18
|
+
:order_ref => 'What_if',
|
20
19
|
:limit_price => 0.01,
|
21
20
|
:total_quantity => 10,
|
22
21
|
:what_if => true
|
@@ -70,6 +69,7 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
70
69
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
71
70
|
|
72
71
|
place_order @contract,
|
72
|
+
:order_ref => 'Original',
|
73
73
|
:limit_price => 0.01,
|
74
74
|
:total_quantity => 10
|
75
75
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
|
3
|
-
#OPTS[:silent] = false
|
4
|
-
|
5
3
|
describe 'Orders', :connected => true, :integration => true do
|
6
4
|
let(:contract_type) { :stock }
|
7
5
|
|
@@ -89,7 +87,7 @@ describe 'Orders', :connected => true, :integration => true do
|
|
89
87
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
90
88
|
@ib.wait_for :NextValidId
|
91
89
|
place_order IB::Symbols::Stocks[:wfc], :limit_price => 9.13 # Acceptable price
|
92
|
-
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2],
|
90
|
+
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2], 6
|
93
91
|
end
|
94
92
|
|
95
93
|
after(:all) { close_connection }
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
|
3
|
-
#OPTS[:silent] = false
|
4
3
|
shared_examples_for 'Received single id' do
|
5
4
|
subject { @ib.received[:NextValidId].first }
|
6
5
|
|
@@ -52,7 +51,7 @@ describe 'Ids valid for Order placement', :connected => true, :integration => tr
|
|
52
51
|
|
53
52
|
it_behaves_like 'Received single id'
|
54
53
|
|
55
|
-
it 'receives also :OpenOrderEnd message', :pending => 'not in GW 924.
|
54
|
+
it 'receives also :OpenOrderEnd message', :pending => 'not in GW 924.3a' do
|
56
55
|
@ib.received[:OpenOrderEnd].should have_exactly(1).message
|
57
56
|
@ib.received[:OpenOrderEnd].first.should be_an IB::Messages::Incoming::OpenOrderEnd
|
58
57
|
end
|
data/spec/message_helper.rb
CHANGED
@@ -35,7 +35,7 @@ end
|
|
35
35
|
|
36
36
|
# Clear logs and message collector. Output may be silenced.
|
37
37
|
def clean_connection
|
38
|
-
|
38
|
+
if OPTS[:verbose]
|
39
39
|
#puts @received.map { |type, msg| [" #{type}:", msg.map(&:to_human)] } if @received
|
40
40
|
puts @ib.received.map { |type, msg| [" #{type}:", msg.map(&:to_human)] }
|
41
41
|
puts " Logs:", log_entries if @stdout
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def codes_and_values_for property
|
4
|
+
Hash[IB::VALUES[property].map { |code, value| [[code, value], value] }]
|
5
|
+
end
|
6
|
+
|
7
|
+
shared_examples_for 'Model' do
|
8
|
+
context 'instantiation without properties' do
|
9
|
+
subject { described_class.new }
|
10
|
+
|
11
|
+
it_behaves_like 'Model instantiated empty'
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'instantiation with properties' do
|
15
|
+
subject { described_class.new props }
|
16
|
+
|
17
|
+
it_behaves_like 'Model instantiated with properties'
|
18
|
+
|
19
|
+
|
20
|
+
it 'has correct human-readeable format' do
|
21
|
+
subject.to_human.should == human
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
shared_examples_for 'Self-equal Model' do
|
27
|
+
subject { described_class.new(props) }
|
28
|
+
|
29
|
+
it 'is self-equal ' do
|
30
|
+
should == subject
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is equal to Model with the same properties' do
|
34
|
+
should == described_class.new(props)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_examples_for 'Model instantiated empty' do
|
39
|
+
it { should_not be_nil }
|
40
|
+
|
41
|
+
it 'sets all properties to defaults' do
|
42
|
+
defined?(defaults) && defaults.each do |name, value|
|
43
|
+
case value
|
44
|
+
when Module, Class
|
45
|
+
subject.send(name).should be_a value
|
46
|
+
else
|
47
|
+
subject.send(name).should == value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it_behaves_like 'Model properties'
|
53
|
+
it_behaves_like 'Invalid Model'
|
54
|
+
end
|
55
|
+
|
56
|
+
shared_examples_for 'Model instantiated with properties' do
|
57
|
+
it 'auto-assigns all properties given to initializer' do
|
58
|
+
props.each do |name, value|
|
59
|
+
subject.send(name).should == value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it_behaves_like 'Model properties'
|
64
|
+
it_behaves_like 'Valid Model'
|
65
|
+
end
|
66
|
+
|
67
|
+
shared_examples_for 'Model properties' do
|
68
|
+
context 'essential properties are still set, even if not given explicitely' do
|
69
|
+
its(:created_at) { should be_a Time }
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'allows setting properties' do
|
73
|
+
expect {
|
74
|
+
props.each do |name, value|
|
75
|
+
subject.send("#{name}=", value)
|
76
|
+
subject.send(name).should == value
|
77
|
+
end
|
78
|
+
}.to_not raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'sets values to properties as directed by its setters' do
|
82
|
+
defined?(assigns) && assigns.each do |props, cases|
|
83
|
+
#p props, cases
|
84
|
+
|
85
|
+
# For each given property ...
|
86
|
+
[props].flatten.each do |prop|
|
87
|
+
|
88
|
+
# For all test cases given as an Array [res1, res2] or Hash {val => res} ...
|
89
|
+
(cases.is_a?(Array) ? cases.map { |e| [e, e] } : cases).each do |values, result|
|
90
|
+
|
91
|
+
# For all values in this test case ...
|
92
|
+
[values].flatten.each do |value|
|
93
|
+
|
94
|
+
# Assigning this value to property results in ...
|
95
|
+
case result
|
96
|
+
when Exception # ... Exception
|
97
|
+
expect { subject.send "#{prop}=", value }.
|
98
|
+
to raise_error result
|
99
|
+
|
100
|
+
when Regexp # ... Non-exceptional error, making model invalid
|
101
|
+
expect { subject.send "#{prop}=", value }.to_not raise_error
|
102
|
+
subject.should be_invalid
|
103
|
+
|
104
|
+
#pp subject.errors.messages
|
105
|
+
#p value, result
|
106
|
+
|
107
|
+
subject.errors.messages[prop].should_not be_nil
|
108
|
+
msg = subject.errors.messages[prop].find { |msg| msg =~ result }
|
109
|
+
msg.should =~ result
|
110
|
+
|
111
|
+
else # ... correct uniform assignment to result
|
112
|
+
|
113
|
+
was_valid = subject.valid?
|
114
|
+
expect { subject.send "#{prop}=", value }.to_not raise_error
|
115
|
+
subject.send("#{prop}").should == result
|
116
|
+
|
117
|
+
was_valid && (subject.should be_valid) # assignment keeps validity
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
shared_examples_for 'Valid Model' do
|
128
|
+
it 'validates' do
|
129
|
+
#subject.valid?
|
130
|
+
#pp subject.errors.messages
|
131
|
+
subject.should be_valid
|
132
|
+
subject.errors.should be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'with DB backend', :db => true do
|
136
|
+
after(:all) do
|
137
|
+
#DatabaseCleaner.clean
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'is saved' do
|
141
|
+
subject.save.should be_true
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'is loaded just right' do
|
145
|
+
models = described_class.find(:all)
|
146
|
+
model = models.first
|
147
|
+
#pp model
|
148
|
+
models.should have_exactly(1).model
|
149
|
+
model.should == subject
|
150
|
+
model.should be_valid
|
151
|
+
props.each do |name, value|
|
152
|
+
model.send(name).should == value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end # DB
|
156
|
+
end
|
157
|
+
|
158
|
+
shared_examples_for 'Invalid Model' do
|
159
|
+
it 'does not validate' do
|
160
|
+
subject.should_not be_valid
|
161
|
+
subject.should be_invalid
|
162
|
+
subject.errors.should_not be_empty
|
163
|
+
subject.errors.messages.should == errors if defined? errors
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'with DB backend', :db => true do
|
167
|
+
after(:all) do
|
168
|
+
#DatabaseCleaner.clean
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'is not saved' do
|
172
|
+
subject.save.should be_false
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'is not loaded' do
|
176
|
+
models = described_class.find(:all)
|
177
|
+
models.should have_exactly(0).model
|
178
|
+
end
|
179
|
+
end # DB
|
180
|
+
end
|
181
|
+
|
182
|
+
shared_examples_for 'Contract' do
|
183
|
+
it 'summary points to itself (ContractDetails artifact' do
|
184
|
+
subject.summary.should == subject
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'becomes invalid if assigned wrong :sec_type property' do
|
188
|
+
subject.sec_type = 'FOO'
|
189
|
+
subject.should be_invalid
|
190
|
+
subject.errors.messages[:sec_type].should include "should be valid security type"
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'becomes invalid if assigned wrong :right property' do
|
194
|
+
subject.right = 'BAR'
|
195
|
+
subject.should be_invalid
|
196
|
+
subject.errors.messages[:right].should include "should be put, call or none"
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'becomes invalid if assigned wrong :expiry property' do
|
200
|
+
subject.expiry = 'BAR'
|
201
|
+
subject.should be_invalid
|
202
|
+
subject.errors.messages[:expiry].should include "should be YYYYMM or YYYYMMDD"
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'becomes invalid if primary_exchange is set to SMART' do
|
206
|
+
subject.primary_exchange = 'SMART'
|
207
|
+
subject.should be_invalid
|
208
|
+
subject.errors.messages[:primary_exchange].should include "should not be SMART"
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|